You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
12 KiB
360 lines
12 KiB
/***************************************************************************
|
|
gdbcontroller.h - description
|
|
-------------------
|
|
begin : Sun Aug 8 1999
|
|
copyright : (C) 1999 by John Birch
|
|
email : jbb@kdevelop.org
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#ifndef _GDBCONTROLLER_H_
|
|
#define _GDBCONTROLLER_H_
|
|
|
|
#include "dbgcontroller.h"
|
|
#include "mi/gdbmi.h"
|
|
#include "mi/miparser.h"
|
|
|
|
#include <tqcstring.h>
|
|
#include <tqdom.h>
|
|
#include <tqobject.h>
|
|
#include <tqptrlist.h>
|
|
#include <tqstring.h>
|
|
#include <tqmap.h>
|
|
#include <tqdatetime.h>
|
|
|
|
#include <memory>
|
|
#include <set>
|
|
|
|
class TDEProcess;
|
|
|
|
namespace GDBDebugger
|
|
{
|
|
|
|
class Breakpoint;
|
|
class DbgCommand;
|
|
class GDBCommand;
|
|
class VarItem;
|
|
class STTY;
|
|
|
|
/**
|
|
* A front end implementation to the gdb command line debugger
|
|
* @author jbb
|
|
*/
|
|
|
|
class GDBController : public DbgController
|
|
{
|
|
TQ_OBJECT
|
|
|
|
|
|
public:
|
|
GDBController(TQDomDocument &projectDom);
|
|
~GDBController();
|
|
|
|
enum event_t { program_state_changed = 1, program_exited, debugger_exited,
|
|
thread_or_frame_changed, debugger_busy, debugger_ready,
|
|
shared_library_loaded,
|
|
// Raised when debugger believe that program start running.
|
|
// Can be used to hide current line indicator.
|
|
// Don't count on this being raise in all cases where
|
|
// program is running.
|
|
program_running,
|
|
connected_to_program
|
|
};
|
|
|
|
|
|
/** Adds a command to the end of queue of commands to be executed
|
|
by gdb. The command will be actually sent to gdb only when
|
|
replies from all previous commands are received and full processed.
|
|
|
|
The literal command sent to gdb is obtained by calling
|
|
cmd->cmdToSend. The call is made immediately before sending the
|
|
command, so it's possible to use results of prior commands when
|
|
computing the exact command to send.
|
|
*/
|
|
void addCommand(GDBCommand* cmd);
|
|
|
|
/** Same as above, but internally constructs new GDBCommand
|
|
instance from the string. */
|
|
void addCommand(const TQString& cmd);
|
|
|
|
/** Adds command to the front of the commands queue. It will be executed
|
|
next.
|
|
|
|
This is usefull to implement 'atomic' command sequences. For example,
|
|
if one wants to switch to each thread in turn, asking gdb where that
|
|
thread stand, this should never be interrupted by other command, since
|
|
other commands might not expect that thread magically changes.
|
|
|
|
In this specific case, first -thread-list-ids commands is issued. The
|
|
handler for reply will add a number of command to front, and it will
|
|
guarantee that no other command will get in between.
|
|
|
|
Note that if you call:
|
|
|
|
addCommandToFront(cmd1);
|
|
addCommandToFront(cmd2);
|
|
|
|
The execution order will be 'cmd2', then 'cmd1'.
|
|
|
|
FIXME: is not used for now, maybe remove.
|
|
*/
|
|
void addCommandToFront(GDBCommand* cmd);
|
|
|
|
/* If current command queue has any command
|
|
for which isRun is true, inserts 'cmd'
|
|
before the first such command. Otherwise,
|
|
works the same as addCommand. */
|
|
void addCommandBeforeRun(GDBCommand* cmd);
|
|
|
|
/** Selects the specified thread/frame. Immediately emits
|
|
thread_or_frame_changed event.
|
|
*/
|
|
void selectFrame(int frameNo, int threadNo);
|
|
|
|
|
|
/** Returns the numerical identfier of the current thread,
|
|
or -1 if the program is not threaded (i.e. there's just
|
|
one thread.
|
|
*/
|
|
int currentThread() const;
|
|
|
|
int currentFrame() const;
|
|
|
|
bool start(const TQString& shell,
|
|
const DomUtil::PairList& run_envvars,
|
|
const TQString& run_directory,
|
|
const TQString &application,
|
|
const TQString& run_arguments);
|
|
|
|
int qtVersion() const;
|
|
|
|
/**
|
|
* Call this when something very interesting happens that the user
|
|
* might be unaware of. It will make KDevelop's taskbar entry flash
|
|
* if the application doesn't already have focus.
|
|
* Typical use case: The debugger has stopped on a breakpoint.
|
|
*/
|
|
void demandAttention() const;
|
|
|
|
void pauseApp();
|
|
|
|
bool miPendingBreakpoints() const;
|
|
|
|
protected:
|
|
enum queue_where { queue_at_end, queue_at_front, queue_before_run };
|
|
|
|
void queueCmd(GDBCommand *cmd, enum queue_where queue_where = queue_at_end);
|
|
|
|
private:
|
|
void parseLocals (char type, char *buf);
|
|
/** Parses the CLI output line, and catches interesting messages
|
|
like "Program exited". This is intended to allow using console
|
|
commands in the gdb window despite the fact that GDB does not
|
|
produce right MI notification for CLI commands. I.e. if you
|
|
run "continue" there will be no MI message if the application has
|
|
exited.
|
|
*/
|
|
void parseCliLine (const TQString&);
|
|
|
|
/** Handles a result response from a MI command -- that is
|
|
all MI responses except for Stream and Prompt responses.
|
|
Uses currentCmd to decide what to do with response and
|
|
calls appropriate method.
|
|
*/
|
|
void processMICommandResponse(const GDBMI::ResultRecord& r);
|
|
|
|
void handleMiFileListExecSourceFile(const GDBMI::ResultRecord& r);
|
|
|
|
/** Handles reply from -stack-info-frame command issues
|
|
after switching the stack frame.
|
|
*/
|
|
void handleMiFrameSwitch(const GDBMI::ResultRecord& r);
|
|
|
|
void executeCmd ();
|
|
void destroyCmds();
|
|
void removeInfoRequests();
|
|
void actOnProgramPauseMI(const GDBMI::ResultRecord& mi_record);
|
|
/** Called when there are no pending commands and 'state_reload_needed'
|
|
is true.
|
|
Issues commands to completely reload all program state shown
|
|
to the user.
|
|
*/
|
|
void reloadProgramState();
|
|
|
|
void programNoApp(const TQString &msg, bool msgBox);
|
|
|
|
void setStateOn(int stateOn);
|
|
void setStateOff(int stateOff);
|
|
void setState(int newState);
|
|
|
|
void debugStateChange(int oldState, int newState);
|
|
void commandDone();
|
|
void destroyCurrentCommand();
|
|
|
|
/** Removes all 'stateReloading' commands from the queue.
|
|
*/
|
|
void removeStateReloadingCommands();
|
|
|
|
/** Raises the specified event. Should be used instead of
|
|
emitting 'event' directly, since this method can perform
|
|
additional book-keeping for events.
|
|
*/
|
|
void raiseEvent(event_t e);
|
|
|
|
void maybeAnnounceWatchpointHit();
|
|
|
|
void handleListFeatures(const GDBMI::ResultRecord& result);
|
|
void startDone();
|
|
|
|
/** Default handler for errors.
|
|
Tries to guess is the error message is telling that target is
|
|
gone, if so, informs the user.
|
|
Otherwise, shows a dialog box and reloads view state. */
|
|
void defaultErrorHandler(const GDBMI::ResultRecord& result);
|
|
|
|
public:
|
|
bool stateIsOn(int state);
|
|
|
|
public slots:
|
|
void configure();
|
|
|
|
|
|
//void slotStart(const TQString& shell, const TQString &application);
|
|
void slotCoreFile(const TQString &coreFile);
|
|
void slotAttachTo(int pid);
|
|
|
|
void slotStopDebugger();
|
|
|
|
void slotRun();
|
|
void slotKill();
|
|
void slotRunUntil(const TQString &filename, int lineNum);
|
|
void slotJumpTo(const TQString &filename, int lineNum);
|
|
void slotStepInto();
|
|
void slotStepOver();
|
|
void slotStepIntoIns();
|
|
void slotStepOverIns();
|
|
void slotStepOutOff();
|
|
|
|
void slotBreakInto();
|
|
|
|
void slotUserGDBCmd(const TQString&);
|
|
|
|
// Pops up a dialog box with some hopefully
|
|
// detailed information about which state debugger
|
|
// is in, which commands were sent and so on.
|
|
void explainDebuggerStatus();
|
|
|
|
|
|
protected slots:
|
|
void slotDbgStdout(TDEProcess *proc, char *buf, int buflen);
|
|
void slotDbgStderr(TDEProcess *proc, char *buf, int buflen);
|
|
void slotDbgWroteStdin(TDEProcess *proc);
|
|
void slotDbgProcessExited(TDEProcess *proc);
|
|
|
|
signals:
|
|
|
|
/** This signal is emitted whenever the given event in a program
|
|
happens. See DESIGN.txt for expected handled of each event.
|
|
|
|
NOTE: this signal should never be emitted directly. Instead,
|
|
use raiseEvent.
|
|
*/
|
|
void event(GDBController::event_t e);
|
|
|
|
void debuggerAbnormalExit();
|
|
|
|
|
|
/** Emitted immediately after breakpoint is hit, before any commands
|
|
are sent and before current line indicator is shown. */
|
|
void breakpointHit(int id);
|
|
/** Emitted for watchpoint hit, after line indicator is shown. */
|
|
void watchpointHit(int id,
|
|
const TQString& oldValue, const TQString& newValue);
|
|
|
|
private:
|
|
int currentFrame_;
|
|
int viewedThread_;
|
|
|
|
// The output from gdb that was not parsed yet
|
|
TQCString gdbOutput_;
|
|
// The output from gdb that arrived where we was
|
|
// parsing the previous output. To avoid messing
|
|
// things up, it's not directly added to
|
|
// gdbOutput_ but stored for future use.
|
|
// VP: It's not clear why the previous code was doing
|
|
// this, and holdingZone_ won't be processed until
|
|
// next output arrives, so probably should be just removed.
|
|
TQCString holdingZone_;
|
|
|
|
TQPtrList<GDBCommand> cmdList_;
|
|
GDBCommand* currentCmd_;
|
|
|
|
STTY* tty_;
|
|
TQString badCore_;
|
|
TQString application_;
|
|
|
|
// Gdb command that should be issued when we stop on breakpoint
|
|
// with the given gdb breakpoint id.
|
|
TQMap<int, const Breakpoint*> tracedBreakpoints_;
|
|
|
|
// Some state variables
|
|
int state_;
|
|
bool programHasExited_;
|
|
|
|
// Configuration values
|
|
TQDomDocument &dom;
|
|
bool config_breakOnLoadingLibrary_;
|
|
bool config_forceBPSet_;
|
|
bool config_displayStaticMembers_;
|
|
bool config_asmDemangle_;
|
|
bool config_dbgTerminal_;
|
|
TQString config_gdbPath_;
|
|
TQString config_dbgShell_;
|
|
TQCString config_configGdbScript_;
|
|
TQCString config_runShellScript_;
|
|
TQCString config_runGdbScript_;
|
|
int config_outputRadix_;
|
|
|
|
MIParser mi_parser_;
|
|
// As of gdb 6.3, the *stopped packet does not contain
|
|
// full file name. So we need to send another command to
|
|
// fetch that, to highlight current line.
|
|
// After highting current line we need to do something more,
|
|
// like announcing write watchpoints, and so need to have
|
|
// access to the stop packet. So store it here.
|
|
std::auto_ptr<GDBMI::ResultRecord> last_stop_result;
|
|
|
|
// Gdb 6.4 (and 6.3) does not support "character" format with MI,
|
|
// so the only way it can work is via the "print" command. As gdb
|
|
// outputs things, we'll grep for lines that look like output from
|
|
// print, and store such lines in this variable, so later use.
|
|
TQCString print_command_result;
|
|
|
|
bool state_reload_needed;
|
|
|
|
TQTime commandExecutionTime;
|
|
|
|
bool stateReloadInProgress_;
|
|
|
|
/** Commands issues as result of the 'program_state_changed'
|
|
event. */
|
|
std::set<GDBCommand*> stateReloadingCommands_;
|
|
|
|
bool saw_gdb_prompt_;
|
|
|
|
/** Does the used GDB supports pending breakpoints in MI? */
|
|
bool mi_pending_breakpoints_;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|