00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
#include "gdbparser.h"
00017
#include "variablewidget.h"
00018
00019
#include <qregexp.h>
00020
00021
#include <ctype.h>
00022
#include <stdlib.h>
00023
00024
namespace GDBDebugger
00025 {
00026
00027
00028
00029
00030
00031 GDBParser *GDBParser::GDBParser_ = 0;
00032
00033 GDBParser *GDBParser::getGDBParser()
00034 {
00035
if (!
GDBParser_)
00036
GDBParser_ =
new GDBParser();
00037
00038
return GDBParser_;
00039 }
00040
00041
00042
00043 void GDBParser::destroy()
00044 {
00045
delete GDBParser_;
00046
GDBParser_ = 0;
00047 }
00048
00049
00050
00051 GDBParser::GDBParser()
00052 {
00053 }
00054
00055
00056
00057 GDBParser::~GDBParser()
00058 {
00059 }
00060
00061
00062
00063 void GDBParser::parseData(
TrimmableItem *parent,
char *buf,
00064
bool requested,
bool params)
00065 {
00066
static const char *unknown =
"?";
00067
00068 Q_ASSERT(parent);
00069
if (!buf)
00070
return;
00071
00072
if (parent->
getDataType() ==
typeArray) {
00073
parseArray(parent, buf);
00074
return;
00075 }
00076
00077
if (requested && !*buf)
00078 buf = (
char*)unknown;
00079
00080
while (*buf) {
00081
QString varName =
"";
00082
DataType dataType =
determineType(buf);
00083
00084
if (dataType ==
typeName) {
00085 varName =
getName(&buf);
00086 dataType = determineType(buf);
00087 }
00088
00089
QCString value =
getValue(&buf, requested);
00090
setItem(parent, varName, dataType, value, requested, params);
00091 }
00092 }
00093
00094
00095
00096 void GDBParser::parseArray(
TrimmableItem *parent,
char *buf)
00097 {
00098
QString elementRoot = parent->
getName() +
"[%1]";
00099
int idx = 0;
00100
while (*buf) {
00101 buf =
skipNextTokenStart(buf);
00102
if (!*buf)
00103
return;
00104
00105
DataType dataType =
determineType(buf);
00106
QCString value =
getValue(&buf,
false);
00107
QString varName = elementRoot.arg(idx);
00108
setItem(parent, varName, dataType, value,
false,
false);
00109
00110
int pos = value.find(
" <repeats", 0);
00111
if (pos > -1) {
00112
if (
int i = atoi(value.data()+pos+10))
00113 idx += (i-1);
00114 }
00115
00116 idx++;
00117 }
00118 }
00119
00120
00121
00122 QString GDBParser::getName(
char **buf)
00123 {
00124
char *start =
skipNextTokenStart(*buf);
00125
if (*start) {
00126 *buf =
skipTokenValue(start);
00127
return QCString(start, *buf - start + 1);
00128 }
else
00129 *buf = start;
00130
00131
return QString();
00132 }
00133
00134
00135
00136 QCString GDBParser::getValue(
char **buf,
bool requested)
00137 {
00138
char *start =
skipNextTokenStart(*buf);
00139 *buf =
skipTokenValue(start);
00140
00141
if (*start ==
'{')
00142
return QCString(start+1, *buf - start -1);
00143
00144
QCString value(start, *buf - start + 1);
00145
00146
00147
00148
if (requested)
00149
return value.replace(
QRegExp(
"\\\\000|\\\\0"),
"" );
00150
00151
return value;
00152 }
00153
00154
00155
00156 TrimmableItem *GDBParser::getItem(
TrimmableItem *parent, DataType dataType,
00157
const QString &varName,
bool requested)
00158 {
00159
if (requested)
00160
return parent;
00161
00162
if (varName.isEmpty()) {
00163
if (parent->
getDataType() ==
typeReference)
00164
return parent;
00165
00166
return 0;
00167 }
00168
00169
return parent->
findMatch(varName, dataType);
00170 }
00171
00172
00173
00174 void GDBParser::setItem(
TrimmableItem *parent,
const QString &varName,
00175 DataType dataType,
const QCString &value,
00176
bool requested,
bool)
00177 {
00178
TrimmableItem *item =
getItem(parent, dataType, varName, requested);
00179
if (!item) {
00180
if (varName.isEmpty())
00181
return;
00182
00183 item =
new VarItem(parent, varName, dataType);
00184 }
00185
00186
switch (dataType) {
00187
case typePointer:
00188 item->setText(
ValueCol, value);
00189 item->setExpandable(varName !=
"_vptr.");
00190
break;
00191
00192
case typeStruct:
00193
case typeArray:
00194 item->
setCache(value);
00195
break;
00196
00197
case typeReference:
00198 {
00199
int pos;
00200
if ((pos = value.find(
':', 0)) != -1) {
00201
QCString rhs((value.mid(pos+2, value.length()).data()));
00202
00203
DataType dataType =
determineType( rhs.data() );
00204
if ( dataType ==
typeUnknown )
00205 {
00206 item->setText(
ValueCol, value.left(pos));
00207 item->setExpandable(
false );
00208
break;
00209 }
00210
if ( dataType !=
typeValue) {
00211
00212
00213 item->
setCache(rhs);
00214 item->setText(
ValueCol, value.left(pos));
00215
break;
00216 }
00217 }
00218 item->setText(
ValueCol, value);
00219 item->setExpandable(!value.isEmpty() && (value[0] ==
'@'));
00220
break;
00221 }
00222
00223
case typeValue:
00224 item->setText(
ValueCol, value);
00225
break;
00226
00227
default:
00228
break;
00229 }
00230 }
00231
00232
00233
00234 DataType GDBParser::determineType(
char *buf)
const
00235
{
00236
if (!buf || !*(buf=
skipNextTokenStart(buf)))
00237
return typeUnknown;
00238
00239
00240
if (*buf ==
'@')
00241
return typeReference;
00242
00243
00244
00245
00246
if (*buf ==
'{') {
00247
if (strncmp(buf,
"{{", 2) == 0)
00248
return typeArray;
00249
00250
if (strncmp(buf,
"{<No data fields>}", 18) == 0)
00251
return typeValue;
00252
00253 buf++;
00254
while (*buf) {
00255
switch (*buf) {
00256
case '=':
00257
return typeStruct;
00258
case '"':
00259 buf =
skipString(buf);
00260
break;
00261
case '\'':
00262 buf =
skipQuotes(buf,
'\'');
00263
break;
00264
case ',':
00265
if (*(buf-1) ==
'}')
00266 Q_ASSERT(
false);
00267
return typeArray;
00268
case '}':
00269
if (*(buf+1) ==
',' || *(buf+1) ==
'\n' || !*(buf+1))
00270
return typeArray;
00271
if (strncmp(buf+1,
" 0x", 3) == 0)
00272
return typePointer;
00273
return typeUnknown;
00274
case '(':
00275 buf =
skipDelim(buf,
'(',
')');
00276
break;
00277
case '<':
00278 buf = skipDelim(buf,
'<',
'>');
00279
break;
00280
default:
00281 buf++;
00282
break;
00283 }
00284 }
00285
return typeUnknown;
00286 }
00287
00288
00289
00290
00291
if (strncmp(buf,
"0x", 2) == 0) {
00292
while (*buf) {
00293
if (!isspace(*buf))
00294 buf++;
00295
else if (*(buf+1) ==
'\"')
00296
return typeValue;
00297
else
00298
break;
00299 }
00300
00301
return typePointer;
00302 }
00303
00304
00305
00306
00307
00308
if (*buf ==
'(') {
00309 buf =
skipDelim(buf,
'(',
')');
00310
switch (*(buf-2)) {
00311
case '*':
00312
return typePointer;
00313
case '&':
00314
return typeReference;
00315
default:
00316
switch (*(buf-8)) {
00317
case '*':
00318
return typePointer;
00319
case '&':
00320
return typeReference;
00321 }
00322
return typeUnknown;
00323 }
00324 }
00325
00326 buf =
skipTokenValue(buf);
00327
if ((strncmp(buf,
" = ", 3) == 0) || (*buf ==
'='))
00328
return typeName;
00329
00330
return typeValue;
00331 }
00332
00333
00334
00335 char *GDBParser::skipString(
char *buf)
const
00336
{
00337
if (buf && *buf ==
'\"') {
00338 buf =
skipQuotes(buf, *buf);
00339
while (*buf) {
00340
if ((strncmp(buf,
", \"", 3) == 0) ||
00341 (strncmp(buf,
", '", 3) == 0))
00342 buf = skipQuotes(buf+2, *(buf+2));
00343
else if (strncmp(buf,
" <", 2) == 0)
00344 buf =
skipDelim(buf+1,
'<',
'>');
00345
else
00346
break;
00347 }
00348
00349
00350
while (*buf && *buf ==
'.')
00351 buf++;
00352 }
00353
00354
return buf;
00355 }
00356
00357
00358
00359 char *GDBParser::skipQuotes(
char *buf,
char quotes)
const
00360
{
00361
if (buf && *buf == quotes) {
00362 buf++;
00363
00364
while (*buf) {
00365
if (*buf ==
'\\')
00366 buf++;
00367
else if (*buf == quotes)
00368
return buf+1;
00369
00370 buf++;
00371 }
00372 }
00373
00374
return buf;
00375 }
00376
00377
00378
00379 char *GDBParser::skipDelim(
char *buf,
char open,
char close)
const
00380
{
00381
if (buf && *buf == open) {
00382 buf++;
00383
00384
while (*buf) {
00385
if (*buf == open)
00386 buf =
skipDelim(buf, open, close);
00387
else if (*buf == close)
00388
return buf+1;
00389
else if (*buf ==
'\"')
00390 buf =
skipString(buf);
00391
else if (*buf ==
'\'')
00392 buf =
skipQuotes(buf, *buf);
00393
else if (*buf)
00394 buf++;
00395 }
00396 }
00397
return buf;
00398 }
00399
00400
00401
00402 char *GDBParser::skipTokenValue(
char *buf)
const
00403
{
00404
if (buf) {
00405
while (
true) {
00406 buf =
skipTokenEnd(buf);
00407
00408
char *end = buf;
00409
while (*end && isspace(*end) && *end !=
'\n')
00410 end++;
00411
00412
if (*end == 0 || *end ==
',' || *end ==
'\n' || *end ==
'=' || *end ==
'}')
00413
break;
00414
00415
if (buf == end)
00416
break;
00417
00418 buf = end;
00419 }
00420 }
00421
00422
return buf;
00423 }
00424
00425
00426
00427 char *GDBParser::skipTokenEnd(
char *buf)
const
00428
{
00429
if (buf) {
00430
switch (*buf) {
00431
case '"':
00432
return skipString(buf);
00433
case '\'':
00434
return skipQuotes(buf, *buf);
00435
case '{':
00436
return skipDelim(buf,
'{',
'}');
00437
case '<':
00438
return skipDelim(buf,
'<',
'>');
00439
case '(':
00440
return skipDelim(buf,
'(',
')');
00441 }
00442
00443
while (*buf && !isspace(*buf) && *buf !=
',' && *buf !=
'}' && *buf !=
'=')
00444 buf++;
00445 }
00446
00447
return buf;
00448 }
00449
00450
00451
00452 char *GDBParser::skipNextTokenStart(
char *buf)
const
00453
{
00454
if (buf)
00455
while (*buf && (isspace(*buf) || *buf ==
',' || *buf ==
'}' || *buf ==
'='))
00456 buf++;
00457
00458
return buf;
00459 }
00460
00461
00462
00463
00464
00465 }