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.
623 lines
18 KiB
623 lines
18 KiB
/*
|
|
* Copyright Johannes Sixt
|
|
* This file is licensed under the GNU General Public License Version 2.
|
|
* See the file COPYING in the toplevel directory of the source directory.
|
|
*/
|
|
|
|
#ifndef DBGDRIVER_H
|
|
#define DBGDRIVER_H
|
|
|
|
#include <tqfile.h>
|
|
#include <tqregexp.h>
|
|
#include <tqcstring.h>
|
|
#include <kprocess.h>
|
|
#include <queue>
|
|
#include <list>
|
|
|
|
|
|
class VarTree;
|
|
class ExprValue;
|
|
class ExprWnd;
|
|
class KDebugger;
|
|
class TQStringList;
|
|
|
|
|
|
/**
|
|
* A type representing an address.
|
|
*/
|
|
struct DbgAddr
|
|
{
|
|
TQString a;
|
|
TQString fnoffs;
|
|
DbgAddr() { }
|
|
DbgAddr(const TQString& aa);
|
|
DbgAddr(const DbgAddr& src) : a(src.a), fnoffs(src.fnoffs) { }
|
|
void operator=(const TQString& aa);
|
|
void operator=(const DbgAddr& src) { a = src.a; fnoffs = src.fnoffs; }
|
|
TQString asString() const;
|
|
bool isEmpty() const { return a.isEmpty(); }
|
|
protected:
|
|
void cleanAddr();
|
|
};
|
|
bool operator==(const DbgAddr& a1, const DbgAddr& a2);
|
|
bool operator>(const DbgAddr& a1, const DbgAddr& a2);
|
|
|
|
|
|
enum DbgCommand {
|
|
DCinitialize,
|
|
DCtty,
|
|
DCexecutable,
|
|
DCtargetremote,
|
|
DCcorefile,
|
|
DCattach,
|
|
DCinfolinemain,
|
|
DCinfolocals,
|
|
DCinforegisters,
|
|
DCexamine,
|
|
DCinfoline,
|
|
DCdisassemble,
|
|
DCsetargs,
|
|
DCsetenv,
|
|
DCunsetenv,
|
|
DCsetoption, /* debugger options */
|
|
DCcd,
|
|
DCbt,
|
|
DCrun,
|
|
DCcont,
|
|
DCstep,
|
|
DCstepi,
|
|
DCnext,
|
|
DCnexti,
|
|
DCfinish,
|
|
DCuntil, /* line number is zero-based! */
|
|
DCkill,
|
|
DCbreaktext,
|
|
DCbreakline, /* line number is zero-based! */
|
|
DCtbreakline, /* line number is zero-based! */
|
|
DCbreakaddr,
|
|
DCtbreakaddr,
|
|
DCwatchpoint,
|
|
DCdelete,
|
|
DCenable,
|
|
DCdisable,
|
|
DCprint,
|
|
DCprintDeref,
|
|
DCprintStruct,
|
|
DCprintTQStringStruct,
|
|
DCframe,
|
|
DCfindType,
|
|
DCinfosharedlib,
|
|
DCthread,
|
|
DCinfothreads,
|
|
DCinfobreak,
|
|
DCcondition,
|
|
DCsetpc,
|
|
DCignore,
|
|
DCprintWChar,
|
|
DCsetvariable
|
|
};
|
|
|
|
enum RunDevNull {
|
|
RDNstdin = 0x1, /* redirect stdin to /dev/null */
|
|
RDNstdout = 0x2, /* redirect stdout to /dev/null */
|
|
RDNstderr = 0x4 /* redirect stderr to /dev/null */
|
|
};
|
|
|
|
/**
|
|
* How the memory dump is formated. The lowest 4 bits define the size of
|
|
* the entities. The higher bits define how these are formatted. Note that
|
|
* not all combinations make sense.
|
|
*/
|
|
enum MemoryDumpType {
|
|
// sizes
|
|
MDTbyte = 0x1,
|
|
MDThalfword = 0x2,
|
|
MDTword = 0x3,
|
|
MDTgiantword = 0x4,
|
|
MDTsizemask = 0xf,
|
|
// formats
|
|
MDThex = 0x10,
|
|
MDTsigned = 0x20,
|
|
MDTunsigned = 0x30,
|
|
MDToctal = 0x40,
|
|
MDTbinary = 0x50,
|
|
MDTaddress = 0x60,
|
|
MDTchar = 0x70,
|
|
MDTfloat = 0x80,
|
|
MDTstring = 0x90,
|
|
MDTinsn = 0xa0,
|
|
MDTformatmask = 0xf0
|
|
};
|
|
|
|
struct Breakpoint;
|
|
|
|
/**
|
|
* Debugger commands are placed in a queue. Only one command at a time is
|
|
* sent down to the debugger. All other commands in the queue are retained
|
|
* until the sent command has been processed by gdb. The debugger tells us
|
|
* that it's done with the command by sending the prompt. The output of the
|
|
* debugger is parsed at that time. Then, if more commands are in the
|
|
* queue, the next one is sent to the debugger.
|
|
*/
|
|
struct CmdQueueItem
|
|
{
|
|
DbgCommand m_cmd;
|
|
TQString m_cmdString;
|
|
bool m_committed; /* just a debugging aid */
|
|
// remember which expression when printing an expression
|
|
VarTree* m_expr;
|
|
ExprWnd* m_exprWnd;
|
|
// remember file position
|
|
TQString m_fileName;
|
|
int m_lineNo;
|
|
// the breakpoint info
|
|
Breakpoint* m_brkpt;
|
|
int m_existingBrkpt;
|
|
// whether command was emitted due to direct user request (only set when relevant)
|
|
bool m_byUser;
|
|
|
|
CmdQueueItem(DbgCommand cmd, const TQString& str) :
|
|
m_cmd(cmd),
|
|
m_cmdString(str),
|
|
m_committed(false),
|
|
m_expr(0),
|
|
m_exprWnd(0),
|
|
m_lineNo(0),
|
|
m_brkpt(0),
|
|
m_existingBrkpt(0),
|
|
m_byUser(false)
|
|
{ }
|
|
|
|
struct IsEqualCmd
|
|
{
|
|
IsEqualCmd(DbgCommand cmd, const TQString& str) : m_cmd(cmd), m_str(str) { }
|
|
bool operator()(CmdQueueItem*) const;
|
|
DbgCommand m_cmd;
|
|
const TQString& m_str;
|
|
};
|
|
};
|
|
|
|
/**
|
|
* The information about a breakpoint that is parsed from the list of
|
|
* breakpoints.
|
|
*/
|
|
struct Breakpoint
|
|
{
|
|
int id; /* gdb's number */
|
|
enum Type {
|
|
breakpoint, watchpoint
|
|
} type;
|
|
bool temporary;
|
|
bool enabled;
|
|
TQString location;
|
|
TQString text; /* text if set using DCbreaktext */
|
|
DbgAddr address; /* exact address of breakpoint */
|
|
TQString condition; /* condition as printed by gdb */
|
|
int ignoreCount; /* ignore next that may hits */
|
|
int hitCount; /* as reported by gdb */
|
|
// the following items repeat the location, but in a better usable way
|
|
TQString fileName;
|
|
int lineNo; /* zero-based line number */
|
|
Breakpoint();
|
|
bool isOrphaned() const { return id < 0; }
|
|
};
|
|
|
|
/**
|
|
* Information about a stack frame.
|
|
*/
|
|
struct FrameInfo
|
|
{
|
|
TQString fileName;
|
|
int lineNo; /* zero-based line number */
|
|
DbgAddr address; /* exact address of PC */
|
|
};
|
|
|
|
/**
|
|
* The information about a stack frame as parsed from the backtrace.
|
|
*/
|
|
struct StackFrame : FrameInfo
|
|
{
|
|
int frameNo;
|
|
ExprValue* var; /* more information if non-zero */
|
|
StackFrame() : var(0) { }
|
|
~StackFrame();
|
|
};
|
|
|
|
/**
|
|
* The information about a thread as parsed from the threads list.
|
|
*/
|
|
struct ThreadInfo : FrameInfo
|
|
{
|
|
int id; /* gdb's number */
|
|
TQString threadName; /* the SYSTAG */
|
|
TQString function; /* where thread is halted */
|
|
bool hasFocus; /* the thread whose stack we are watching */
|
|
};
|
|
|
|
/**
|
|
* Register information
|
|
*/
|
|
struct RegisterInfo
|
|
{
|
|
TQString regName;
|
|
TQString rawValue;
|
|
TQString cookedValue; /* may be empty */
|
|
TQString type; /* of vector register if not empty */
|
|
};
|
|
|
|
/**
|
|
* Disassembled code
|
|
*/
|
|
struct DisassembledCode
|
|
{
|
|
DbgAddr address;
|
|
TQString code;
|
|
};
|
|
|
|
/**
|
|
* Memory contents
|
|
*/
|
|
struct MemoryDump
|
|
{
|
|
DbgAddr address;
|
|
TQString dump;
|
|
};
|
|
|
|
/**
|
|
* This is an abstract base class for debugger process.
|
|
*
|
|
* This class represents the debugger program. It provides the low-level
|
|
* interface to the commandline debugger. As such it implements the
|
|
* commands and parses the output.
|
|
*/
|
|
class DebuggerDriver : public TDEProcess
|
|
{
|
|
TQ_OBJECT
|
|
public:
|
|
DebuggerDriver();
|
|
virtual ~DebuggerDriver() = 0;
|
|
|
|
virtual TQString driverName() const = 0;
|
|
/**
|
|
* Returns the default command string to invoke the debugger driver.
|
|
*/
|
|
virtual TQString defaultInvocation() const = 0;
|
|
|
|
/**
|
|
* Returns a list of options that can be turned on and off.
|
|
*/
|
|
virtual TQStringList boolOptionList() const = 0;
|
|
|
|
virtual bool startup(TQString cmdStr);
|
|
void setLogFileName(const TQString& fname) { m_logFileName = fname; }
|
|
|
|
protected:
|
|
TQString m_runCmd;
|
|
|
|
enum DebuggerState {
|
|
DSidle, /* gdb waits for input */
|
|
DSinterrupted, /* a command was interrupted */
|
|
DSrunningLow, /* gdb is running a low-priority command */
|
|
DSrunning, /* gdb waits for program */
|
|
DScommandSent, /* command has been sent, we wait for wroteStdin signal */
|
|
DScommandSentLow /* low-prioritycommand has been sent */
|
|
};
|
|
DebuggerState m_state;
|
|
|
|
public:
|
|
bool isIdle() const { return m_state == DSidle; }
|
|
/**
|
|
* Tells whether a high prority command would be executed immediately.
|
|
*/
|
|
bool canExecuteImmediately() const { return m_hipriCmdQueue.empty(); }
|
|
|
|
protected:
|
|
char* m_output; /* normal gdb output */
|
|
size_t m_outputLen; /* amount of data so far accumulated in m_output */
|
|
size_t m_outputAlloc; /* space available in m_output */
|
|
std::queue<TQByteArray> m_delayedOutput; /* output colleced while we have receivedOutput */
|
|
/* but before signal wroteStdin arrived */
|
|
|
|
public:
|
|
/**
|
|
* Enqueues a high-priority command. High-priority commands are
|
|
* executed before any low-priority commands. No user interaction is
|
|
* possible as long as there is a high-priority command in the queue.
|
|
*/
|
|
virtual CmdQueueItem* executeCmd(DbgCommand,
|
|
bool clearLow = false) = 0;
|
|
virtual CmdQueueItem* executeCmd(DbgCommand, TQString strArg,
|
|
bool clearLow = false) = 0;
|
|
virtual CmdQueueItem* executeCmd(DbgCommand, int intArg,
|
|
bool clearLow = false) = 0;
|
|
virtual CmdQueueItem* executeCmd(DbgCommand, TQString strArg, int intArg,
|
|
bool clearLow = false) = 0;
|
|
virtual CmdQueueItem* executeCmd(DbgCommand, TQString strArg1, TQString strArg2,
|
|
bool clearLow = false) = 0;
|
|
virtual CmdQueueItem* executeCmd(DbgCommand, int intArg1, int intArg2,
|
|
bool clearLow = false) = 0;
|
|
|
|
enum QueueMode {
|
|
TQMnormal, /* queues the command last */
|
|
TQMoverride, /* removes an already queued command */
|
|
TQMoverrideMoreEqual /* ditto, also puts the command first in the queue */
|
|
};
|
|
|
|
/**
|
|
* Enqueues a low-priority command. Low-priority commands are executed
|
|
* after any high-priority commands.
|
|
*/
|
|
virtual CmdQueueItem* queueCmd(DbgCommand,
|
|
QueueMode mode) = 0;
|
|
virtual CmdQueueItem* queueCmd(DbgCommand, TQString strArg,
|
|
QueueMode mode) = 0;
|
|
virtual CmdQueueItem* queueCmd(DbgCommand, int intArg,
|
|
QueueMode mode) = 0;
|
|
virtual CmdQueueItem* queueCmd(DbgCommand, TQString strArg, int intArg,
|
|
QueueMode mode) = 0;
|
|
virtual CmdQueueItem* queueCmd(DbgCommand, TQString strArg1, TQString strArg2,
|
|
QueueMode mode) = 0;
|
|
|
|
/**
|
|
* Flushes the command queues.
|
|
* @param hipriOnly if true, only the high priority queue is flushed.
|
|
*/
|
|
virtual void flushCommands(bool hipriOnly = false);
|
|
|
|
/**
|
|
* Terminates the debugger process.
|
|
*/
|
|
virtual void terminate() = 0;
|
|
|
|
/**
|
|
* Terminates the debugger process, but also detaches any program that
|
|
* it has been attached to.
|
|
*/
|
|
virtual void detachAndTerminate() = 0;
|
|
|
|
/**
|
|
* Interrupts the debuggee.
|
|
*/
|
|
virtual void interruptInferior() = 0;
|
|
|
|
/**
|
|
* Specifies the command that prints the TQString data.
|
|
*/
|
|
virtual void setPrintTQStringDataCmd(const char* cmd) = 0;
|
|
|
|
/**
|
|
* Parses the output as an array of TQChars.
|
|
*/
|
|
virtual ExprValue* parseTQCharArray(const char* output, bool wantErrorValue, bool qt3like) = 0;
|
|
|
|
/**
|
|
* Parses a back-trace (the output of the DCbt command).
|
|
*/
|
|
virtual void parseBackTrace(const char* output, std::list<StackFrame>& stack) = 0;
|
|
|
|
/**
|
|
* Parses the output of the DCframe command;
|
|
* @param frameNo Returns the frame number.
|
|
* @param file Returns the source file name.
|
|
* @param lineNo The zero-based line number.
|
|
* @param address Returns the exact address.
|
|
* @return false if the frame could not be parsed successfully. The
|
|
* output values are undefined in this case.
|
|
*/
|
|
virtual bool parseFrameChange(const char* output, int& frameNo,
|
|
TQString& file, int& lineNo, DbgAddr& address) = 0;
|
|
|
|
/**
|
|
* Parses a list of breakpoints.
|
|
* @param output The output of the debugger.
|
|
* @param brks The list of new #Breakpoint objects. The list
|
|
* must initially be empty.
|
|
* @return False if there was an error before the first breakpoint
|
|
* was found. Even if true is returned, #brks may be empty.
|
|
*/
|
|
virtual bool parseBreakList(const char* output, std::list<Breakpoint>& brks) = 0;
|
|
|
|
/**
|
|
* Parses a list of threads.
|
|
* @param output The output of the debugger.
|
|
* @return The new thread list. There is no indication if there was
|
|
* a parse error.
|
|
*/
|
|
virtual std::list<ThreadInfo> parseThreadList(const char* output) = 0;
|
|
|
|
/**
|
|
* Parses the output when the program stops to see whether this it
|
|
* stopped due to a breakpoint.
|
|
* @param output The output of the debugger.
|
|
* @param id Returns the breakpoint id.
|
|
* @param file Returns the file name in which the breakpoint is.
|
|
* @param lineNo Returns the zero-based line number of the breakpoint.
|
|
* @param address Returns the address of the breakpoint.
|
|
* @return False if there was no breakpoint.
|
|
*/
|
|
virtual bool parseBreakpoint(const char* output, int& id,
|
|
TQString& file, int& lineNo, TQString& address) = 0;
|
|
|
|
/**
|
|
* Parses the output of the DCinfolocals command.
|
|
* @param output The output of the debugger.
|
|
* @param newVars Receives the parsed variable values. The values are
|
|
* simply append()ed to the supplied list.
|
|
*/
|
|
virtual void parseLocals(const char* output, std::list<ExprValue*>& newVars) = 0;
|
|
|
|
/**
|
|
* Parses the output of a DCprint or DCprintStruct command.
|
|
* @param output The output of the debugger.
|
|
* @param wantErrorValue Specifies whether the error message should be
|
|
* provided as the value of a NKplain variable. If this is false,
|
|
* 0 is returned if the printed value is an error message.
|
|
* @return the parsed value. It is 0 if there was a parse error
|
|
* or if the output is an error message and #wantErrorValue
|
|
* is \c false. The returned object's text() is undefined.
|
|
*/
|
|
virtual ExprValue* parsePrintExpr(const char* output, bool wantErrorValue) = 0;
|
|
|
|
/**
|
|
* Parses the output of the DCcd command.
|
|
* @return false if the message is an error message.
|
|
*/
|
|
virtual bool parseChangeWD(const char* output, TQString& message) = 0;
|
|
|
|
/**
|
|
* Parses the output of the DCexecutable command.
|
|
* @return false if an error occured.
|
|
*/
|
|
virtual bool parseChangeExecutable(const char* output, TQString& message) = 0;
|
|
|
|
/**
|
|
* Parses the output of the DCcorefile command.
|
|
* @return false if the core file was not loaded successfully.
|
|
*/
|
|
virtual bool parseCoreFile(const char* output) = 0;
|
|
|
|
enum StopFlags {
|
|
SFrefreshSource = 1, /* refresh of source code is needed */
|
|
SFrefreshBreak = 2, /* refresh breakpoints */
|
|
SFrefreshThreads = 4, /* refresh thread list */
|
|
SFprogramActive = 128 /* program remains active */
|
|
};
|
|
/**
|
|
* Parses the output of commands that execute (a piece of) the program.
|
|
* @return The inclusive OR of zero or more of the StopFlags.
|
|
*/
|
|
virtual uint parseProgramStopped(const char* output, TQString& message) = 0;
|
|
|
|
/**
|
|
* Parses the output of the DCsharedlibs command.
|
|
*/
|
|
virtual TQStringList parseSharedLibs(const char* output) = 0;
|
|
|
|
/**
|
|
* Parses the output of the DCfindType command.
|
|
* @return true if a type was found.
|
|
*/
|
|
virtual bool parseFindType(const char* output, TQString& type) = 0;
|
|
|
|
/**
|
|
* Parses the output of the DCinforegisters command.
|
|
*/
|
|
virtual std::list<RegisterInfo> parseRegisters(const char* output) = 0;
|
|
|
|
/**
|
|
* Parses the output of the DCinfoline command. Returns false if the
|
|
* two addresses could not be found.
|
|
*/
|
|
virtual bool parseInfoLine(const char* output,
|
|
TQString& addrFrom, TQString& addrTo) = 0;
|
|
|
|
/**
|
|
* Parses the ouput of the DCdisassemble command.
|
|
*/
|
|
virtual std::list<DisassembledCode> parseDisassemble(const char* output) = 0;
|
|
|
|
/**
|
|
* Parses a memory dump. Returns an empty string if no error was found;
|
|
* otherwise it contains an error message.
|
|
*/
|
|
virtual TQString parseMemoryDump(const char* output, std::list<MemoryDump>& memdump) = 0;
|
|
|
|
/**
|
|
* Parses the output of the DCsetvariable command. Returns an empty
|
|
* string if no error was found; otherwise it contains an error
|
|
* message.
|
|
*/
|
|
virtual TQString parseSetVariable(const char* output) = 0;
|
|
|
|
/**
|
|
* Returns a value that the user can edit.
|
|
*/
|
|
virtual TQString editableValue(VarTree* value);
|
|
|
|
protected:
|
|
/** Removes all commands from the low-priority queue. */
|
|
void flushLoPriQueue();
|
|
/** Removes all commands from the high-priority queue. */
|
|
void flushHiPriQueue();
|
|
|
|
std::queue<CmdQueueItem*> m_hipriCmdQueue;
|
|
std::list<CmdQueueItem*> m_lopriCmdQueue;
|
|
/**
|
|
* The active command is kept separately from other pending commands.
|
|
*/
|
|
CmdQueueItem* m_activeCmd;
|
|
/**
|
|
* Helper function that queues the given command string in the
|
|
* low-priority queue.
|
|
*/
|
|
CmdQueueItem* queueCmdString(DbgCommand cmd, TQString cmdString,
|
|
QueueMode mode);
|
|
/**
|
|
* Helper function that queues the given command string in the
|
|
* high-priority queue.
|
|
*/
|
|
CmdQueueItem* executeCmdString(DbgCommand cmd, TQString cmdString,
|
|
bool clearLow);
|
|
void writeCommand();
|
|
virtual void commandFinished(CmdQueueItem* cmd) = 0;
|
|
|
|
protected:
|
|
/** @internal */
|
|
virtual int commSetupDoneC();
|
|
|
|
char m_prompt[10];
|
|
size_t m_promptMinLen;
|
|
char m_promptLastChar;
|
|
TQRegExp m_promptRE;
|
|
|
|
// log file
|
|
TQString m_logFileName;
|
|
TQFile m_logFile;
|
|
|
|
public slots:
|
|
void dequeueCmdByVar(VarTree* var);
|
|
|
|
protected slots:
|
|
virtual void slotReceiveOutput(TDEProcess*, char* buffer, int buflen);
|
|
virtual void slotCommandRead(TDEProcess*);
|
|
virtual void slotExited(TDEProcess*);
|
|
|
|
signals:
|
|
/**
|
|
* This signal is emitted when the output of a command has been fully
|
|
* collected and is ready to be interpreted.
|
|
*/
|
|
void commandReceived(CmdQueueItem* cmd, const char* output);
|
|
|
|
/**
|
|
* This signal is emitted when the debugger recognizes that a specific
|
|
* location in a file ought to be displayed.
|
|
*
|
|
* Gdb's --fullname option supports this for the step, next, frame, and
|
|
* run commands (and possibly others).
|
|
*
|
|
* @param file specifies the file; this is not necessarily a full path
|
|
* name, and if it is relative, you won't know relative to what, you
|
|
* can only guess.
|
|
* @param lineNo specifies the line number (0-based!) (this may be
|
|
* negative, in which case the file should be activated, but the line
|
|
* should NOT be changed).
|
|
* @param address specifies the exact address of the PC or is empty.
|
|
*/
|
|
void activateFileLine(const TQString& file, int lineNo, const DbgAddr& address);
|
|
|
|
/**
|
|
* This signal is emitted when a command that starts the inferior has
|
|
* been submitted to the debugger.
|
|
*/
|
|
void inferiorRunning();
|
|
|
|
/**
|
|
* This signal is emitted when all output from the debugger has been
|
|
* consumed and no more commands are in the queues.
|
|
*/
|
|
void enterIdleState();
|
|
};
|
|
|
|
#endif // DBGDRIVER_H
|