KDevelop API Documentation

languages/cpp/debugger/gdbparser.cpp

Go to the documentation of this file.
00001 // ************************************************************************** 00002 // begin : Tue Aug 17 1999 00003 // copyright : (C) 1999 by John Birch 00004 // email : jbb@kdevelop.org 00005 // ************************************************************************** 00006 00007 // ************************************************************************** 00008 // * 00009 // This program is free software; you can redistribute it and/or modify * 00010 // it under the terms of the GNU General Public License as published by * 00011 // the Free Software Foundation; either version 2 of the License, or * 00012 // (at your option) any later version. * 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 // QT2.x string handling 00147 // A very bad hack alert! 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 // -- I don't understand this code, but this seems to make sense 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 // -- end clueless patch 00212 // if (determineType(rhs.data()) != typeValue) { 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 // A reference, probably from a parameter value. 00240 if (*buf == '@') 00241 return typeReference; 00242 00243 // Structures and arrays - (but which one is which?) 00244 // {void (void)} 0x804a944 <__builtin_new+41> - this is a fn pointer 00245 // (void (*)(void)) 0x804a944 <f(E *, char)> - so is this - ugly!!! 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; // Hmm a single element array?? 00271 if (strncmp(buf+1, " 0x", 3) == 0) 00272 return typePointer; // What about references? 00273 return typeUnknown; // very odd? 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 // some sort of address. We need to sort out if we have 00289 // a 0x888888 "this is a char*" type which we'll term a value 00290 // or whether we just have an address 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 // Pointers and references - references are a bit odd 00305 // and cause GDB to fail to produce all the local data 00306 // if they haven't been initialised. but that's not our problem!! 00307 // (void (*)(void)) 0x804a944 <f(E *, char)> - this is a fn pointer 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) // take care of <repeats 00344 buf = skipDelim(buf+1, '<', '>'); 00345 else 00346 break; 00347 } 00348 00349 // If the string is long then it's chopped and has ... after it. 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++; // skips \" or \' problems 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 }
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 6 17:39:01 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003