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 }