KDevelop API Documentation

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.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 00:03:46 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003