3 // Copyright by Johannes Sixt, Keith Isdale
4 // This file is under GPL, the GNU General Public Licence
6 #include "xsldbgdriver.h"
8 #include <qstringlist.h>
9 #include <klocale.h> /* i18n */
11 #include <stdlib.h> /* strtol, atoi */
12 #include <string.h> /* strcpy */
21 static VarTree
*parseVar(const char *&s
);
22 static bool parseName(const char *&s
, QString
& name
,
23 VarTree::NameKind
& kind
);
24 static bool parseValue(const char *&s
, VarTree
* variable
);
26 #define TERM_IO_ALLOWED 1
28 // TODO: make this cmd info stuff non-static to allow multiple
29 // simultaneous gdbs to run!
31 struct XsldbgCmdInfo
{
33 const char *fmt
; /* format string */
35 argNone
, argString
, argNum
,
36 argStringNum
, argNumString
,
42 * The following array of commands must be sorted by the DC* values,
43 * because they are used as indices.
45 static XsldbgCmdInfo cmds
[] = {
46 {DCinitialize
, "init\n", XsldbgCmdInfo::argNone
},
47 {DCtty
, "tty %s\n", XsldbgCmdInfo::argString
},
48 {DCexecutable
, "source %s\n", XsldbgCmdInfo::argString
}, /* force a restart */
49 {DCtargetremote
, "print 'target remote %s'\n", XsldbgCmdInfo::argString
},
50 {DCcorefile
, "data %s\n", XsldbgCmdInfo::argString
}, /* force a restart */
51 {DCattach
, "print 'attach %s'\n", XsldbgCmdInfo::argString
},
52 {DCinfolinemain
, "print 'info main line'\n", XsldbgCmdInfo::argNone
},
53 {DCinfolocals
, "locals -f\n", XsldbgCmdInfo::argNone
},
54 {DCinforegisters
, "print 'info reg'\n", XsldbgCmdInfo::argNone
},
55 {DCexamine
, "print 'x %s %s'\n", XsldbgCmdInfo::argString2
},
56 {DCinfoline
, "print 'templates %s:%d'\n", XsldbgCmdInfo::argStringNum
},
57 {DCdisassemble
, "print 'disassemble %s %s'\n", XsldbgCmdInfo::argString2
},
58 {DCsetargs
, "setargs %s\n", XsldbgCmdInfo::argString
},
59 {DCsetenv
, "addparam %s %s\n", XsldbgCmdInfo::argString2
},
60 {DCunsetenv
, "unset env %s\n", XsldbgCmdInfo::argString
},
61 {DCsetoption
, "setoption %s %d\n", XsldbgCmdInfo::argStringNum
},
62 {DCcd
, "chdir %s\n", XsldbgCmdInfo::argString
},
63 {DCbt
, "where\n", XsldbgCmdInfo::argNone
},
64 {DCrun
, "run\nsource\n", XsldbgCmdInfo::argNone
}, /* Ensure that at the start
65 of executing XSLT we show the XSLT file */
66 {DCcont
, "continue\n", XsldbgCmdInfo::argNone
},
67 {DCstep
, "step\n", XsldbgCmdInfo::argNone
},
68 {DCstepi
, "print 'DCstepi'\n", XsldbgCmdInfo::argNone
},
69 {DCnext
, "next\n", XsldbgCmdInfo::argNone
},
70 {DCnexti
, "print 'nexti'\n", XsldbgCmdInfo::argNone
},
71 {DCfinish
, "quit\n", XsldbgCmdInfo::argNone
},
72 {DCuntil
, "continue %s:%d\n", XsldbgCmdInfo::argStringNum
},
73 {DCkill
, "quit\n", XsldbgCmdInfo::argNone
},
74 {DCbreaktext
, "break %s\n", XsldbgCmdInfo::argString
},
75 {DCbreakline
, "break -l %s %d\n", XsldbgCmdInfo::argStringNum
},
76 {DCtbreakline
, "print `tbreak %s:%d`\n", XsldbgCmdInfo::argStringNum
},
77 {DCbreakaddr
, "print `break *%s`\n", XsldbgCmdInfo::argString
},
78 {DCtbreakaddr
, "print `tbreak *%s`\n", XsldbgCmdInfo::argString
},
79 {DCwatchpoint
, "print 'watch %s'\n", XsldbgCmdInfo::argString
},
80 {DCdelete
, "delete %d\n", XsldbgCmdInfo::argNum
},
81 {DCenable
, "enable %d\n", XsldbgCmdInfo::argNum
},
82 {DCdisable
, "disable %d\n", XsldbgCmdInfo::argNum
},
83 {DCprint
, "print %s\n", XsldbgCmdInfo::argString
},
84 {DCprintStruct
, "print 'print %s'\n", XsldbgCmdInfo::argString
},
85 {DCprintQStringStruct
, "print 'print %s'\n", XsldbgCmdInfo::argString
},
86 {DCframe
, "frame %d\n", XsldbgCmdInfo::argNum
},
87 {DCfindType
, "print 'whatis %s'\n", XsldbgCmdInfo::argString
},
88 {DCinfosharedlib
, "stylesheets\n", XsldbgCmdInfo::argNone
},
89 {DCthread
, "print 'thread %d'\n", XsldbgCmdInfo::argNum
},
90 {DCinfothreads
, "print 'info threads'\n", XsldbgCmdInfo::argNone
},
91 {DCinfobreak
, "show\n", XsldbgCmdInfo::argNone
},
92 {DCcondition
, "print 'condition %d %s'\n", XsldbgCmdInfo::argNumString
},
93 {DCignore
, "print 'ignore %d %d'\n", XsldbgCmdInfo::argNum2
},
96 #define NUM_CMDS (int(sizeof(cmds)/sizeof(cmds[0])))
97 #define MAX_FMTLEN 200
99 XsldbgDriver::XsldbgDriver():
100 DebuggerDriver(), m_gdbMajor(2), m_gdbMinor(0)
102 m_promptRE
.setPattern("\\(xsldbg\\) .*> $");
104 m_promptLastChar
= ' ';
106 m_markerRE
.setPattern("^Breakpoint at file ");
109 // check command info array
112 for (int i
= 0; i
< NUM_CMDS
; i
++) {
113 // must be indexable by DbgCommand values, i.e. sorted by DbgCommand values
114 assert(i
== cmds
[i
].cmd
);
115 // a format string must be associated
116 assert(cmds
[i
].fmt
!= 0);
117 assert(strlen(cmds
[i
].fmt
) <= MAX_FMTLEN
);
118 // format string must match arg specification
119 switch (cmds
[i
].argsNeeded
) {
120 case XsldbgCmdInfo::argNone
:
121 assert(strchr(cmds
[i
].fmt
, '%') == 0);
123 case XsldbgCmdInfo::argString
:
124 perc
= strchr(cmds
[i
].fmt
, '%');
125 assert(perc
!= 0 && perc
[1] == 's');
126 assert(strchr(perc
+ 2, '%') == 0);
128 case XsldbgCmdInfo::argNum
:
129 perc
= strchr(cmds
[i
].fmt
, '%');
130 assert(perc
!= 0 && perc
[1] == 'd');
131 assert(strchr(perc
+ 2, '%') == 0);
133 case XsldbgCmdInfo::argStringNum
:
134 perc
= strchr(cmds
[i
].fmt
, '%');
135 assert(perc
!= 0 && perc
[1] == 's');
136 perc
= strchr(perc
+ 2, '%');
137 assert(perc
!= 0 && perc
[1] == 'd');
138 assert(strchr(perc
+ 2, '%') == 0);
140 case XsldbgCmdInfo::argNumString
:
141 perc
= strchr(cmds
[i
].fmt
, '%');
142 assert(perc
!= 0 && perc
[1] == 'd');
143 perc
= strchr(perc
+ 2, '%');
144 assert(perc
!= 0 && perc
[1] == 's');
145 assert(strchr(perc
+ 2, '%') == 0);
147 case XsldbgCmdInfo::argString2
:
148 perc
= strchr(cmds
[i
].fmt
, '%');
149 assert(perc
!= 0 && perc
[1] == 's');
150 perc
= strchr(perc
+ 2, '%');
151 assert(perc
!= 0 && perc
[1] == 's');
152 assert(strchr(perc
+ 2, '%') == 0);
154 case XsldbgCmdInfo::argNum2
:
155 perc
= strchr(cmds
[i
].fmt
, '%');
156 assert(perc
!= 0 && perc
[1] == 'd');
157 perc
= strchr(perc
+ 2, '%');
158 assert(perc
!= 0 && perc
[1] == 'd');
159 assert(strchr(perc
+ 2, '%') == 0);
166 XsldbgDriver::~XsldbgDriver()
172 XsldbgDriver::driverName() const
178 XsldbgDriver::defaultXsldbg()
180 return "xsldbg --shell --gdb";
184 XsldbgDriver::defaultInvocation() const
186 return defaultXsldbg();
189 QStringList
XsldbgDriver::boolOptionList() const
191 QStringList allOptions
;
192 allOptions
.append("verbose");
193 allOptions
.append("repeat");
194 allOptions
.append("debug");
195 allOptions
.append("novalid");
196 allOptions
.append("noout");
197 allOptions
.append("html");
198 allOptions
.append("docbook");
199 allOptions
.append("nonet");
200 allOptions
.append("catalogs");
201 allOptions
.append("xinclude");
202 allOptions
.append("profile");
208 XsldbgDriver::slotReceiveOutput(KProcess
* process
, char *buffer
,
212 if (m_state
!= DSidle
) {
214 DebuggerDriver::slotReceiveOutput(process
, buffer
, buflen
);
216 if (strncmp(buffer
, "quit", 4) == 0) {
217 TRACE("Ignoring text when xsldbg is quiting");
220 ("Stray output received by XsldbgDriver::slotReceiveOutput");
227 XsldbgDriver::startup(QString cmdStr
)
229 if (!DebuggerDriver::startup(cmdStr
))
232 static const char xsldbgInitialize
[] = "pwd\n"; /* don't need to do anything else */
234 executeCmdString(DCinitialize
, xsldbgInitialize
, false);
240 XsldbgDriver::commandFinished(CmdQueueItem
* cmd
)
243 TRACE(__PRETTY_FUNCTION__
);
244 // command string must be committed
245 if (!cmd
->m_committed
) {
248 (__PRETTY_FUNCTION__
+
249 (" with uncommited command:\n\t" + cmd
->m_cmdString
)));
253 switch (cmd
->m_cmd
) {
255 // get version number from preamble
258 QRegExp
xsldbgVersion("^XSLDBG [0-9]+\\.[0-9]+\\.[0-9]+");
259 int offset
= xsldbgVersion
.match(m_output
, 0, &len
);
262 char *start
= m_output
+ offset
+ 7; // skip "^XSLDBG "
265 TRACE("Reading version");
267 m_gdbMajor
= strtol(start
, &end
, 10);
268 m_gdbMinor
= strtol(end
+ 1, 0, 10); // skip "."
270 // nothing was parsed
275 // assume some default version (what would make sense?)
279 TRACE(QString("Got version ") +
280 QString::number(m_gdbMajor
) + "." +
281 QString::number(m_gdbMinor
));
286 /* ok, the command is ready */
287 emit
commandReceived(cmd
, m_output
);
289 switch (cmd
->m_cmd
) {
306 XsldbgDriver::parseMarker()
309 // TRACE("parseMarker : xsldbg");
311 int len
, markerStart
= -1;
314 while (markerStart
== -1) {
315 if ((p
== 0) || (*p
== '\0')) {
319 //TRACE(QString("parseMarker is looking at :") + p);
320 markerStart
= m_markerRE
.match(p
, 0, &len
);
321 if (markerStart
== -1) {
322 // try to marker on next line !
324 if ((p
!= 0) && (*p
!= '\0'))
330 // extract the marker
331 char *startMarker
= p
+ markerStart
+ len
;
333 //TRACE(QString("found marker:") + startMarker);
334 char *endMarker
= strchr(startMarker
, '\n');
341 // extract filename and line number
342 static QRegExp
MarkerRE(" : line [0-9]+");
344 int lineNoStart
= MarkerRE
.match(startMarker
, 0, &len
);
346 if (lineNoStart
>= 0) {
347 int lineNo
= atoi(startMarker
+ lineNoStart
+ 8);
351 // now show the window
352 startMarker
[lineNoStart
] = '\0'; /* split off file name */
353 TRACE("Got file and line number");
354 TRACE(QString(startMarker
) + ": " + QString::number(lineNo
));
355 emit
activateFileLine(startMarker
, lineNo
- 1, address
);
361 * Escapes characters that might lead to problems when they appear on gdb's
365 normalizeStringArg(QString
& arg
)
368 * Remove trailing backslashes. This approach is a little simplistic,
369 * but we know that there is at the moment no case where a trailing
370 * backslash would make sense.
372 while (!arg
.isEmpty() && arg
[arg
.length() - 1] == '\\') {
373 arg
= arg
.left(arg
.length() - 1);
379 XsldbgDriver::makeCmdString(DbgCommand cmd
, QString strArg
)
381 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
382 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argString
);
384 normalizeStringArg(strArg
);
387 // need the working directory when parsing the output
388 m_programWD
= strArg
;
391 SIZED_QString(cmdString
, MAX_FMTLEN
+ strArg
.length());
392 cmdString
.sprintf(cmds
[cmd
].fmt
, strArg
.latin1());
397 XsldbgDriver::makeCmdString(DbgCommand cmd
, int intArg
)
399 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
400 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNum
);
402 SIZED_QString(cmdString
, MAX_FMTLEN
+ 30);
404 cmdString
.sprintf(cmds
[cmd
].fmt
, intArg
);
409 XsldbgDriver::makeCmdString(DbgCommand cmd
, QString strArg
, int intArg
)
411 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
412 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argStringNum
||
413 cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNumString
||
414 cmd
== DCexamine
|| cmd
== DCtty
);
416 normalizeStringArg(strArg
);
418 SIZED_QString(cmdString
, MAX_FMTLEN
+ 30 + strArg
.length());
422 * intArg specifies which channels should be redirected to
423 * /dev/null. It is a value or'ed together from RDNstdin,
424 * RDNstdout, RDNstderr.
426 static const char *const runRedir
[8] = {
430 " </dev/null >/dev/null",
432 " </dev/null 2>/dev/null",
434 " </dev/null >/dev/null 2>&1"
437 if (strArg
.isEmpty())
438 intArg
= 7; /* failsafe if no tty */
439 m_redirect
= runRedir
[intArg
& 7];
441 return makeCmdString(DCtty
, strArg
); /* note: no problem if strArg empty */
444 if (cmd
== DCexamine
) {
445 // make a format specifier from the intArg
446 static const char size
[16] = {
447 '\0', 'b', 'h', 'w', 'g'
449 static const char format
[16] = {
450 '\0', 'x', 'd', 'u', 'o', 't',
451 'a', 'c', 'f', 's', 'i'
454 assert(MDTsizemask
== 0xf); /* lowest 4 bits */
455 assert(MDTformatmask
== 0xf0); /* next 4 bits */
456 int count
= 16; /* number of entities to print */
457 char sizeSpec
= size
[intArg
& MDTsizemask
];
458 char formatSpec
= format
[(intArg
& MDTformatmask
) >> 4];
460 assert(sizeSpec
!= '\0');
461 assert(formatSpec
!= '\0');
462 // adjust count such that 16 lines are printed
463 switch (intArg
& MDTformatmask
) {
466 break; /* no modification needed */
468 // all cases drop through:
469 switch (intArg
& MDTsizemask
) {
482 spec
.sprintf("/%d%c%c", count
, sizeSpec
, formatSpec
);
484 return makeCmdString(DCexamine
, spec
, strArg
);
487 if (cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argStringNum
) {
488 // line numbers are zero-based
489 if (cmd
== DCuntil
|| cmd
== DCbreakline
||
490 cmd
== DCtbreakline
|| cmd
== DCinfoline
) {
493 if (cmd
== DCinfoline
) {
494 // must split off file name part
495 int slash
= strArg
.findRev('/');
498 strArg
= strArg
.right(strArg
.length() - slash
- 1);
500 cmdString
.sprintf(cmds
[cmd
].fmt
, strArg
.latin1(), intArg
);
502 cmdString
.sprintf(cmds
[cmd
].fmt
, intArg
, strArg
.latin1());
508 XsldbgDriver::makeCmdString(DbgCommand cmd
, QString strArg1
,
511 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
512 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argString2
);
514 normalizeStringArg(strArg1
);
515 normalizeStringArg(strArg2
);
517 SIZED_QString(cmdString
,
518 MAX_FMTLEN
+ strArg1
.length() + strArg2
.length());
519 cmdString
.sprintf(cmds
[cmd
].fmt
, strArg1
.latin1(), strArg2
.latin1());
524 XsldbgDriver::makeCmdString(DbgCommand cmd
, int intArg1
, int intArg2
)
526 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
527 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNum2
);
529 SIZED_QString(cmdString
, MAX_FMTLEN
+ 60);
530 cmdString
.sprintf(cmds
[cmd
].fmt
, intArg1
, intArg2
);
535 XsldbgDriver::executeCmd(DbgCommand cmd
, bool clearLow
)
537 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
538 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNone
);
541 m_haveCoreFile
= false;
544 return executeCmdString(cmd
, cmds
[cmd
].fmt
, clearLow
);
548 XsldbgDriver::executeCmd(DbgCommand cmd
, QString strArg
, bool clearLow
)
550 return executeCmdString(cmd
, makeCmdString(cmd
, strArg
), clearLow
);
554 XsldbgDriver::executeCmd(DbgCommand cmd
, int intArg
, bool clearLow
)
557 return executeCmdString(cmd
, makeCmdString(cmd
, intArg
), clearLow
);
561 XsldbgDriver::executeCmd(DbgCommand cmd
, QString strArg
, int intArg
,
564 return executeCmdString(cmd
, makeCmdString(cmd
, strArg
, intArg
),
569 XsldbgDriver::executeCmd(DbgCommand cmd
, QString strArg1
, QString strArg2
,
572 return executeCmdString(cmd
, makeCmdString(cmd
, strArg1
, strArg2
),
577 XsldbgDriver::executeCmd(DbgCommand cmd
, int intArg1
, int intArg2
,
580 return executeCmdString(cmd
, makeCmdString(cmd
, intArg1
, intArg2
),
585 XsldbgDriver::queueCmd(DbgCommand cmd
, QueueMode mode
)
587 return queueCmdString(cmd
, cmds
[cmd
].fmt
, mode
);
591 XsldbgDriver::queueCmd(DbgCommand cmd
, QString strArg
, QueueMode mode
)
593 return queueCmdString(cmd
, makeCmdString(cmd
, strArg
), mode
);
597 XsldbgDriver::queueCmd(DbgCommand cmd
, int intArg
, QueueMode mode
)
599 return queueCmdString(cmd
, makeCmdString(cmd
, intArg
), mode
);
603 XsldbgDriver::queueCmd(DbgCommand cmd
, QString strArg
, int intArg
,
606 return queueCmdString(cmd
, makeCmdString(cmd
, strArg
, intArg
), mode
);
610 XsldbgDriver::queueCmd(DbgCommand cmd
, QString strArg1
, QString strArg2
,
613 return queueCmdString(cmd
, makeCmdString(cmd
, strArg1
, strArg2
), mode
);
617 XsldbgDriver::terminate()
619 qDebug("XsldbgDriver::Terminate");
621 executeCmdString(DCinitialize
, "quit\n", true);
627 XsldbgDriver::detachAndTerminate()
629 qDebug("XsldbgDriver::detachAndTerminate");
631 executeCmdString(DCinitialize
, "quit\n", true);
636 XsldbgDriver::interruptInferior()
638 // remove accidentally queued commands
639 qDebug("interruptInferior");
645 isErrorExpr(const char *output
)
649 #define ERROR_WORD_COUNT 3
650 static const char *errorWords
[ERROR_WORD_COUNT
] = {
655 static int errorWordLength
[ERROR_WORD_COUNT
] = {
657 15, /* Unknown command*/
661 for (wordIndex
= 0; wordIndex
< ERROR_WORD_COUNT
; wordIndex
++){
663 errorWords
[wordIndex
],
664 errorWordLength
[wordIndex
]) == 0){
666 TRACE(QString("Error/Warning from xsldbg ") + output
);
675 * Returns true if the output is an error message. If wantErrorValue is
676 * true, a new VarTree object is created and filled with the error message.
679 parseErrorMessage(const char *output
,
680 VarTree
* &variable
, bool wantErrorValue
)
682 if (isErrorExpr(output
)) {
683 if (wantErrorValue
) {
684 // put the error message as value in the variable
685 variable
= new VarTree(QString(), VarTree::NKplain
);
686 const char *endMsg
= strchr(output
, '\n');
689 endMsg
= output
+ strlen(output
);
690 variable
->m_value
= FROM_LATIN1(output
, endMsg
- output
);
701 XsldbgDriver::parseQCharArray(const char */
*output*/
, bool /*wantErrorValue*/,
704 VarTree
*variable
= 0;
706 TRACE("XsldbgDriver::parseQCharArray not implmented");
711 parseVar(const char *&s
)
714 bool foundLocalVar
= false;
715 VarTree
*variable
= 0L;
718 VarTree::NameKind kind
;
720 TRACE(__PRETTY_FUNCTION__
);
723 if (parseErrorMessage(p
, variable
, false) == true) {
724 TRACE("Found error message");
728 if (strncmp(p
, " Local", 6) == 0) {
729 foundLocalVar
= true;
732 TRACE("Found local variable");
733 } else if (strncmp(p
, " Global", 7) == 0) {
736 TRACE("Found global variable");
737 } else if (strncmp(p
, "= ", 2) == 0) {
738 /* we're processing the result of a "print command" */
740 char *nextLine
= strchr(p
, '\n');
742 TRACE("Found print expr");
744 char nameBuffer
[100];
746 p
= p
+ 2; /* skip the "= " */
747 strncpy(nameBuffer
, p
, nextLine
- p
);
749 variable
= new VarTree(nameBuffer
, kind
);
750 if (variable
!= 0L) {
751 variable
->setDeleteChildren(true);
752 parseValue(p
, variable
);
757 return variable
; /* don't know what to do this this data abort!! */
764 // No value provided just a name
765 TRACE(QString("Parse var: name") + p
);
766 if (!parseName(p
, name
, kind
)) {
769 variable
= new VarTree(name
, kind
);
770 if (variable
!= 0L) {
771 variable
->setDeleteChildren(true);
778 TRACE(QString("Parse var: name") + p
);
779 if (!parseName(p
, name
, kind
)) {
782 variable
= new VarTree(name
, kind
);
783 if (variable
!= 0L) {
784 variable
->setDeleteChildren(true);
788 if (!parseValue(p
, variable
)) {
803 skipName(const char *&p
)
805 // allow : (for enumeration values) and $ and . (for _vtbl.)
806 while (isalnum(*p
) || *p
== '_' || *p
== ':' || *p
== '$' || *p
== '.')
811 parseName(const char *&s
, QString
& name
, VarTree::NameKind
& kind
)
813 /* qDebug(__PRETTY_FUNCTION__); */
814 kind
= VarTree::NKplain
;
819 // examples of names:
822 while ((*p
!= '\n') && (*p
!= '\0')) {
828 name
= FROM_LATIN1(s
, len
);
829 /* XSL variables will have a $ prefix to be evaluated
831 //TRACE(QString("parseName got name" ) + name);
833 // return the new position
839 parseValue(const char *&s
, VarTree
* variable
)
841 const char *start
= s
, *end
= s
;
842 VarTree
* childValue
;
843 #define VALUE_END_MARKER_INDEX 0
845 /* This mark the end of a value */
846 static const char *marker
[] = {
847 "\032\032", /* value end marker*/
849 "Breakpoint at", /* stepped to next location */
850 "Breakpoint in", /* reached a set breakpoint */
851 "Reached ", /* reached template */
858 static char valueBuffer
[255];
859 int markerIndex
= 0, foundEnd
= 0;
863 return false; /* should never happen but .. */
865 variable
->m_value
= "";
866 while (start
&& (*start
!= '\0')) {
867 /* look for the next marker */
868 for (markerIndex
= 0; marker
[markerIndex
] != 0; markerIndex
++) {
870 strncmp(start
, marker
[markerIndex
],
871 strlen(marker
[markerIndex
])) == 0;
880 end
= strchr(start
, '\n');
884 copySize
= end
- start
- 1;
885 if (copySize
> sizeof(valueBuffer
))
886 copySize
= sizeof(valueBuffer
);
888 strncpy(valueBuffer
, start
, copySize
);
889 valueBuffer
[copySize
] = '\0';
890 TRACE("Got value :");
892 childValue
= new VarTree(valueBuffer
, VarTree::NKplain
);
893 variable
->appendChild(childValue
);
897 childValue
= new VarTree(start
, VarTree::NKplain
);
898 variable
->appendChild(childValue
);
904 TRACE(QString("Unable to find end on value near :") + start
);
906 // If we've got something otherthan a end of value marker then
907 // advance to the end of this buffer
908 if (markerIndex
!= VALUE_END_MARKER_INDEX
){
909 while (start
&& *start
!= '\0')
912 start
= start
+ strlen(marker
[0]);
922 * Parses a stack frame.
925 parseFrameInfo(const char *&s
, QString
& func
,
926 QString
& file
, int &lineNo
, DbgAddr
& /*address*/)
928 const char *p
= s
, *endPos
= s
+ strlen(s
);
929 QString lineNoString
;
933 /* skip 'template :\" */
935 //TRACE("parseFrameInfo");
938 while ((*p
!= '\"') && (*p
!= '\0')) {
948 /* skip mode :".*" */
949 while (p
&& *p
!= '"')
953 while (p
&& *p
!= '"')
957 while (p
&& *p
!= '"')
959 /* skip '" in file ' */
963 while (!isspace(*p
) && (*p
!= '\0')) {
973 /* skip ' : line '" */
982 /* KDbg uses an offset of +1 for its line numbers */
983 lineNo
= atoi(p
) - 1;
984 lineNoString
= QString::number(lineNo
);
986 /* convert func into format needed */
990 func
.append(lineNoString
);
992 //TRACE(QString("Got frame : template :\"") + func + "\"file:" +
993 // file + " line : " + lineNoString);
995 /*advance to next line */
1006 * Parses a stack frame including its frame number
1009 parseFrame(const char *&s
, int &frameNo
, QString
& func
,
1010 QString
& file
, int &lineNo
, DbgAddr
& address
)
1013 // TRACE("XsldbgDriver ::parseFrame");
1014 /* skip leading 'where' or 'frame <frame_no>' */
1015 if ((strncmp(s
, "where", 5) == 0) || (strncmp(s
, "frame", 5) == 0)) {
1016 s
= strchr(s
, '\n');
1017 if ((*s
!= '\0') && (*s
!= '#'))
1023 //#1 template :"/" in file /home/keith/anon_CVS/xsldbg/docs/en/xsldoc.xsl : line 21
1024 // must start with a hash mark followed by number
1025 if (s
[0] != '#' || !isdigit(s
[1]))
1028 //TRACE("XsldbgDriver ::parseFrame got #");
1029 s
++; /* skip the hash mark */
1035 //TRACE(QString("Got frame ").append(QString::number(frameNo)));
1039 parseFrameInfo(s
, func
, file
, lineNo
, address
);
1040 // TRACE("Will next look at ");
1046 XsldbgDriver::parseBackTrace(const char *output
,
1047 QList
< StackFrame
> &stack
)
1050 int lineNo
, frameNo
;
1053 while (::parseFrame(output
, frameNo
, func
, file
, lineNo
, address
)) {
1054 StackFrame
*frm
= new StackFrame
;
1056 frm
->frameNo
= frameNo
;
1057 frm
->fileName
= file
;
1058 frm
->lineNo
= lineNo
;
1059 frm
->address
= address
;
1060 frm
->var
= new VarTree(func
, VarTree::NKplain
);
1066 XsldbgDriver::parseFrameChange(const char *output
, int &frameNo
,
1067 QString
& file
, int &lineNo
,
1072 return::parseFrame(output
, frameNo
, func
, file
, lineNo
, address
);
1077 XsldbgDriver::parseBreakList(const char *output
,
1078 QList
< Breakpoint
> &brks
)
1080 TRACE("parseBreakList");
1081 /* skip the first blank line */
1085 QString location
, file
, lineNo
;
1087 QString templateName
;
1090 uint ignoreCount
= 0;
1093 p
= strchr(output
, '\n');/* skip the first blank line*/
1095 while ((p
!= 0) && (*p
!= '\0')) {
1096 templateName
= QString();
1098 Breakpoint::Type bpType
= Breakpoint::breakpoint
;
1099 //qDebug("Looking at :%s", p);
1100 if (strncmp(p
, " Breakpoint", 11) != 0)
1108 long bpNum
= strtol(p
, &dummy
, 10); /* don't care about overflows */
1111 if ((p
== 0) || (p
[1] == '\0'))
1116 // Get breakpoint state ie enabled/disabled
1117 if (strncmp(p
, "enabled", 7) == 0) {
1121 if (strncmp(p
, "disabled", 8) == 0) {
1125 TRACE("Parse error in breakpoint list");
1131 //TRACE("Looking for template");
1134 /* check for ' for template :"'*/
1135 if (strncmp(p
, " for template :\"", 16) == 0){
1137 //TRACE("Looking for template name near");
1139 /* get the template name */
1140 while (p
&& (*p
!= '\0') && (*p
!= '\"')){
1141 templateName
.append(*p
);
1147 TRACE("Error missed \" near");
1152 //TRACE("Looking for mode near");
1154 if (strncmp(p
, " mode :\"", 8) == 0) {
1156 while (p
&& *p
!= '\"')
1162 if (strncmp(p
, " in file ", 9) != 0){
1163 TRACE("Parse error in breakpoint list");
1169 /* skip ' in file ' */
1173 /* grab file name */
1174 while (!isspace(*p
)) {
1181 /* skip ' : line ' */
1184 while (isdigit(*p
)) {
1190 //TRACE("Got breakpoint");
1192 Breakpoint
*bp
= new Breakpoint
;
1195 // take 1 of line number
1196 lineNo
.setNum(lineNo
.toInt() - 1);
1199 bp
->temporary
= false;
1200 bp
->enabled
= enabled
;
1201 location
.append("in ").append(templateName
).append(" at ");
1202 location
.append(file
).append(":").append(lineNo
);
1203 bp
->location
= location
;
1204 bp
->fileName
= file
;
1205 bp
->lineNo
= lineNo
.toInt();
1206 bp
->address
= address
;
1207 bp
->hitCount
= hits
;
1208 bp
->ignoreCount
= ignoreCount
;
1209 bp
->condition
= condition
;
1215 TRACE("Outof memory, breakpoint not created");
1218 p
= strchr(p
, '\n');
1225 XsldbgDriver::parseThreadList(const char */
*output*/
,
1226 QList
< ThreadInfo
> &/*threads*/)
1232 XsldbgDriver::parseBreakpoint(const char */
*output*/
, int &/*id*/,
1233 QString
& /*file*/, int &/*lineNo*/)
1235 TRACE("parseBreakpoint");
1240 XsldbgDriver::parseLocals(const char *output
, QList
< VarTree
> &newVars
)
1243 /* keep going until error or xsldbg prompt is found */
1244 while (*output
!= '\0') {
1245 VarTree
*variable
= parseVar(output
);
1247 if (variable
== 0) {
1250 // do not add duplicates
1251 for (VarTree
* o
= newVars
.first(); o
!= 0; o
= newVars
.next()) {
1252 if (o
->getText() == variable
->getText()) {
1258 newVars
.append(variable
);
1265 XsldbgDriver::parsePrintExpr(const char *output
, bool wantErrorValue
,
1268 // check for error conditions
1269 if (parseErrorMessage(output
, var
, wantErrorValue
)) {
1272 // parse the variable
1273 var
= parseVar(output
);
1279 XsldbgDriver::parseChangeWD(const char *output
, QString
& message
)
1281 bool isGood
= false;
1283 if (strncmp(output
, "Change to directory", 20) == 0) {
1284 output
= output
+ 20; /* skip 'Change to directory' */
1285 message
= QString(output
).simplifyWhiteSpace();
1286 if (message
.isEmpty()) {
1287 message
= i18n("New working directory: ") + m_programWD
;
1295 XsldbgDriver::parseChangeExecutable(const char *output
, QString
& message
)
1298 TRACE(QString("XsldbgDriver::parseChangeExecutable :") + output
);
1299 m_haveCoreFile
= false;
1302 * The command is successful if there is no output or the single
1303 * message (no debugging symbols found)...
1305 QRegExp
exp(".*Load of source deferred use run command.*");
1306 int len
, index
= exp
.match(output
, 0, &len
);
1309 TRACE("Parsed stylesheet executable");
1312 return (output
[0] == '\0') || (index
!= -1);
1316 XsldbgDriver::parseCoreFile(const char *output
)
1318 TRACE("XsldbgDriver::parseCoreFile");
1320 QRegExp
exp(".*Load of xml data deferred use run command.*");
1321 int len
, index
= exp
.match(output
, 0, &len
);
1324 m_haveCoreFile
= true;
1325 TRACE("Parsed xml data file");
1328 return m_haveCoreFile
;
1332 XsldbgDriver::parseProgramStopped(const char *output
, QString
& message
)
1334 /* Not sure about this function leave it here for the moment */
1336 * return DebuggerDriver::SFrefreshBreak & DebuggerDriver::SFprogramActive;
1339 // go through the output, line by line, checking what we have
1340 const char *start
= output
- 1;
1341 uint flags
= SFprogramActive
;
1343 message
= QString();
1345 start
++; /* skip '\n' */
1347 if (strncmp(start
, "Program ", 8) == 0 ||
1348 strncmp(start
, "ptrace: ", 8) == 0) {
1350 * When we receive a signal, the program remains active.
1352 * Special: If we "stopped" in a corefile, the string "Program
1353 * terminated with signal"... is displayed. (Normally, we see
1354 * "Program received signal"... when a signal happens.)
1356 if (strncmp(start
, "Program exited", 14) == 0 ||
1357 (strncmp(start
, "Program terminated", 18) == 0
1359 || strncmp(start
, "ptrace: ", 8) == 0) {
1360 flags
&= ~SFprogramActive
;
1363 const char *endOfMessage
= strchr(start
, '\n');
1365 if (endOfMessage
== 0)
1366 endOfMessage
= start
+ strlen(start
);
1367 message
= FROM_LATIN1(start
, endOfMessage
- start
);
1368 } else if (strncmp(start
, "Breakpoint ", 11) == 0) {
1370 * We stopped at a (permanent) breakpoint (gdb doesn't tell us
1371 * that it stopped at a temporary breakpoint).
1373 flags
|= SFrefreshBreak
;
1374 } else if (strstr(start
, "re-reading symbols.") != 0) {
1375 flags
|= SFrefreshSource
;
1377 // next line, please
1378 start
= strchr(start
, '\n');
1379 } while (start
!= 0);
1382 * Gdb only notices when new threads have appeared, but not when a
1383 * thread finishes. So we always have to assume that the list of
1384 * threads has changed.
1386 flags
|= SFrefreshThreads
;
1394 XsldbgDriver::parseSharedLibs(const char */
*output*/
, QStrList
& /*shlibs*/)
1400 XsldbgDriver::parseFindType(const char */
*output*/
, QString
& /*type*/)
1406 XsldbgDriver::parseRegisters(const char */
*output*/
,
1407 QList
< RegisterInfo
> &/*regs*/)
1413 XsldbgDriver::parseInfoLine(const char */
*output*/
, QString
& /*addrFrom*/,
1414 QString
& /*addrTo*/)
1420 XsldbgDriver::parseDisassemble(const char */
*output*/
,
1421 QList
< DisassembledCode
> &/*code*/)
1427 XsldbgDriver::parseMemoryDump(const char */
*output*/
,
1428 QList
< MemoryDump
> &/*memdump*/)
1430 return i18n("No memory dump available");
1434 #include "xsldbgdriver.moc"