1 /*
2  * Copyright Johannes Sixt
3  * This file is licensed under the GNU General Public License Version 2.
4  * See the file COPYING in the toplevel directory of the source directory.
5  */
6 
7 #ifndef DBGDRIVER_H
8 #define DBGDRIVER_H
9 
10 #include <QFile>
11 #include <QByteArray>
12 #include <QProcess>
13 #include <queue>
14 #include <list>
15 
16 
17 class VarTree;
18 class ExprValue;
19 class ExprWnd;
20 class KDebugger;
21 class QStringList;
22 
23 
24 /**
25  * A type representing an address.
26  */
27 struct DbgAddr
28 {
29     QString a;
30     QString fnoffs;
DbgAddrDbgAddr31     DbgAddr() { }
32     DbgAddr(const QString& aa);
DbgAddrDbgAddr33     DbgAddr(const DbgAddr& src) : a(src.a), fnoffs(src.fnoffs) { }
34     void operator=(const QString& aa);
35     void operator=(const DbgAddr& src) { a = src.a; fnoffs = src.fnoffs; }
36     QString asString() const;
isEmptyDbgAddr37     bool isEmpty() const { return a.isEmpty(); }
38 protected:
39     void cleanAddr();
40 };
41 bool operator==(const DbgAddr& a1, const DbgAddr& a2);
42 bool operator>(const DbgAddr& a1, const DbgAddr& a2);
43 
44 
45 enum DbgCommand {
46 	DCinitialize,
47 	DCtty,
48 	DCexecutable,
49 	DCtargetremote,
50 	DCcorefile,
51 	DCattach,
52 	DCinfolinemain,
53 	DCinfolocals,
54 	DCinforegisters,
55 	DCexamine,
56 	DCinfoline,
57 	DCdisassemble,
58 	DCsetargs,
59 	DCsetenv,
60 	DCunsetenv,
61 	DCsetoption,                    /* debugger options */
62 	DCcd,
63 	DCbt,
64 	DCrun,
65 	DCcont,
66 	DCstep,
67 	DCstepi,
68 	DCnext,
69 	DCnexti,
70 	DCfinish,
71 	DCuntil,			/* line number is zero-based! */
72 	DCkill,
73 	DCdetach,
74 	DCbreaktext,
75 	DCbreakline,			/* line number is zero-based! */
76 	DCtbreakline,			/* line number is zero-based! */
77 	DCbreakaddr,
78 	DCtbreakaddr,
79 	DCwatchpoint,
80 	DCdelete,
81 	DCenable,
82 	DCdisable,
83 	DCprint,
84 	DCprintDeref,
85 	DCprintStruct,
86 	DCprintQStringStruct,
87 	DCprintPopup,
88 	DCframe,
89 	DCfindType,
90 	DCinfosharedlib,
91 	DCthread,
92 	DCinfothreads,
93 	DCinfobreak,
94 	DCcondition,
95 	DCsetpc,
96 	DCignore,
97 	DCprintWChar,
98 	DCsetvariable
99 };
100 
101 enum RunDevNull {
102     RDNstdin = 0x1,			/* redirect stdin to /dev/null */
103     RDNstdout = 0x2,			/* redirect stdout to /dev/null */
104     RDNstderr = 0x4			/* redirect stderr to /dev/null */
105 };
106 
107 /**
108  * How the memory dump is formated. The lowest 4 bits define the size of
109  * the entities. The higher bits define how these are formatted. Note that
110  * not all combinations make sense.
111  */
112 enum MemoryDumpType {
113     // sizes
114     MDTbyte = 0x1,
115     MDThalfword = 0x2,
116     MDTword = 0x3,
117     MDTgiantword = 0x4,
118     MDTsizemask = 0xf,
119     // formats
120     MDThex = 0x10,
121     MDTsigned = 0x20,
122     MDTunsigned = 0x30,
123     MDToctal = 0x40,
124     MDTbinary = 0x50,
125     MDTaddress = 0x60,
126     MDTchar = 0x70,
127     MDTfloat = 0x80,
128     MDTstring = 0x90,
129     MDTinsn = 0xa0,
130     MDTformatmask = 0xf0
131 };
132 
133 struct Breakpoint;
134 
135 /**
136  * Debugger commands are placed in a queue. Only one command at a time is
137  * sent down to the debugger. All other commands in the queue are retained
138  * until the sent command has been processed by gdb. The debugger tells us
139  * that it's done with the command by sending the prompt. The output of the
140  * debugger is parsed at that time. Then, if more commands are in the
141  * queue, the next one is sent to the debugger.
142  */
143 struct CmdQueueItem
144 {
145     DbgCommand m_cmd;
146     QString m_cmdString;
147     bool m_committed;			/* just a debugging aid */
148     // remember which expression when printing an expression
149     VarTree* m_expr;
150     ExprWnd* m_exprWnd;
151     // remember file position
152     QString m_fileName;
153     int m_lineNo;
154     DbgAddr m_addr;
155     // the breakpoint info
156     Breakpoint* m_brkpt;
157     int m_existingBrkpt;
158     // whether command was emitted due to direct user request (only set when relevant)
159     bool m_byUser;
160     // used to store the expression to print in case of DCprintPopup is executed
161     QString m_popupExpr;
162 
CmdQueueItemCmdQueueItem163     CmdQueueItem(DbgCommand cmd, const QString& str) :
164     	m_cmd(cmd),
165 	m_cmdString(str),
166 	m_committed(false),
167 	m_expr(0),
168 	m_exprWnd(0),
169 	m_lineNo(0),
170 	m_brkpt(0),
171 	m_existingBrkpt(0),
172 	m_byUser(false)
173     { }
174 
175     struct IsEqualCmd
176     {
IsEqualCmdCmdQueueItem::IsEqualCmd177 	IsEqualCmd(DbgCommand cmd, const QString& str) : m_cmd(cmd), m_str(str) { }
178 	bool operator()(CmdQueueItem*) const;
179 	DbgCommand m_cmd;
180 	const QString& m_str;
181     };
182 };
183 
184 /**
185  * The information about a breakpoint that is parsed from the list of
186  * breakpoints.
187  */
188 struct Breakpoint
189 {
190     int id;				/* gdb's number */
191     enum Type {
192 	breakpoint, watchpoint
193     } type;
194     bool temporary;
195     bool enabled;
196     QString location;
197     QString text;			/* text if set using DCbreaktext */
198     DbgAddr address;			/* exact address of breakpoint */
199     QString condition;			/* condition as printed by gdb */
200     int ignoreCount;			/* ignore next that may hits */
201     int hitCount;			/* as reported by gdb */
202     // the following items repeat the location, but in a better usable way
203     QString fileName;
204     int lineNo;				/* zero-based line number */
205     Breakpoint();
isOrphanedBreakpoint206     bool isOrphaned() const { return id < 0; }
207 };
208 
209 /**
210  * Information about a stack frame.
211  */
212 struct FrameInfo
213 {
214     QString fileName;
215     int lineNo;				/* zero-based line number */
216     DbgAddr address;			/* exact address of PC */
217 };
218 
219 /**
220  * The information about a stack frame as parsed from the backtrace.
221  */
222 struct StackFrame : FrameInfo
223 {
224     int frameNo;
225     ExprValue* var;			/* more information if non-zero */
StackFrameStackFrame226     StackFrame() : var(0) { }
227     ~StackFrame();
228 };
229 
230 /**
231  * The information about a thread as parsed from the threads list.
232  */
233 struct ThreadInfo : FrameInfo
234 {
235     int id;				/* gdb's number */
236     QString threadName;			/* the SYSTAG */
237     QString function;			/* where thread is halted */
238     bool hasFocus;			/* the thread whose stack we are watching */
239 };
240 
241 /**
242  * Register information
243  */
244 struct RegisterInfo
245 {
246     QString regName;
247     QString rawValue;
248     QString cookedValue;		/* may be empty */
249     QString type;			/* of vector register if not empty */
250 };
251 
252 /**
253  * Disassembled code
254  */
255 struct DisassembledCode
256 {
257     DbgAddr address;
258     QString code;
259 };
260 
261 /**
262  * Memory contents
263  */
264 struct MemoryDump
265 {
266     DbgAddr address;
267     QString dump;
268     bool littleendian = true;
269     bool endOfDump = false;
270 };
271 
272 /**
273  * This is an abstract base class for debugger process.
274  *
275  * This class represents the debugger program. It provides the low-level
276  * interface to the commandline debugger. As such it implements the
277  * commands and parses the output.
278  */
279 class DebuggerDriver : public QProcess
280 {
281     Q_OBJECT
282 public:
283     DebuggerDriver();
284     virtual ~DebuggerDriver() = 0;
285 
286     virtual QString driverName() const = 0;
287     /**
288      * Returns the default command string to invoke the debugger driver.
289      */
290     virtual QString defaultInvocation() const = 0;
291 
292     /**
293      * Returns a list of options that can be  turned on and off.
294      */
295     virtual QStringList boolOptionList() const = 0;
296 
297     virtual bool startup(QString cmdStr);
setLogFileName(const QString & fname)298     void setLogFileName(const QString& fname) { m_logFileName = fname; }
isRunning()299     bool isRunning() { return state() != NotRunning; }
300 
301 protected:
302     QString m_runCmd;
303 
304     enum DebuggerState {
305 	DSidle,				/* gdb waits for input */
306 	DSinterrupted,			/* a command was interrupted */
307 	DSrunningLow,			/* gdb is running a low-priority command */
308 	DSrunning,			/* gdb waits for program */
309 	DScommandSent,			/* command has been sent, we wait for wroteStdin signal */
310 	DScommandSentLow		/* low-prioritycommand has been sent */
311     };
312     DebuggerState m_state;
313 
314 public:
isIdle()315     bool isIdle() const { return m_state == DSidle; }
316     /**
317      * Tells whether a high prority command would be executed immediately.
318      */
canExecuteImmediately()319     bool canExecuteImmediately() const { return m_hipriCmdQueue.empty(); }
320 
321 protected:
322     QByteArray m_output;		// normal gdb output
323     std::queue<QByteArray> m_delayedOutput;	// output colleced before signal bytesWritten() arrived
324 
325 public:
326     /**
327      * Enqueues a high-priority command. High-priority commands are
328      * executed before any low-priority commands. No user interaction is
329      * possible as long as there is a high-priority command in the queue.
330      */
331     template<class... ARGS>
executeCmd(DbgCommand cmd,ARGS &&...args)332     CmdQueueItem* executeCmd(DbgCommand cmd, ARGS&&... args)
333     {
334 	return executeCmdString(cmd,
335 			makeCmdString(cmd, std::forward<ARGS>(args)...), false);
336     }
337     template<class... ARGS>
executeCmdOnce(DbgCommand cmd,ARGS &&...args)338     CmdQueueItem* executeCmdOnce(DbgCommand cmd, ARGS&&... args)
339     {
340 	return executeCmdString(cmd,
341 			makeCmdString(cmd, std::forward<ARGS>(args)...), true);
342     }
343 
344     enum QueueMode {
345 	QMnormal,			/* queues the command last */
346 	QMoverride,			/* removes an already queued command */
347 	QMoverrideMoreEqual		/* ditto, also puts the command first in the queue */
348     };
349 
350     /**
351      * Enqueues a low-priority command irrespective of whether it as already
352      * in the queue.
353      * Low-priority commands are executed after any high-priority commands.
354      */
355     template<class... ARGS>
queueCmdAgain(DbgCommand cmd,ARGS &&...args)356     CmdQueueItem* queueCmdAgain(DbgCommand cmd, ARGS&&... args)
357     {
358 	return queueCmdString(cmd,
359 			makeCmdString(cmd, std::forward<ARGS>(args)...), QMnormal);
360     }
361 
362     /**
363      * Enqueues a low-priority command, unless it is already in the queue.
364      * Low-priority commands are executed after any high-priority commands.
365      */
366     template<class... ARGS>
queueCmd(DbgCommand cmd,ARGS &&...args)367     CmdQueueItem* queueCmd(DbgCommand cmd, ARGS&&... args)
368     {
369 	return queueCmdString(cmd,
370 			makeCmdString(cmd, std::forward<ARGS>(args)...), QMoverride);
371     }
372 
373     /**
374      * Enqueues a low-priority command in front of all other low-prority
375      * commands.
376      * Low-priority commands are executed after any high-priority commands.
377      */
378     template<class... ARGS>
queueCmdPrio(DbgCommand cmd,ARGS &&...args)379     CmdQueueItem* queueCmdPrio(DbgCommand cmd, ARGS&&... args)
380     {
381 	return queueCmdString(cmd,
382 			makeCmdString(cmd, std::forward<ARGS>(args)...), QMoverrideMoreEqual);
383     }
384 
385    /**
386      * Flushes the command queues.
387      * @param hipriOnly if true, only the high priority queue is flushed.
388      */
389     virtual void flushCommands(bool hipriOnly = false);
390 
391     /**
392      * Terminates the debugger process.
393      */
394     virtual void terminate() = 0;
395 
396     /**
397      * Terminates the debugger process, but also detaches any program that
398      * it has been attached to.
399      */
400     virtual void detachAndTerminate() = 0;
401 
402     /**
403      * Interrupts the debuggee.
404      */
405     virtual void interruptInferior() = 0;
406 
407     /**
408      * Specifies the command that prints the QString data.
409      */
410     virtual void setPrintQStringDataCmd(const char* cmd) = 0;
411 
412     /**
413      * Parses the output as an array of QChars.
414      */
415     virtual ExprValue* parseQCharArray(const char* output, bool wantErrorValue, bool qt3like) = 0;
416 
417     /**
418      * Parses a back-trace (the output of the DCbt command).
419      */
420     virtual void parseBackTrace(const char* output, std::list<StackFrame>& stack) = 0;
421 
422     /**
423      * Parses the output of the DCframe command;
424      * @param frameNo Returns the frame number.
425      * @param file Returns the source file name.
426      * @param lineNo The zero-based line number.
427      * @param address Returns the exact address.
428      * @return false if the frame could not be parsed successfully. The
429      * output values are undefined in this case.
430      */
431     virtual bool parseFrameChange(const char* output, int& frameNo,
432 				  QString& file, int& lineNo, DbgAddr& address) = 0;
433 
434     /**
435      * Parses a list of breakpoints.
436      * @param output The output of the debugger.
437      * @param brks The list of new #Breakpoint objects. The list
438      * must initially be empty.
439      * @return False if there was an error before the first breakpoint
440      * was found. Even if true is returned, #brks may be empty.
441      */
442     virtual bool parseBreakList(const char* output, std::list<Breakpoint>& brks) = 0;
443 
444     /**
445      * Parses a list of threads.
446      * @param output The output of the debugger.
447      * @return The new thread list. There is no indication if there was
448      * a parse error.
449      */
450     virtual std::list<ThreadInfo> parseThreadList(const char* output) = 0;
451 
452     /**
453      * Parses the output when the program stops to see whether this it
454      * stopped due to a breakpoint.
455      * @param output The output of the debugger.
456      * @param id Returns the breakpoint id.
457      * @param file Returns the file name in which the breakpoint is.
458      * @param lineNo Returns the zero-based line number of the breakpoint.
459      * @param address Returns the address of the breakpoint.
460      * @return False if there was no breakpoint.
461      */
462     virtual bool parseBreakpoint(const char* output, int& id,
463 				 QString& file, int& lineNo, QString& address) = 0;
464 
465     /**
466      * Parses the output of the DCinfolocals command.
467      * @param output The output of the debugger.
468      * @param newVars Receives the parsed variable values. The values are
469      * simply append()ed to the supplied list.
470      */
471     virtual void parseLocals(const char* output, std::list<ExprValue*>& newVars) = 0;
472 
473     /**
474      * Parses the output of a DCprint or DCprintStruct command.
475      * @param output The output of the debugger.
476      * @param wantErrorValue Specifies whether the error message should be
477      * provided as the value of a NKplain variable. If this is false,
478      * 0 is returned if the printed value is an error message.
479      * @return the parsed value. It is 0 if there was a parse error
480      * or if the output is an error message and #wantErrorValue
481      * is \c false. The returned object's text() is undefined.
482      */
483     virtual ExprValue* parsePrintExpr(const char* output, bool wantErrorValue) = 0;
484 
485     /**
486      * Parses the output of the DCcd command.
487      * @return false if the message is an error message.
488      */
489     virtual bool parseChangeWD(const char* output, QString& message) = 0;
490 
491     /**
492      * Parses the output of the DCexecutable command.
493      * @return false if an error occured.
494      */
495     virtual bool parseChangeExecutable(const char* output, QString& message) = 0;
496 
497     /**
498      * Parses the output of the DCcorefile command.
499      * @return false if the core file was not loaded successfully.
500      */
501     virtual bool parseCoreFile(const char* output) = 0;
502 
503     enum StopFlags {
504 	SFrefreshSource = 1,		/* refresh of source code is needed */
505 	SFrefreshBreak = 2,		/* refresh breakpoints */
506 	SFrefreshThreads = 4,		/* refresh thread list */
507 	SFprogramActive = 128		/* program remains active */
508     };
509     /**
510      * Parses the output of commands that execute (a piece of) the program.
511      * \a haveCoreFile indicates whether the "stop" could be due to
512      * a core file being loaded.
513      * @return The inclusive OR of zero or more of the StopFlags.
514      */
515     virtual uint parseProgramStopped(const char* output, bool haveCoreFile,
516 				     QString& message) = 0;
517 
518     /**
519      * Parses the output of the DCsharedlibs command.
520      */
521     virtual QStringList parseSharedLibs(const char* output) = 0;
522 
523     /**
524      * Parses the output of the DCfindType command.
525      * @return true if a type was found.
526      */
527     virtual bool parseFindType(const char* output, QString& type) = 0;
528 
529     /**
530      * Parses the output of the DCinforegisters command.
531      */
532     virtual std::list<RegisterInfo> parseRegisters(const char* output) = 0;
533 
534     /**
535      * Parses the output of the DCinfoline command. Returns false if the
536      * two addresses could not be found.
537      */
538     virtual bool parseInfoLine(const char* output,
539 			       QString& addrFrom, QString& addrTo) = 0;
540 
541     /**
542      * Parses the ouput of the DCdisassemble command.
543      */
544     virtual std::list<DisassembledCode> parseDisassemble(const char* output) = 0;
545 
546     /**
547      * Parses a memory dump. Returns an empty string if no error was found;
548      * otherwise it contains an error message.
549      */
550     virtual QString parseMemoryDump(const char* output, std::list<MemoryDump>& memdump) = 0;
551 
552     /**
553      * Parses the output of the DCsetvariable command. Returns an empty
554      * string if no error was found; otherwise it contains an error
555      * message.
556      */
557     virtual QString parseSetVariable(const char* output) = 0;
558 
559     /**
560      * Returns a value that the user can edit.
561      */
562     virtual QString editableValue(VarTree* value);
563 
564 protected:
565     /** Removes all commands from the low-priority queue. */
566     void flushLoPriQueue();
567     /** Removes all commands from  the high-priority queue. */
568     void flushHiPriQueue();
569 
570     std::queue<CmdQueueItem*> m_hipriCmdQueue;
571     std::list<CmdQueueItem*> m_lopriCmdQueue;
572     /**
573      * The active command is kept separately from other pending commands.
574      */
575     CmdQueueItem* m_activeCmd;
576     /**
577      * Helper function that queues the given command string in the
578      * low-priority queue.
579      */
580     CmdQueueItem* queueCmdString(DbgCommand cmd, QString cmdString,
581 				 QueueMode mode);
582     /**
583      * Helper function that queues the given command string in the
584      * high-priority queue.
585      */
586     CmdQueueItem* executeCmdString(DbgCommand cmd, QString cmdString,
587 				   bool clearLow);
588     void writeCommand();
589     virtual void commandFinished(CmdQueueItem* cmd) = 0;
590     virtual QString makeCmdString(DbgCommand cmd) = 0;
591     virtual QString makeCmdString(DbgCommand cmd, QString strArg) = 0;
592     virtual QString makeCmdString(DbgCommand cmd, int intArg) = 0;
593     virtual QString makeCmdString(DbgCommand cmd, QString strArg, int intArg) = 0;
594     virtual QString makeCmdString(DbgCommand cmd, QString strArg1, QString strArg2) = 0;
595     virtual QString makeCmdString(DbgCommand cmd, int intArg1, int intArg2) = 0;
596     virtual QString makeCmdString(DbgCommand cmd, QString strArg, int intArg1, int intArg2) = 0;
597 
598 protected:
599     void processOutput(const QByteArray& data);
600 
601     /**
602      * Returns the start of the prompt in \a output or -1.
603      * \a len specifies the size of \a output, but in addition, the contents
604      * of \a output are NUL-terminated, i.e., \c output[len] is zero.
605      */
606     virtual int findPrompt(const QByteArray& output) const = 0;
607 
608     // log file
609     QString m_logFileName;
610     QFile m_logFile;
611 
612 public slots:
613     void dequeueCmdByVar(VarTree* var);
614 
615 protected slots:
616     virtual void slotReceiveOutput();
617     virtual void slotCommandRead();
618     virtual void slotExited();
619 
620 signals:
621     /**
622      * This signal is emitted when the output of a command has been fully
623      * collected and is ready to be interpreted.
624      */
625     void commandReceived(CmdQueueItem* cmd, const char* output);
626 
627     /**
628      * This signal is emitted when the debugger recognizes that a specific
629      * location in a file ought to be displayed.
630      *
631      * Gdb's --fullname option supports this for the step, next, frame, and
632      * run commands (and possibly others).
633      *
634      * @param file specifies the file; this is not necessarily a full path
635      * name, and if it is relative, you won't know relative to what, you
636      * can only guess.
637      * @param lineNo specifies the line number (0-based!) (this may be
638      * negative, in which case the file should be activated, but the line
639      * should NOT be changed).
640      * @param address specifies the exact address of the PC or is empty.
641      */
642     void activateFileLine(const QString& file, int lineNo, const DbgAddr& address);
643 
644     /**
645      * This signal is emitted when a command that starts the inferior has
646      * been submitted to the debugger.
647      */
648     void inferiorRunning();
649 
650     /**
651      * This signal is emitted when all output from the debugger has been
652      * consumed and no more commands are in the queues.
653      */
654     void enterIdleState();
655 };
656 
657 #endif // DBGDRIVER_H
658