gdbdriver.cpp (kdbg-2.5.5) | : | gdbdriver.cpp (kdbg-2.5.6) | ||
---|---|---|---|---|
skipping to change at line 694 | skipping to change at line 694 | |||
strncmp(output, "Cannot access memory at", 23) == 0 || | strncmp(output, "Cannot access memory at", 23) == 0 || | |||
strncmp(output, "Attempt to dereference a generic pointer", 40) == 0 || | strncmp(output, "Attempt to dereference a generic pointer", 40) == 0 || | |||
strncmp(output, "Attempt to take contents of ", 28) == 0 || | strncmp(output, "Attempt to take contents of ", 28) == 0 || | |||
strncmp(output, "Attempt to use a type name as an expression", 43) == 0 | | | strncmp(output, "Attempt to use a type name as an expression", 43) == 0 | | | |||
strncmp(output, "There is no member or method named", 34) == 0 || | strncmp(output, "There is no member or method named", 34) == 0 || | |||
strncmp(output, "A parse error in expression", 27) == 0 || | strncmp(output, "A parse error in expression", 27) == 0 || | |||
strncmp(output, "No symbol \"", 11) == 0 || | strncmp(output, "No symbol \"", 11) == 0 || | |||
strncmp(output, "Internal error: ", 16) == 0; | strncmp(output, "Internal error: ", 16) == 0; | |||
} | } | |||
static void skipSpace(const char*& p) | ||||
{ | ||||
while (isspace(*p)) | ||||
p++; | ||||
} | ||||
static void skipDecimal(const char*& p) | ||||
{ | ||||
while (isdigit(*p)) | ||||
p++; | ||||
} | ||||
/** | /** | |||
* Returns true if the output is an error message. If wantErrorValue is | * Returns true if the output is an error message. If wantErrorValue is | |||
* true, a new ExprValue object is created and filled with the error message. | * true, a new ExprValue object is created and filled with the error message. | |||
* If there are warnings, they are skipped and output points past the warnings | * If there are warnings, they are skipped and output points past the warnings | |||
* on return (even if there \e are errors). | * on return (even if there \e are errors). | |||
*/ | */ | |||
static bool parseErrorMessage(const char*& output, | static bool parseErrorMessage(const char*& output, | |||
ExprValue*& variable, bool wantErrorValue) | ExprValue*& variable, bool wantErrorValue) | |||
{ | { | |||
while (isspace(*output)) | skipSpace(output); | |||
output++; | ||||
// skip warnings | // skip warnings | |||
while (strncmp(output, "warning:", 8) == 0) | while (strncmp(output, "warning:", 8) == 0) | |||
{ | { | |||
const char* end = strchr(output+8, '\n'); | const char* end = strchr(output+8, '\n'); | |||
if (end == 0) | if (end == 0) | |||
output += strlen(output); | output += strlen(output); | |||
else | else | |||
output = end+1; | output = end+1; | |||
while (isspace(*output)) | skipSpace(output); | |||
output++; | ||||
} | } | |||
if (isErrorExpr(output)) | if (isErrorExpr(output)) | |||
{ | { | |||
if (wantErrorValue) { | if (wantErrorValue) { | |||
// put the error message as value in the variable | // put the error message as value in the variable | |||
variable = new ExprValue(QString(), VarTree::NKplain); | variable = new ExprValue(QString(), VarTree::NKplain); | |||
const char* endMsg = strchr(output, '\n'); | const char* endMsg = strchr(output, '\n'); | |||
if (endMsg == 0) | if (endMsg == 0) | |||
endMsg = output + strlen(output); | endMsg = output + strlen(output); | |||
skipping to change at line 762 | skipping to change at line 772 | |||
} | } | |||
ExprValue* GdbDriver::parseQCharArray(const char* output, bool wantErrorValue, b ool qt3like) | ExprValue* GdbDriver::parseQCharArray(const char* output, bool wantErrorValue, b ool qt3like) | |||
{ | { | |||
ExprValue* variable = 0; | ExprValue* variable = 0; | |||
/* | /* | |||
* Parse off white space. gdb sometimes prints white space first if the | * Parse off white space. gdb sometimes prints white space first if the | |||
* printed array leaded to an error. | * printed array leaded to an error. | |||
*/ | */ | |||
while (isspace(*output)) | skipSpace(output); | |||
output++; | ||||
// special case: empty string (0 repetitions) | // special case: empty string (0 repetitions) | |||
if (strncmp(output, "Invalid number 0 of repetitions", 31) == 0) | if (strncmp(output, "Invalid number 0 of repetitions", 31) == 0) | |||
{ | { | |||
variable = new ExprValue(QString(), VarTree::NKplain); | variable = new ExprValue(QString(), VarTree::NKplain); | |||
variable->m_value = "\"\""; | variable->m_value = "\"\""; | |||
return variable; | return variable; | |||
} | } | |||
// check for error conditions | // check for error conditions | |||
skipping to change at line 785 | skipping to change at line 794 | |||
return variable; | return variable; | |||
// parse the array | // parse the array | |||
// find '=' | // find '=' | |||
const char* p = output; | const char* p = output; | |||
p = strchr(p, '='); | p = strchr(p, '='); | |||
if (p == 0) { | if (p == 0) { | |||
goto error; | goto error; | |||
} | } | |||
// skip white space | p++; | |||
do { | skipSpace(p); | |||
p++; | ||||
} while (isspace(*p)); | ||||
if (*p == '{') | if (*p == '{') | |||
{ | { | |||
// this is the real data | // this is the real data | |||
p++; /* skip '{' */ | p++; /* skip '{' */ | |||
// parse the array | // parse the array | |||
QString result; | QString result; | |||
QString repeatCount; | QString repeatCount; | |||
enum { wasNothing, wasChar, wasRepeat } lastThing = wasNothing; | enum { wasNothing, wasChar, wasRepeat } lastThing = wasNothing; | |||
skipping to change at line 915 | skipping to change at line 922 | |||
variable = new ExprValue(QString(), VarTree::NKplain); | variable = new ExprValue(QString(), VarTree::NKplain); | |||
variable->m_value = "internal parse error"; | variable->m_value = "internal parse error"; | |||
} | } | |||
return variable; | return variable; | |||
} | } | |||
static ExprValue* parseVar(const char*& s) | static ExprValue* parseVar(const char*& s) | |||
{ | { | |||
const char* p = s; | const char* p = s; | |||
// skip whitespace | skipSpace(p); | |||
while (isspace(*p)) | ||||
p++; | ||||
QString name; | QString name; | |||
VarTree::NameKind kind; | VarTree::NameKind kind; | |||
/* | /* | |||
* Detect anonymouse struct values: The 'name =' part is missing: | * Detect anonymouse struct values: The 'name =' part is missing: | |||
* s = { a = 1, { b = 2 }} | * s = { a = 1, { b = 2 }} | |||
* Note that this detection works only inside structs when the anonymous | * Note that this detection works only inside structs when the anonymous | |||
* struct is not the first member: | * struct is not the first member: | |||
* s = {{ a = 1 }, b = 2} | * s = {{ a = 1 }, b = 2} | |||
* This is misparsed (by parseNested()) because it is mistakenly | * This is misparsed (by parseNested()) because it is mistakenly | |||
skipping to change at line 943 | skipping to change at line 948 | |||
name = i18n("<anonymous struct or union>"); | name = i18n("<anonymous struct or union>"); | |||
kind = VarTree::NKanonymous; | kind = VarTree::NKanonymous; | |||
} | } | |||
else | else | |||
{ | { | |||
if (!parseName(p, name, kind)) { | if (!parseName(p, name, kind)) { | |||
return 0; | return 0; | |||
} | } | |||
// go for '=' | // go for '=' | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
if (*p != '=') { | if (*p != '=') { | |||
TRACE("parse error: = not found after " + name); | TRACE("parse error: = not found after " + name); | |||
return 0; | return 0; | |||
} | } | |||
// skip the '=' and more whitespace | // skip the '=' and more whitespace | |||
p++; | p++; | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
} | } | |||
ExprValue* variable = new ExprValue(name, kind); | ExprValue* variable = new ExprValue(name, kind); | |||
if (!parseValue(p, variable)) { | if (!parseValue(p, variable)) { | |||
delete variable; | delete variable; | |||
return 0; | return 0; | |||
} | } | |||
s = p; | s = p; | |||
return variable; | return variable; | |||
skipping to change at line 1084 | skipping to change at line 1087 | |||
} | } | |||
// closing quote | // closing quote | |||
p++; | p++; | |||
/* | /* | |||
* Strings can consist of several parts, some of which contain repeated | * Strings can consist of several parts, some of which contain repeated | |||
* characters. | * characters. | |||
*/ | */ | |||
if (quote == '\'') { | if (quote == '\'') { | |||
// look ahaead for <repeats 123 times> | // look ahaead for <repeats 123 times> | |||
const char* q = p+1; | const char* q = p+1; | |||
while (isspace(*q)) | skipSpace(q); | |||
q++; | ||||
if (strncmp(q, "<repeats ", 9) == 0) { | if (strncmp(q, "<repeats ", 9) == 0) { | |||
p = q+9; | p = q+9; | |||
while (*p != '\0' && *p != '>') | while (*p != '\0' && *p != '>') | |||
p++; | p++; | |||
if (*p != '\0') { | if (*p != '\0') { | |||
p++; /* skip the '>' */ | p++; /* skip the '>' */ | |||
} | } | |||
} | } | |||
} | } | |||
// Is the string continued? If so, there is no L in wchar_t strings | // Is the string continued? If so, there is no L in wchar_t strings | |||
if (*p == ',') | if (*p == ',') | |||
{ | { | |||
// look ahead for another quote | // look ahead for another quote | |||
const char* q = p+1; | const char* q = p+1; | |||
while (isspace(*q)) | skipSpace(q); | |||
q++; | ||||
if (*q == '"' || *q == '\'') { | if (*q == '"' || *q == '\'') { | |||
// yes! | // yes! | |||
p = q; | p = q; | |||
goto moreStrings; | goto moreStrings; | |||
} | } | |||
// some strings can end in <incomplete sequence ...> | // some strings can end in <incomplete sequence ...> | |||
if (strncmp(q, "<incomplete sequence", 20) == 0) | if (strncmp(q, "<incomplete sequence", 20) == 0) | |||
{ | { | |||
p = q+20; | p = q+20; | |||
skipping to change at line 1170 | skipping to change at line 1171 | |||
continue; | continue; | |||
} | } | |||
p++; | p++; | |||
} | } | |||
if (nest > 0) { | if (nest > 0) { | |||
TRACE(QString().sprintf("parse error: mismatching %c%c at %-20.20s", open ing, closing, s)); | TRACE(QString().sprintf("parse error: mismatching %c%c at %-20.20s", open ing, closing, s)); | |||
} | } | |||
s = p; | s = p; | |||
} | } | |||
inline void skipName(const char*& p) | static void skipName(const char*& p) | |||
{ | { | |||
// allow : (for enumeration values) and $ and . (for _vtbl.) | // allow : (for enumeration values) and $ and . (for _vtbl.) | |||
while (isalnum(*p) || *p == '_' || *p == ':' || *p == '$' || *p == '.') | while (isalnum(*p) || *p == '_' || *p == ':' || *p == '$' || *p == '.') | |||
p++; | p++; | |||
} | } | |||
static void skipFunctionName(const char*& p) | ||||
{ | ||||
while (*p) | ||||
{ | ||||
if (*p == '<') { | ||||
// skip template parameter list | ||||
skipNestedAngles(p); | ||||
} else if (*p == '(') { | ||||
// this skips "(anonymous namespace)" as well as the formal | ||||
// parameter list of the containing function if this is a member | ||||
// of a nested class | ||||
skipNestedWithString(p, '(', ')'); | ||||
} else if (isalnum(*p) || *p == '_' || *p == ':') { | ||||
const char* start = p; | ||||
skipName(p); | ||||
// check for operator | ||||
if (p-start >= 8 && | ||||
strncmp(p-8, "operator", 8) == 0 && | ||||
// do not mistake this as the tail of some identifier | ||||
(p-start == 8 || !(isalnum(p[-9]) || p[-9] == '_'))) | ||||
{ | ||||
// skip forward until we find the opening parenthesis | ||||
// this catches both operator()(...) as well as | ||||
// type conversion operators, e.g. | ||||
// operator char const*() const | ||||
// operator void(*)() | ||||
while (*p && *p != '(') | ||||
p++; | ||||
} | ||||
} else if (strncmp(p, " const", 6) == 0 && | ||||
// must not mistake "const" as the beginning of | ||||
// a subequent identifier | ||||
!isalnum(p[6]) && p[6] != '_') { | ||||
p += 6; | ||||
} else { | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
static bool parseName(const char*& s, QString& name, VarTree::NameKind& kind) | static bool parseName(const char*& s, QString& name, VarTree::NameKind& kind) | |||
{ | { | |||
kind = VarTree::NKplain; | kind = VarTree::NKplain; | |||
const char* p = s; | const char* p = s; | |||
// examples of names: | // examples of names: | |||
// name | // name | |||
// <Object> | // <Object> | |||
// <string<a,b<c>,7> > | // <string<a,b<c>,7> > | |||
skipping to change at line 1205 | skipping to change at line 1246 | |||
skipName(p); | skipName(p); | |||
if (p == s) { | if (p == s) { | |||
TRACE(QString().sprintf("parse error: not a name %-20.20s", s)); | TRACE(QString().sprintf("parse error: not a name %-20.20s", s)); | |||
return false; | return false; | |||
} | } | |||
int len = p - s; | int len = p - s; | |||
if (len == 6 && strncmp(s, "static", 6) == 0) { | if (len == 6 && strncmp(s, "static", 6) == 0) { | |||
kind = VarTree::NKstatic; | kind = VarTree::NKstatic; | |||
// its a static variable, name comes now | // its a static variable, name comes now | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
s = p; | s = p; | |||
skipName(p); | skipName(p); | |||
if (p == s) { | if (p == s) { | |||
TRACE(QString().sprintf("parse error: not a name after static %-2 0.20s", s)); | TRACE(QString().sprintf("parse error: not a name after static %-2 0.20s", s)); | |||
return false; | return false; | |||
} | } | |||
len = p - s; | len = p - s; | |||
} | } | |||
name = QString::fromLatin1(s, len); | name = QString::fromLatin1(s, len); | |||
} | } | |||
skipping to change at line 1240 | skipping to change at line 1280 | |||
// {<data variable, no debug info>} | // {<data variable, no debug info>} | |||
// {<variable (not text or data), no debug info>} | // {<variable (not text or data), no debug info>} | |||
if (strncmp(s, "{<text variable, ", 17) == 0 || | if (strncmp(s, "{<text variable, ", 17) == 0 || | |||
strncmp(s, "{<data variable, ", 17) == 0 || | strncmp(s, "{<data variable, ", 17) == 0 || | |||
strncmp(s, "{<variable (not text or data), ", 31) == 0) | strncmp(s, "{<variable (not text or data), ", 31) == 0) | |||
{ | { | |||
const char* start = s; | const char* start = s; | |||
skipNested(s, '{', '}'); | skipNested(s, '{', '}'); | |||
variable->m_value = QString::fromLatin1(start, s-start); | variable->m_value = QString::fromLatin1(start, s-start); | |||
variable->m_value += ' '; // add only a single space | variable->m_value += ' '; // add only a single space | |||
while (isspace(*s)) | skipSpace(s); | |||
s++; | ||||
goto repeat; | goto repeat; | |||
} | } | |||
else | else | |||
{ | { | |||
s++; | s++; | |||
if (!parseNested(s, variable)) { | if (!parseNested(s, variable)) { | |||
return false; | return false; | |||
} | } | |||
// must be the closing brace | // must be the closing brace | |||
if (*s != '}') { | if (*s != '}') { | |||
TRACE("parse error: missing } of " + variable->m_name); | TRACE("parse error: missing } of " + variable->m_name); | |||
return false; | return false; | |||
} | } | |||
s++; | s++; | |||
// final white space | // final white space | |||
while (isspace(*s)) | skipSpace(s); | |||
s++; | ||||
} | } | |||
} | } | |||
// Sometimes we find a warning; it ends at the next LF | // Sometimes we find a warning; it ends at the next LF | |||
else if (strncmp(s, "warning: ", 9) == 0) { | else if (strncmp(s, "warning: ", 9) == 0) { | |||
const char* end = strchr(s, '\n'); | const char* end = strchr(s, '\n'); | |||
s = end ? end : s+strlen(s); | s = end ? end : s+strlen(s); | |||
// skip space at start of next line | // skip space at start of next line | |||
while (isspace(*s)) | skipSpace(s); | |||
s++; | ||||
goto repeat; | goto repeat; | |||
} else { | } else { | |||
// examples of leaf values (cannot be the empty string): | // examples of leaf values (cannot be the empty string): | |||
// 123 | // 123 | |||
// -123 | // -123 | |||
// 23.575e+37 | // 23.575e+37 | |||
// 0x32a45 | // 0x32a45 | |||
// @0x012ab4 | // @0x012ab4 | |||
// (DwContentType&) @0x8123456: {...} | // (DwContentType&) @0x8123456: {...} | |||
// 0x32a45 "text" | // 0x32a45 "text" | |||
// 10 '\n' | // 10 '\n' | |||
// <optimized out> | // <optimized out> | |||
// 0x823abc <Array<int> virtual table> | // 0x823abc <Array<int> virtual table> | |||
// 0x40240f <globarstr> "test" | // 0x40240f <globarstr> "test" | |||
// (void (*)()) 0x8048480 <f(E *, char)> | // (void (*)()) 0x8048480 <f(E *, char)> | |||
// (E *) 0xbffff450 | // (E *) 0xbffff450 | |||
// red | // red | |||
// &parseP (HTMLClueV *, char *) | // &parseP (HTMLClueV *, char *) | |||
// &virtual table offset 0, this adjustment 140737488346016 | ||||
// &virtual Dl::operator char const*() const | ||||
// Variable "x" is not available. | // Variable "x" is not available. | |||
// The value of variable 'x' is distributed... | // The value of variable 'x' is distributed... | |||
// -nan(0xfffff081defa0) | // -nan(0xfffff081defa0) | |||
// @0x100400f08: <error reading variable> | ||||
// (void (Templated<double>::*)(Templated<double> * const)) 0x400d74 <Mo | ||||
stDerived::PrintV()>, this adjustment -16 | ||||
const char*p = s; | const char*p = s; | |||
// check for type | // check for type | |||
QString type; | QString type; | |||
if (*p == '(') { | if (*p == '(') { | |||
skipNested(p, '(', ')'); | skipNested(p, '(', ')'); | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
variable->m_value = QString::fromLatin1(s, p - s); | variable->m_value = QString::fromLatin1(s, p - s); | |||
} | } | |||
bool reference = false; | bool reference = false; | |||
if (*p == '@') { | if (*p == '@') { | |||
// skip reference marker | // skip reference marker | |||
p++; | p++; | |||
reference = true; | reference = true; | |||
} | } | |||
const char* start = p; | const char* start = p; | |||
skipping to change at line 1342 | skipping to change at line 1382 | |||
if (*p == ':') { | if (*p == ':') { | |||
p++; | p++; | |||
} else { | } else { | |||
// Paranoia. (Can this happen, i.e. reference not followed by ':'?) | // Paranoia. (Can this happen, i.e. reference not followed by ':'?) | |||
reference = false; | reference = false; | |||
} | } | |||
} | } | |||
checkMultiPart = true; | checkMultiPart = true; | |||
} else if (isdigit(*p)) { | } else if (isdigit(*p)) { | |||
// parse decimal number, possibly a float | // parse decimal number, possibly a float | |||
while (isdigit(*p)) | skipDecimal(p); | |||
p++; | ||||
if (*p == '.') { /* TODO: obey i18n? */ | if (*p == '.') { /* TODO: obey i18n? */ | |||
// In long arrays an integer may be followed by '...'. | // In long arrays an integer may be followed by '...'. | |||
// We test for this situation and don't gobble the '...'. | // We test for this situation and don't gobble the '...'. | |||
if (p[1] != '.' || p[0] != '.') { | if (p[1] != '.' || p[0] != '.') { | |||
// fractional part | // fractional part | |||
p++; | p++; | |||
while (isdigit(*p)) | skipDecimal(p); | |||
p++; | ||||
} | } | |||
} | } | |||
if (*p == 'e' || *p == 'E') { | if (*p == 'e' || *p == 'E') { | |||
p++; | p++; | |||
// exponent | // exponent | |||
if (*p == '-' || *p == '+') | if (*p == '-' || *p == '+') | |||
p++; | p++; | |||
while (isdigit(*p)) | skipDecimal(p); | |||
p++; | ||||
} | } | |||
// for char variables there is the char, eg. 10 '\n' | // for char variables there is the char, eg. 10 '\n' | |||
checkMultiPart = true; | checkMultiPart = true; | |||
} else if (*p == '<') { | } else if (*p == '<') { | |||
// e.g. <optimized out> | // e.g. <optimized out> | |||
skipNestedAngles(p); | skipNestedAngles(p); | |||
} else if (*p == '"' || *p == '\'') { | } else if (*p == '"' || *p == '\'') { | |||
// character may have multipart: '\000' <repeats 11 times> | // character may have multipart: '\000' <repeats 11 times> | |||
checkMultiPart = *p == '\''; | checkMultiPart = *p == '\''; | |||
// found a string | // found a string | |||
skipString(p); | skipString(p); | |||
} else if (*p == 'L' && (p[1] == '"' || p[1] == '\'')) { | } else if (*p == 'L' && (p[1] == '"' || p[1] == '\'')) { | |||
// ditto for wchar_t strings | // ditto for wchar_t strings | |||
checkMultiPart = p[1] == '\''; | checkMultiPart = p[1] == '\''; | |||
skipString(p); | skipString(p); | |||
} else if (*p == '&') { | } else if (*p == '&') { | |||
// function pointer | ||||
p++; | p++; | |||
skipName(p); | if (strncmp(p, "virtual ", 8) == 0) { | |||
while (isspace(*p)) { | p += 8; | |||
p++; | if (strncmp(p, "table offset ", 13) == 0) { | |||
} | p += 13; | |||
if (*p == '(') { | skipDecimal(p); | |||
skipNested(p, '(', ')'); | checkMultiPart = true; | |||
} else { | ||||
skipFunctionName(p); | ||||
} | ||||
} else { | ||||
// function pointer | ||||
skipName(p); | ||||
skipSpace(p); | ||||
if (*p == '(') { | ||||
skipNested(p, '(', ')'); | ||||
} | ||||
} | } | |||
} else if (strncmp(p, "Variable \"", 10) == 0) { | } else if (strncmp(p, "Variable \"", 10) == 0) { | |||
// Variable "x" is not available. | // Variable "x" is not available. | |||
p += 10; // skip to " | p += 10; // skip to " | |||
skipName(p); | skipName(p); | |||
if (strncmp(p, "\" is not available.", 19) == 0) { | if (strncmp(p, "\" is not available.", 19) == 0) { | |||
p += 19; | p += 19; | |||
} | } | |||
} else if (strncmp(p, "The value of variable '", 23) == 0) { | } else if (strncmp(p, "The value of variable '", 23) == 0) { | |||
p += 23; | p += 23; | |||
skipping to change at line 1424 | skipping to change at line 1470 | |||
} | } | |||
} | } | |||
variable->m_value += QString::fromLatin1(start, p - start); | variable->m_value += QString::fromLatin1(start, p - start); | |||
// remove line breaks from the value; this is ok since | // remove line breaks from the value; this is ok since | |||
// string values never contain a literal line break | // string values never contain a literal line break | |||
variable->m_value.replace('\n', ' '); | variable->m_value.replace('\n', ' '); | |||
while (checkMultiPart) { | while (checkMultiPart) { | |||
// white space | // white space | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
// may be followed by a string or <...> | // may be followed by a string or <...> | |||
// if this was a pointer with a string, | // if this was a pointer with a string, | |||
// reset that pointer flag since we have now a value | // reset that pointer flag since we have now a value | |||
start = p; | start = p; | |||
checkMultiPart = false; | checkMultiPart = false; | |||
if (*p == '"' || *p == '\'') { | if (*p == '"' || *p == '\'') { | |||
skipString(p); | skipString(p); | |||
variable->m_varKind = VarTree::VKsimple; | variable->m_varKind = VarTree::VKsimple; | |||
} else if (*p == 'L' && (p[1] == '"' || p[1] == '\'')) { | } else if (*p == 'L' && (p[1] == '"' || p[1] == '\'')) { | |||
skipString(p); // wchar_t string | skipString(p); // wchar_t string | |||
variable->m_varKind = VarTree::VKsimple; | variable->m_varKind = VarTree::VKsimple; | |||
} else if (*p == '<') { | } else if (*p == '<') { | |||
// if this value is part of an array, it might be followed | // if this value is part of an array, it might be followed | |||
// by <repeats 15 times>, which we don't skip here | // by <repeats 15 times>, which we don't skip here | |||
if (strncmp(p, "<repeats ", 9) != 0) { | if (strncmp(p, "<repeats ", 9) == 0) | |||
; | ||||
// sometimes, a reference is followed by an error message: | ||||
// @0x100400f08: <error reading variable> | ||||
// in this case, we do not skip the text here, but leave it | ||||
// for the subsequent parsing pass induced by the reference | ||||
else if (reference && strncmp(p, "<error reading", 14) == 0) | ||||
; | ||||
else { | ||||
skipNestedAngles(p); | skipNestedAngles(p); | |||
checkMultiPart = true; | checkMultiPart = true; | |||
} | } | |||
} else if (strncmp(p, ", this adjustment ", 18) == 0) { | ||||
// pointers-to-member are sometimes followed by | ||||
// a "this adjustment" hint | ||||
p += 18; | ||||
if (*p == '-') | ||||
p++; | ||||
skipDecimal(p); | ||||
// we know that this is not a dereferencable pointer | ||||
variable->m_varKind = VarTree::VKsimple; | ||||
++start; // skip ',', will be picked up below | ||||
} | } | |||
if (p != start) { | if (p != start) { | |||
// there is always a blank before the string, | // there is always a blank before the string, | |||
// which we will include in the final string value | // which we will include in the final string value | |||
variable->m_value += QString::fromLatin1(start-1, (p - start)+1); | variable->m_value += QString::fromLatin1(start-1, (p - start)+1); | |||
} | } | |||
} | } | |||
if (variable->m_value.length() == 0) { | if (variable->m_value.length() == 0) { | |||
TRACE("parse error: no value for " + variable->m_name); | TRACE("parse error: no value for " + variable->m_name); | |||
return false; | return false; | |||
} | } | |||
// final white space | // final white space | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
s = p; | s = p; | |||
/* | /* | |||
* If this was a reference, the value follows. It might even be a | * If this was a reference, the value follows. It might even be a | |||
* composite variable! | * composite variable! | |||
*/ | */ | |||
if (reference) { | if (reference) { | |||
goto repeat; | goto repeat; | |||
} | } | |||
} | } | |||
return true; | return true; | |||
} | } | |||
static bool parseNested(const char*& s, ExprValue* variable) | static bool parseNested(const char*& s, ExprValue* variable) | |||
{ | { | |||
// could be a structure or an array | // could be a structure or an array | |||
while (isspace(*s)) | skipSpace(s); | |||
s++; | ||||
const char* p = s; | const char* p = s; | |||
bool isStruct = false; | bool isStruct = false; | |||
/* | /* | |||
* If there is a name followed by an = or an < -- which starts a type | * If there is a name followed by an = or an < -- which starts a type | |||
* name -- or "static", it is a structure | * name -- or "static", it is a structure | |||
*/ | */ | |||
if (*p == '<' || *p == '}') { | if (*p == '<' || *p == '}') { | |||
isStruct = true; | isStruct = true; | |||
} else if (strncmp(p, "static ", 7) == 0) { | } else if (strncmp(p, "static ", 7) == 0) { | |||
isStruct = true; | isStruct = true; | |||
} else if (isalpha(*p) || *p == '_' || *p == '$') { | } else if (isalpha(*p) || *p == '_' || *p == '$') { | |||
// look ahead for a comma after the name | // look ahead for a comma after the name | |||
skipName(p); | skipName(p); | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
if (*p == '=') { | if (*p == '=') { | |||
isStruct = true; | isStruct = true; | |||
} | } | |||
p = s; /* rescan the name */ | p = s; /* rescan the name */ | |||
} | } | |||
if (isStruct) { | if (isStruct) { | |||
if (!parseVarSeq(p, variable)) { | if (!parseVarSeq(p, variable)) { | |||
return false; | return false; | |||
} | } | |||
variable->m_varKind = VarTree::VKstruct; | variable->m_varKind = VarTree::VKstruct; | |||
skipping to change at line 1537 | skipping to change at line 1597 | |||
break; | break; | |||
} | } | |||
var = parseVar(s); | var = parseVar(s); | |||
if (var == 0) | if (var == 0) | |||
break; /* syntax error */ | break; /* syntax error */ | |||
variable->appendChild(var); | variable->appendChild(var); | |||
if (*s != ',') | if (*s != ',') | |||
break; | break; | |||
// skip the comma and whitespace | // skip the comma and whitespace | |||
s++; | s++; | |||
while (isspace(*s)) | skipSpace(s); | |||
s++; | ||||
} | } | |||
return var != 0; | return var != 0; | |||
} | } | |||
static bool parseValueSeq(const char*& s, ExprValue* variable) | static bool parseValueSeq(const char*& s, ExprValue* variable) | |||
{ | { | |||
// parse a comma-separated sequence of variables | // parse a comma-separated sequence of variables | |||
int index = 0; | int index = 0; | |||
bool good; | bool good; | |||
for (;;) { | for (;;) { | |||
skipping to change at line 1575 | skipping to change at line 1634 | |||
return false; | return false; | |||
} | } | |||
TRACE(QString().sprintf("found <repeats %d times> in array", l)); | TRACE(QString().sprintf("found <repeats %d times> in array", l)); | |||
// replace name and advance index | // replace name and advance index | |||
name.sprintf("[%d .. %d]", index, index+l-1); | name.sprintf("[%d .. %d]", index, index+l-1); | |||
var->m_name = name; | var->m_name = name; | |||
index += l; | index += l; | |||
// skip " times>" and space | // skip " times>" and space | |||
s = end+7; | s = end+7; | |||
// possible final space | // possible final space | |||
while (isspace(*s)) | skipSpace(s); | |||
s++; | ||||
} else { | } else { | |||
index++; | index++; | |||
} | } | |||
variable->appendChild(var); | variable->appendChild(var); | |||
// long arrays may be terminated by '...' | // long arrays may be terminated by '...' | |||
if (strncmp(s, "...", 3) == 0) { | if (strncmp(s, "...", 3) == 0) { | |||
s += 3; | s += 3; | |||
ExprValue* var = new ExprValue("...", VarTree::NKplain); | ExprValue* var = new ExprValue("...", VarTree::NKplain); | |||
var->m_value = i18n("<additional entries of the array suppressed>"); | var->m_value = i18n("<additional entries of the array suppressed>"); | |||
variable->appendChild(var); | variable->appendChild(var); | |||
break; | break; | |||
} | } | |||
if (*s != ',') { | if (*s != ',') { | |||
break; | break; | |||
} | } | |||
// skip the comma and whitespace | // skip the comma and whitespace | |||
s++; | s++; | |||
while (isspace(*s)) | skipSpace(s); | |||
s++; | ||||
// sometimes there is a closing brace after a comma | // sometimes there is a closing brace after a comma | |||
// if (*s == '}') | // if (*s == '}') | |||
// break; | // break; | |||
} | } | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Parses a stack frame. | * Parses a stack frame. | |||
*/ | */ | |||
skipping to change at line 1689 | skipping to change at line 1746 | |||
/* | /* | |||
* Skip parameters. But notice that for complicated conversion | * Skip parameters. But notice that for complicated conversion | |||
* functions (eg. "operator int(**)()()", ie. convert to pointer to | * functions (eg. "operator int(**)()()", ie. convert to pointer to | |||
* pointer to function) as well as operator()(...) we have to skip | * pointer to function) as well as operator()(...) we have to skip | |||
* additional pairs of parentheses. Furthermore, recent gdbs write the | * additional pairs of parentheses. Furthermore, recent gdbs write the | |||
* demangled name followed by the arguments in a pair of parentheses, | * demangled name followed by the arguments in a pair of parentheses, | |||
* where the demangled name can end in "const". | * where the demangled name can end in "const". | |||
*/ | */ | |||
do { | do { | |||
skipNestedWithString(p, '(', ')'); | skipNestedWithString(p, '(', ')'); | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
// skip "const" | // skip "const" | |||
if (strncmp(p, "const", 5) == 0) { | if (strncmp(p, "const", 5) == 0) { | |||
p += 5; | p += 5; | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
} | } | |||
} while (*p == '('); | } while (*p == '('); | |||
// check for file position | // check for file position | |||
if (strncmp(p, "at ", 3) == 0) { | if (strncmp(p, "at ", 3) == 0) { | |||
p += 3; | p += 3; | |||
const char* fileStart = p; | const char* fileStart = p; | |||
// go for the end of the line | // go for the end of the line | |||
while (*p != '\0' && *p != '\n') | while (*p != '\0' && *p != '\n') | |||
p++; | p++; | |||
skipping to change at line 1789 | skipping to change at line 1844 | |||
s++; /* skip the hash mark */ | s++; /* skip the hash mark */ | |||
} else if (strncmp(s, "Breakpoint ", 11) == 0) { | } else if (strncmp(s, "Breakpoint ", 11) == 0) { | |||
if (!isdigit(s[11])) | if (!isdigit(s[11])) | |||
return false; | return false; | |||
s += 11; /* skip "Breakpoint" */ | s += 11; /* skip "Breakpoint" */ | |||
} else | } else | |||
return false; | return false; | |||
// frame number | // frame number | |||
frameNo = atoi(s); | frameNo = atoi(s); | |||
while (isdigit(*s)) | skipDecimal(s); | |||
s++; | ||||
// space and comma | // space and comma | |||
while (isspace(*s) || *s == ',') | while (isspace(*s) || *s == ',') | |||
s++; | s++; | |||
parseFrameInfo(s, func, file, lineNo, address); | parseFrameInfo(s, func, file, lineNo, address); | |||
return true; | return true; | |||
} | } | |||
void GdbDriver::parseBackTrace(const char* output, std::list<StackFrame>& stack) | void GdbDriver::parseBackTrace(const char* output, std::list<StackFrame>& stack) | |||
{ | { | |||
QString func, file; | QString func, file; | |||
skipping to change at line 1848 | skipping to change at line 1902 | |||
bp.id = strtol(p, &dummy, 10); /* don't care about overflows */ | bp.id = strtol(p, &dummy, 10); /* don't care about overflows */ | |||
p = dummy; | p = dummy; | |||
// check for continued <MULTIPLE> breakpoint | // check for continued <MULTIPLE> breakpoint | |||
if (*p == '.' && isdigit(p[1])) | if (*p == '.' && isdigit(p[1])) | |||
{ | { | |||
// continuation: skip type and disposition | // continuation: skip type and disposition | |||
} | } | |||
else | else | |||
{ | { | |||
// get Type | // get Type | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
if (strncmp(p, "breakpoint", 10) == 0) { | if (strncmp(p, "breakpoint", 10) == 0) { | |||
p += 10; | p += 10; | |||
} else if (strncmp(p, "hw watchpoint", 13) == 0) { | } else if (strncmp(p, "hw watchpoint", 13) == 0) { | |||
bp.type = Breakpoint::watchpoint; | bp.type = Breakpoint::watchpoint; | |||
p += 13; | p += 13; | |||
} else if (strncmp(p, "watchpoint", 10) == 0) { | } else if (strncmp(p, "watchpoint", 10) == 0) { | |||
bp.type = Breakpoint::watchpoint; | bp.type = Breakpoint::watchpoint; | |||
p += 10; | p += 10; | |||
} | } | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
if (*p == '\0') | if (*p == '\0') | |||
break; | break; | |||
// get Disp | // get Disp | |||
bp.temporary = *p++ == 'd'; | bp.temporary = *p++ == 'd'; | |||
} | } | |||
while (*p != '\0' && !isspace(*p)) /* "keep" or "del" */ | while (*p != '\0' && !isspace(*p)) /* "keep" or "del" */ | |||
p++; | p++; | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
if (*p == '\0') | if (*p == '\0') | |||
break; | break; | |||
// get Enb | // get Enb | |||
bp.enabled = *p++ == 'y'; | bp.enabled = *p++ == 'y'; | |||
while (*p != '\0' && !isspace(*p)) /* "y" or "n" */ | while (*p != '\0' && !isspace(*p)) /* "y" or "n" */ | |||
p++; | p++; | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
if (*p == '\0') | if (*p == '\0') | |||
break; | break; | |||
// the address, if present | // the address, if present | |||
if (bp.type == Breakpoint::breakpoint && | if (bp.type == Breakpoint::breakpoint && | |||
strncmp(p, "0x", 2) == 0) | strncmp(p, "0x", 2) == 0) | |||
{ | { | |||
const char* start = p; | const char* start = p; | |||
while (*p != '\0' && !isspace(*p)) | while (*p != '\0' && !isspace(*p)) | |||
p++; | p++; | |||
bp.address = QString::fromLatin1(start, p-start); | bp.address = QString::fromLatin1(start, p-start); | |||
skipping to change at line 1908 | skipping to change at line 1958 | |||
} else { | } else { | |||
// location of a <MULTIPLE> filled in from subsequent breakpoints | // location of a <MULTIPLE> filled in from subsequent breakpoints | |||
if (strncmp(p, "<MULTIPLE>", 10) != 0) | if (strncmp(p, "<MULTIPLE>", 10) != 0) | |||
bp.location = QString::fromLatin1(p, end-p).trimmed(); | bp.location = QString::fromLatin1(p, end-p).trimmed(); | |||
p = end+1; /* skip over \n */ | p = end+1; /* skip over \n */ | |||
} | } | |||
// may be continued in next line | // may be continued in next line | |||
while (isspace(*p)) { /* p points to beginning of line */ | while (isspace(*p)) { /* p points to beginning of line */ | |||
// skip white space at beginning of line | // skip white space at beginning of line | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
// seek end of line | // seek end of line | |||
end = strchr(p, '\n'); | end = strchr(p, '\n'); | |||
if (end == 0) | if (end == 0) | |||
end = p+strlen(p); | end = p+strlen(p); | |||
if (strncmp(p, "breakpoint already hit", 22) == 0) { | if (strncmp(p, "breakpoint already hit", 22) == 0) { | |||
// extract the hit count | // extract the hit count | |||
p += 22; | p += 22; | |||
bp.hitCount = strtol(p, &dummy, 10); | bp.hitCount = strtol(p, &dummy, 10); | |||
skipping to change at line 1973 | skipping to change at line 2022 | |||
// no threads | // no threads | |||
return threads; | return threads; | |||
} | } | |||
bool newFormat = false; | bool newFormat = false; | |||
const char* p = output; | const char* p = output; | |||
while (*p != '\0') { | while (*p != '\0') { | |||
ThreadInfo thr; | ThreadInfo thr; | |||
// seach look for thread id, watching out for the focus indicator | // seach look for thread id, watching out for the focus indicator | |||
thr.hasFocus = false; | thr.hasFocus = false; | |||
while (isspace(*p)) /* may be \n from prev line: see "No stac | skipSpace(p); /* may be \n from prev line: see "No stac | |||
k" below */ | k" below */ | |||
p++; | ||||
// recent GDBs write a header line; skip it | // recent GDBs write a header line; skip it | |||
if (threads.empty() && strncmp(p, "Id Target", 11) == 0) { | if (threads.empty() && strncmp(p, "Id Target", 11) == 0) { | |||
p = strchr(p, '\n'); | p = strchr(p, '\n'); | |||
if (p == NULL) | if (p == NULL) | |||
break; | break; | |||
newFormat = true; | newFormat = true; | |||
continue; // next line please, '\n' is skipped above | continue; // next line please, '\n' is skipped above | |||
} | } | |||
skipping to change at line 2000 | skipping to change at line 2048 | |||
const char* end; | const char* end; | |||
char *temp_end = NULL; /* we need a non-const 'end' for strtol to use...* / | char *temp_end = NULL; /* we need a non-const 'end' for strtol to use...* / | |||
thr.id = strtol(p, &temp_end, 10); | thr.id = strtol(p, &temp_end, 10); | |||
end = temp_end; | end = temp_end; | |||
if (p == end) { | if (p == end) { | |||
// syntax error: no number found; bail out | // syntax error: no number found; bail out | |||
return threads; | return threads; | |||
} | } | |||
p = end; | p = end; | |||
// skip space | skipSpace(p); | |||
while (isspace(*p)) | ||||
p++; | ||||
/* | /* | |||
* Now follows the thread's SYSTAG. | * Now follows the thread's SYSTAG. | |||
*/ | */ | |||
if (!newFormat) { | if (!newFormat) { | |||
// In the old format, it is terminated by two blanks. | // In the old format, it is terminated by two blanks. | |||
end = strstr(p, " "); | end = strstr(p, " "); | |||
if (end == 0) { | if (end == 0) { | |||
// syntax error; bail out | // syntax error; bail out | |||
return threads; | return threads; | |||
skipping to change at line 2044 | skipping to change at line 2090 | |||
} else if (*end == '(') { | } else if (*end == '(') { | |||
skipNested(end, '(', ')'); | skipNested(end, '(', ')'); | |||
n = 2; | n = 2; | |||
} else if (n < 2) { | } else if (n < 2) { | |||
while (*end && !isspace(*end)) | while (*end && !isspace(*end)) | |||
++end; | ++end; | |||
++n; | ++n; | |||
} else { | } else { | |||
break; | break; | |||
} | } | |||
while (isspace(*end)) | skipSpace(end); | |||
++end; | ||||
} | } | |||
} | } | |||
thr.threadName = QString::fromLatin1(p, end-p).trimmed(); | thr.threadName = QString::fromLatin1(p, end-p).trimmed(); | |||
p = end; | p = end; | |||
/* | /* | |||
* Now follows a standard stack frame. Sometimes, however, gdb | * Now follows a standard stack frame. Sometimes, however, gdb | |||
* catches a thread at an instant where it doesn't have a stack. | * catches a thread at an instant where it doesn't have a stack. | |||
*/ | */ | |||
if (strncmp(p, "[No stack.]", 11) != 0) { | if (strncmp(p, "[No stack.]", 11) != 0) { | |||
skipping to change at line 2129 | skipping to change at line 2174 | |||
/* | /* | |||
* Mostly, GDB responds with this syntax: | * Mostly, GDB responds with this syntax: | |||
* | * | |||
* Breakpoint 1 at 0x400b94: file multibrkpt.cpp, line 9. (2 locations) | * Breakpoint 1 at 0x400b94: file multibrkpt.cpp, line 9. (2 locations) | |||
* | * | |||
* but sometimes it uses this syntax: | * but sometimes it uses this syntax: | |||
* | * | |||
* Breakpoint 4 at 0x804f158: lotto739.cpp:95. (3 locations) | * Breakpoint 4 at 0x804f158: lotto739.cpp:95. (3 locations) | |||
*/ | */ | |||
char* fileEnd, *numStart = 0; | const char* fileEnd, *numStart = 0; | |||
char* fileStart = strstr(p, "file "); | const char* fileStart = strstr(p, "file "); | |||
if (fileStart != 0) | if (fileStart != 0) | |||
{ | { | |||
fileStart += 5; | fileStart += 5; | |||
fileEnd = strstr(fileStart, ", line "); | fileEnd = strstr(fileStart, ", line "); | |||
if (fileEnd != 0) | if (fileEnd != 0) | |||
numStart = fileEnd + 7; | numStart = fileEnd + 7; | |||
} | } | |||
if (numStart == 0 && p[0] == ':' && p[1] == ' ') | if (numStart == 0 && p[0] == ':' && p[1] == ' ') | |||
{ | { | |||
fileStart = p+2; | fileStart = p+2; | |||
while (isspace(*fileStart)) | skipSpace(fileStart); | |||
++fileStart; | ||||
fileEnd = strchr(fileStart, ':'); | fileEnd = strchr(fileStart, ':'); | |||
if (fileEnd != 0) | if (fileEnd != 0) | |||
numStart = fileEnd + 1; | numStart = fileEnd + 1; | |||
} | } | |||
if (numStart == 0) | if (numStart == 0) | |||
return !address.isEmpty(); /* parse error only if there's no address */ | return !address.isEmpty(); /* parse error only if there's no address */ | |||
QString fileName = QString::fromLatin1(fileStart, fileEnd-fileStart); | QString fileName = QString::fromLatin1(fileStart, fileEnd-fileStart); | |||
int line = strtoul(numStart, &p, 10); | int line = strtoul(numStart, &p, 10); | |||
if (numStart == p) | if (numStart == p) | |||
skipping to change at line 2187 | skipping to change at line 2231 | |||
void GdbDriver::parseLocals(const char* output, std::list<ExprValue*>& newVars) | void GdbDriver::parseLocals(const char* output, std::list<ExprValue*>& newVars) | |||
{ | { | |||
// check for possible error conditions | // check for possible error conditions | |||
if (strncmp(output, "No symbol table", 15) == 0) | if (strncmp(output, "No symbol table", 15) == 0) | |||
{ | { | |||
return; | return; | |||
} | } | |||
while (*output != '\0') { | while (*output != '\0') { | |||
while (isspace(*output)) | skipSpace(output); | |||
output++; | ||||
if (*output == '\0') | if (*output == '\0') | |||
break; | break; | |||
// skip occurrences of "No locals" and "No args" | // skip occurrences of "No locals" and "No args" | |||
if (strncmp(output, "No locals", 9) == 0 || | if (strncmp(output, "No locals", 9) == 0 || | |||
strncmp(output, "No arguments", 12) == 0) | strncmp(output, "No arguments", 12) == 0) | |||
{ | { | |||
output = strchr(output, '\n'); | output = strchr(output, '\n'); | |||
if (output == 0) { | if (output == 0) { | |||
break; | break; | |||
} | } | |||
skipping to change at line 2326 | skipping to change at line 2369 | |||
// set message | // set message | |||
const char* endOfMessage = strchr(start, '\n'); | const char* endOfMessage = strchr(start, '\n'); | |||
if (endOfMessage == 0) | if (endOfMessage == 0) | |||
endOfMessage = start + strlen(start); | endOfMessage = start + strlen(start); | |||
message = QString::fromLatin1(start, endOfMessage-start); | message = QString::fromLatin1(start, endOfMessage-start); | |||
} else if (strncmp(start, "[Inferior ", 10) == 0) { | } else if (strncmp(start, "[Inferior ", 10) == 0) { | |||
const char* p = start + 10; | const char* p = start + 10; | |||
// skip number and space | // skip number and space | |||
while (*p && !isspace(*p)) | while (*p && !isspace(*p)) | |||
++p; | ++p; | |||
while (isspace(*p)) | skipSpace(p); | |||
++p; | ||||
if (*p == '(') { | if (*p == '(') { | |||
skipNested(p, '(', ')'); | skipNested(p, '(', ')'); | |||
if (strncmp(p, " exited ", 8) == 0) { | if (strncmp(p, " exited ", 8) == 0) { | |||
flags &= ~SFprogramActive; | flags &= ~SFprogramActive; | |||
// set message | // set message | |||
const char* end = strchr(p, '\n'); | const char* end = strchr(p, '\n'); | |||
if (end == 0) | if (end == 0) | |||
end = p + strlen(p); | end = p + strlen(p); | |||
// strip [] from the message | // strip [] from the message | |||
skipping to change at line 2387 | skipping to change at line 2429 | |||
output++; /* skip '\n' */ | output++; /* skip '\n' */ | |||
QString shlibName; | QString shlibName; | |||
while (*output != '\0') { | while (*output != '\0') { | |||
// format of a line is | // format of a line is | |||
// 0x404c5000 0x40580d90 Yes /lib/libc.so.5 | // 0x404c5000 0x40580d90 Yes /lib/libc.so.5 | |||
// 3 blocks of non-space followed by space | // 3 blocks of non-space followed by space | |||
for (int i = 0; *output != '\0' && i < 3; i++) { | for (int i = 0; *output != '\0' && i < 3; i++) { | |||
while (*output != '\0' && !isspace(*output)) { /* non-space */ | while (*output != '\0' && !isspace(*output)) { /* non-space */ | |||
output++; | output++; | |||
} | } | |||
while (isspace(*output)) { /* space */ | skipSpace(output); /* space */ | |||
output++; | ||||
} | ||||
} | } | |||
if (*output == '\0') | if (*output == '\0') | |||
return shlibs; | return shlibs; | |||
const char* start = output; | const char* start = output; | |||
output = strchr(output, '\n'); | output = strchr(output, '\n'); | |||
if (output == 0) | if (output == 0) | |||
output = start + strlen(start); | output = start + strlen(start); | |||
shlibName = QString::fromLatin1(start, output-start); | shlibName = QString::fromLatin1(start, output-start); | |||
if (*output != '\0') | if (*output != '\0') | |||
output++; | output++; | |||
skipping to change at line 2438 | skipping to change at line 2478 | |||
std::list<RegisterInfo> regs; | std::list<RegisterInfo> regs; | |||
if (strncmp(output, "The program has no registers now", 32) == 0) { | if (strncmp(output, "The program has no registers now", 32) == 0) { | |||
return regs; | return regs; | |||
} | } | |||
// parse register values | // parse register values | |||
while (*output != '\0') | while (*output != '\0') | |||
{ | { | |||
RegisterInfo reg; | RegisterInfo reg; | |||
// skip space at the start of the line | // skip space at the start of the line | |||
while (isspace(*output)) | skipSpace(output); | |||
output++; | ||||
// register name | // register name | |||
const char* start = output; | const char* start = output; | |||
while (*output != '\0' && !isspace(*output)) | while (*output != '\0' && !isspace(*output)) | |||
output++; | output++; | |||
if (*output == '\0') | if (*output == '\0') | |||
break; | break; | |||
reg.regName = QString::fromLatin1(start, output-start); | reg.regName = QString::fromLatin1(start, output-start); | |||
// skip space | skipSpace(output); | |||
while (isspace(*output)) | ||||
output++; | ||||
QString value; | QString value; | |||
/* | /* | |||
* If we find a brace now, this is a vector register. We look for | * If we find a brace now, this is a vector register. We look for | |||
* the closing brace and treat the result as cooked value. | * the closing brace and treat the result as cooked value. | |||
*/ | */ | |||
if (*output == '{') | if (*output == '{') | |||
{ | { | |||
start = output; | start = output; | |||
skipping to change at line 2703 | skipping to change at line 2740 | |||
// the address | // the address | |||
while (*p != 0) { | while (*p != 0) { | |||
MemoryDump md; | MemoryDump md; | |||
const char* start = p; | const char* start = p; | |||
while (*p != '\0' && *p != ':' && !isspace(*p)) | while (*p != '\0' && *p != ':' && !isspace(*p)) | |||
p++; | p++; | |||
md.address = QString::fromLatin1(start, p-start); | md.address = QString::fromLatin1(start, p-start); | |||
if (*p != ':') { | if (*p != ':') { | |||
// parse function offset | // parse function offset | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
start = p; | start = p; | |||
while (*p != '\0' && !(*p == ':' && isspace(p[1]))) | while (*p != '\0' && !(*p == ':' && isspace(p[1]))) | |||
p++; | p++; | |||
md.address.fnoffs = QString::fromLatin1(start, p-start); | md.address.fnoffs = QString::fromLatin1(start, p-start); | |||
} | } | |||
if (*p == ':') | if (*p == ':') | |||
p++; | p++; | |||
// skip space; this may skip a new-line char! | // skip space; this may skip a new-line char! | |||
while (isspace(*p)) | skipSpace(p); | |||
p++; | ||||
// everything to the end of the line is the memory dump | // everything to the end of the line is the memory dump | |||
const char* end = strchr(p, '\n'); | const char* end = strchr(p, '\n'); | |||
if (end != 0) { | if (end != 0) { | |||
md.dump = QString::fromLatin1(p, end-p); | md.dump = QString::fromLatin1(p, end-p); | |||
p = end+1; | p = end+1; | |||
} else { | } else { | |||
md.dump = QString::fromLatin1(p, strlen(p)); | md.dump = QString::fromLatin1(p, strlen(p)); | |||
p += strlen(p); | p += strlen(p); | |||
} | } | |||
memdump.push_back(md); | memdump.push_back(md); | |||
skipping to change at line 2740 | skipping to change at line 2775 | |||
QString GdbDriver::editableValue(VarTree* value) | QString GdbDriver::editableValue(VarTree* value) | |||
{ | { | |||
QByteArray ba = value->value().toLatin1(); | QByteArray ba = value->value().toLatin1(); | |||
const char* s = ba.constData(); | const char* s = ba.constData(); | |||
// if the variable is a pointer value that contains a cast, | // if the variable is a pointer value that contains a cast, | |||
// remove the cast | // remove the cast | |||
if (*s == '(') { | if (*s == '(') { | |||
skipNested(s, '(', ')'); | skipNested(s, '(', ')'); | |||
// skip space | // skip space | |||
while (isspace(*s)) | skipSpace(s); | |||
++s; | ||||
} | } | |||
repeat: | repeat: | |||
const char* start = s; | const char* start = s; | |||
if (strncmp(s, "0x", 2) == 0) | if (strncmp(s, "0x", 2) == 0) | |||
{ | { | |||
s += 2; | s += 2; | |||
while (isxdigit(*s)) | while (isxdigit(*s)) | |||
++s; | ++s; | |||
skipping to change at line 2765 | skipping to change at line 2799 | |||
* referenced value. Otherwise, edit the pointer. | * referenced value. Otherwise, edit the pointer. | |||
*/ | */ | |||
if (*s == ':') { | if (*s == ':') { | |||
// a reference | // a reference | |||
++s; | ++s; | |||
goto repeat; | goto repeat; | |||
} | } | |||
// a pointer | // a pointer | |||
// if it's a pointer to a string, remove the string | // if it's a pointer to a string, remove the string | |||
const char* end = s; | const char* end = s; | |||
while (isspace(*s)) | skipSpace(s); | |||
++s; | ||||
if (*s == '"') { | if (*s == '"') { | |||
// a string | // a string | |||
return QString::fromLatin1(start, end-start); | return QString::fromLatin1(start, end-start); | |||
} else { | } else { | |||
// other pointer | // other pointer | |||
return QString::fromLatin1(start, strlen(start)); | return QString::fromLatin1(start, strlen(start)); | |||
} | } | |||
} | } | |||
// else leave it unchanged (or stripped of the reference preamble) | // else leave it unchanged (or stripped of the reference preamble) | |||
End of changes. 55 change blocks. | ||||
108 lines changed or deleted | 142 lines changed or added |