~ubuntu-branches/debian/sid/kdevelop/sid

« back to all changes in this revision

Viewing changes to languages/cpp/debugger/gdbparser.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2010-05-05 07:21:55 UTC
  • mfrom: (1.2.3 upstream) (5.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100505072155-h78lx19pu04sbhtn
Tags: 4:4.0.0-2
* Upload to unstable (Closes: #579947, #481832).
* Acknowledge obsolete NMU fixes (Closes: #562410, #546961).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// **************************************************************************
2
 
//    begin                : Tue Aug 17 1999
3
 
//    copyright            : (C) 1999 by John Birch
4
 
//    email                : jbb@kdevelop.org
5
 
// **************************************************************************
6
 
 
7
 
// **************************************************************************
8
 
//                                                                          *
9
 
//    This program is free software; you can redistribute it and/or modify  *
10
 
//    it under the terms of the GNU General Public License as published by  *
11
 
//    the Free Software Foundation; either version 2 of the License, or     *
12
 
//    (at your option) any later version.                                   *
13
 
//                                                                          *
14
 
// **************************************************************************
15
 
 
16
 
#include "gdbparser.h"
17
 
#include "variablewidget.h"
18
 
#include <kdebug.h>
19
 
 
20
 
#include <qregexp.h>
21
 
 
22
 
#include <ctype.h>
23
 
#include <stdlib.h>
24
 
 
25
 
namespace GDBDebugger
26
 
{
27
 
 
28
 
// **************************************************************************
29
 
// **************************************************************************
30
 
// **************************************************************************
31
 
 
32
 
GDBParser *GDBParser::GDBParser_ = 0;
33
 
 
34
 
GDBParser *GDBParser::getGDBParser()
35
 
{
36
 
  if (!GDBParser_)
37
 
    GDBParser_ = new GDBParser();
38
 
 
39
 
  return GDBParser_;
40
 
}
41
 
 
42
 
// **************************************************************************
43
 
 
44
 
void GDBParser::destroy()
45
 
{
46
 
    delete GDBParser_;
47
 
    GDBParser_ = 0;
48
 
}
49
 
 
50
 
// **************************************************************************
51
 
 
52
 
GDBParser::GDBParser()
53
 
{
54
 
}
55
 
 
56
 
// **************************************************************************
57
 
 
58
 
GDBParser::~GDBParser()
59
 
{
60
 
}
61
 
 
62
 
 
63
 
// **************************************************************************
64
 
 
65
 
QString GDBParser::getName(const char **buf)
66
 
{
67
 
    const char *start = skipNextTokenStart(*buf);
68
 
    if (*start) {
69
 
        *buf = skipTokenValue(start);
70
 
        return QCString(start, *buf - start + 1);
71
 
    } else
72
 
        *buf = start;
73
 
 
74
 
    return QString();
75
 
}
76
 
 
77
 
// **************************************************************************
78
 
 
79
 
QString GDBParser::getValue(const char **buf)
80
 
{
81
 
    const char *start = skipNextTokenStart(*buf);
82
 
    *buf = skipTokenValue(start);
83
 
 
84
 
    QString value(QCString(start, *buf - start + 1).data());
85
 
    return value;
86
 
}
87
 
 
88
 
QString GDBParser::undecorateValue(DataType type, const QString& s)
89
 
{
90
 
    QCString l8 = s.local8Bit();
91
 
    const char* start = l8;
92
 
    const char* end = start + s.length();
93
 
 
94
 
    if (*start == '{')
95
 
    {
96
 
        // Gdb uses '{' in two cases:
97
 
        // - composites (arrays and structures)
98
 
        // - pointers to functions. In this case type is
99
 
        //   enclosed in "{}". Not sure why it's so, as
100
 
        //   when printing pointer, type is in parenthesis.
101
 
        if (type == typePointer)
102
 
        {
103
 
            // Looks like type in braces at the beginning. Strip it.
104
 
            start = skipDelim(start, '{', '}');
105
 
        }
106
 
        else
107
 
        {
108
 
            // Looks like composite, strip the braces and return.
109
 
            return QCString(start+1, end - start -1);
110
 
        }
111
 
    }
112
 
    else if (*start == '(')
113
 
    {
114
 
        // Strip the type of the pointer from the value.
115
 
        //
116
 
        // When printing values of pointers, gdb prints the pointer
117
 
        // type as well. This is not necessary for kdevelop -- after
118
 
        // all, there's separate column with value type. But that behaviour
119
 
        // is not configurable. The only way to change it is to explicitly
120
 
        // pass the 'x' format specifier to the 'print' command. 
121
 
        //
122
 
        // We probably can achieve that by sending an 'print in hex' request
123
 
        // as soon as we know the type of variable, but that would be complex
124
 
        // and probably conflict with 'toggle hex/decimal' command.
125
 
        // So, address this problem as close to debugger as possible.
126
 
 
127
 
        // We can't find the first ')', because type can contain '(' and ')'
128
 
        // characters if its function pointer. So count opening and closing
129
 
        // parentheses.
130
 
 
131
 
        start = skipDelim(start, '(', ')');
132
 
    }
133
 
 
134
 
    QString value(QCString(start, end - start + 1).data());
135
 
 
136
 
    value = value.stripWhiteSpace();
137
 
 
138
 
    if (value[0] == '@')
139
 
    {
140
 
        // It's a reference, we need to show just the value.
141
 
        if (int i = value.find(":"))
142
 
        {
143
 
            value = value.mid(i+2);
144
 
        }
145
 
        else
146
 
        {
147
 
            // Just reference, no value at all, remove all
148
 
            value = "";
149
 
        }
150
 
    }
151
 
 
152
 
    if (value.find("Cannot access memory") == 0)
153
 
        value = "(inaccessible)";
154
 
  
155
 
    return value.stripWhiteSpace();
156
 
}
157
 
 
158
 
QString GDBParser::undecorateValue(const QString& s)
159
 
{
160
 
    DataType dataType = determineType(s.local8Bit());
161
 
    QString r = undecorateValue(dataType, s.local8Bit());
162
 
    return r;
163
 
}
164
 
 
165
 
// Given a value that starts with 0xNNNNNN determines if
166
 
// it looks more like pointer, or a string value.
167
 
DataType pointerOrValue(const char *buf)
168
 
{
169
 
    while (*buf) {
170
 
        if (!isspace(*buf))
171
 
            buf++;
172
 
        else if (*(buf+1) == '\"')
173
 
            return typeValue;
174
 
        else
175
 
            break;
176
 
    }
177
 
    
178
 
    return typePointer;
179
 
}
180
 
 
181
 
 
182
 
DataType GDBParser::determineType(const char *buf) const
183
 
{
184
 
    if (!buf || !*(buf= skipNextTokenStart(buf)))
185
 
        return typeUnknown;
186
 
 
187
 
    // A reference, probably from a parameter value.
188
 
    if (*buf == '@')
189
 
        return typeReference;
190
 
 
191
 
    // Structures and arrays - (but which one is which?)
192
 
    // {void (void)} 0x804a944 <__builtin_new+41> - this is a fn pointer
193
 
    // (void (*)(void)) 0x804a944 <f(E *, char)>  - so is this - ugly!!!
194
 
    if (*buf == '{') {
195
 
        if (strncmp(buf, "{{", 2) == 0)
196
 
            return typeArray;
197
 
 
198
 
        if (strncmp(buf, "{<No data fields>}", 18) == 0)
199
 
            return typeValue;
200
 
 
201
 
        buf++;
202
 
        while (*buf) {
203
 
            switch (*buf) {
204
 
            case '=':
205
 
                return typeStruct;
206
 
            case '"':
207
 
                buf = skipString(buf);
208
 
                break;
209
 
            case '\'':
210
 
                buf = skipQuotes(buf, '\'');
211
 
                break;
212
 
            case ',':
213
 
                if (*(buf-1) == '}')
214
 
                    Q_ASSERT(false);
215
 
                return typeArray;
216
 
            case '}':
217
 
                if (*(buf+1) == ',' || *(buf+1) == '\n' || !*(buf+1))
218
 
                    return typeArray;       // Hmm a single element array??
219
 
                if (strncmp(buf+1, " 0x", 3) == 0)
220
 
                    return typePointer;     // What about references?
221
 
                return typeUnknown;         // very odd?
222
 
            case '(':
223
 
                buf = skipDelim(buf, '(', ')');
224
 
                break;
225
 
            case '<':
226
 
                buf = skipDelim(buf, '<', '>');
227
 
                // gdb may produce this output:
228
 
                // $1 = 0x804ddf3 ' ' <repeats 20 times>, "TESTSTRING"
229
 
                // after having finished with the "repeats"-block we need
230
 
                // to check if the string continues
231
 
                if ( buf[0] == ',' && (buf[2] == '\"' || buf[2] == '\'') ) {
232
 
                    buf++; //set the buffer behind the comma to indicate that the string continues
233
 
                }
234
 
                break;
235
 
            default:
236
 
                buf++;
237
 
                break;
238
 
            }
239
 
        }
240
 
        return typeUnknown;
241
 
    }
242
 
 
243
 
    // some sort of address. We need to sort out if we have
244
 
    // a 0x888888 "this is a char*" type which we'll term a value
245
 
    // or whether we just have an address
246
 
    if (strncmp(buf, "0x", 2) == 0) {
247
 
        return pointerOrValue(buf);
248
 
    }
249
 
 
250
 
    // Pointers and references - references are a bit odd
251
 
    // and cause GDB to fail to produce all the local data
252
 
    // if they haven't been initialised. but that's not our problem!!
253
 
    // (void (*)(void)) 0x804a944 <f(E *, char)> - this is a fn pointer
254
 
    if (*buf == '(') {
255
 
        buf = skipDelim(buf, '(', ')');
256
 
        // This 'if' handles values like this:
257
 
        // (int (&)[3]) @0xbffff684: {5, 6, 7}
258
 
        // which is a reference to array.
259
 
        if (buf[1] == '@')
260
 
            return typeReference;
261
 
        // This 'if' handles values like this:
262
 
        // (int (*)[3]) 0xbffff810
263
 
        if (strncmp(buf, " 0x", 3) == 0)
264
 
        {
265
 
            ++buf;
266
 
            return pointerOrValue(buf);
267
 
        }
268
 
 
269
 
        switch (*(buf-2)) {
270
 
        case '*':
271
 
            return typePointer;
272
 
        case '&':
273
 
            return typeReference;
274
 
        default:
275
 
            switch (*(buf-8)) {
276
 
                case '*':
277
 
                    return typePointer;
278
 
                case '&':
279
 
                    return typeReference;
280
 
            }
281
 
            return typeUnknown;
282
 
        }
283
 
    }
284
 
 
285
 
    buf = skipTokenValue(buf);
286
 
    if ((strncmp(buf, " = ", 3) == 0) || (*buf == '='))
287
 
        return typeName;
288
 
 
289
 
    return typeValue;
290
 
}
291
 
 
292
 
// **************************************************************************
293
 
 
294
 
const char *GDBParser::skipString(const char *buf) const
295
 
{
296
 
    if (buf && *buf == '\"') {
297
 
        buf = skipQuotes(buf, *buf);
298
 
        while (*buf) {
299
 
            if ((strncmp(buf, ", \"", 3) == 0) ||
300
 
                (strncmp(buf, ", '", 3) == 0))
301
 
                buf = skipQuotes(buf+2, *(buf+2));
302
 
            else if (strncmp(buf, " <", 2) == 0)  // take care of <repeats
303
 
                buf = skipDelim(buf+1, '<', '>');
304
 
            else
305
 
                break;
306
 
        }
307
 
 
308
 
        // If the string is long then it's chopped and has ... after it.
309
 
        while (*buf && *buf == '.')
310
 
            buf++;
311
 
    }
312
 
 
313
 
    return buf;
314
 
}
315
 
 
316
 
// ***************************************************************************
317
 
 
318
 
const char *GDBParser::skipQuotes(const char *buf, char quotes) const
319
 
{
320
 
    if (buf && *buf == quotes) {
321
 
        buf++;
322
 
 
323
 
        while (*buf) {
324
 
            if (*buf == '\\')
325
 
                buf++;             // skips \" or \' problems
326
 
            else if (*buf == quotes)
327
 
                return buf+1;
328
 
 
329
 
            buf++;
330
 
        }
331
 
    }
332
 
 
333
 
    return buf;
334
 
}
335
 
 
336
 
// **************************************************************************
337
 
 
338
 
const char *GDBParser::skipDelim(const char *buf, char open, char close) const
339
 
{
340
 
    if (buf && *buf == open) {
341
 
        buf++;
342
 
 
343
 
        while (*buf) {
344
 
            if (*buf == open)
345
 
                buf = skipDelim(buf, open, close);
346
 
            else if (*buf == close)
347
 
                return buf+1;
348
 
            else if (*buf == '\"')
349
 
                buf = skipString(buf);
350
 
            else if (*buf == '\'')
351
 
                buf = skipQuotes(buf, *buf);
352
 
            else if (*buf)
353
 
                buf++;
354
 
        }
355
 
    }
356
 
    return buf;
357
 
}
358
 
 
359
 
// **************************************************************************
360
 
 
361
 
const char *GDBParser::skipTokenValue(const char *buf) const
362
 
{
363
 
    if (buf) {
364
 
        while (true) {
365
 
            buf = skipTokenEnd(buf);
366
 
 
367
 
            const char *end = buf;
368
 
            while (*end && isspace(*end) && *end != '\n')
369
 
                end++;
370
 
 
371
 
            if (*end == 0 || *end == ',' || *end == '\n' || *end == '=' || *end == '}')
372
 
                break;
373
 
 
374
 
            if (buf == end)
375
 
                break;
376
 
 
377
 
            buf = end;
378
 
        }
379
 
    }
380
 
 
381
 
    return buf;
382
 
}
383
 
 
384
 
// **************************************************************************
385
 
 
386
 
const char *GDBParser::skipTokenEnd(const char *buf) const
387
 
{
388
 
    if (buf) {
389
 
        switch (*buf) {
390
 
        case '"':
391
 
            return skipString(buf);
392
 
        case '\'':
393
 
            return skipQuotes(buf, *buf);
394
 
        case '{':
395
 
            return skipDelim(buf, '{', '}');
396
 
        case '<':
397
 
            buf = skipDelim(buf, '<', '>');
398
 
            // gdb may produce this output:
399
 
            // $1 = 0x804ddf3 ' ' <repeats 20 times>, "TESTSTRING"
400
 
            // after having finished with the "repeats"-block we need
401
 
            // to check if the string continues
402
 
            if ( buf[0] == ',' && (buf[2] == '\"' || buf[2] == '\'') ) {
403
 
                buf++; //set the buffer behind the comma to indicate that the string continues
404
 
            }
405
 
            return buf;
406
 
        case '(':
407
 
            return skipDelim(buf, '(', ')');
408
 
        }
409
 
 
410
 
        while (*buf && !isspace(*buf) && *buf != ',' && *buf != '}' && *buf != '=')
411
 
            buf++;
412
 
    }
413
 
 
414
 
    return buf;
415
 
}
416
 
 
417
 
// **************************************************************************
418
 
 
419
 
const char *GDBParser::skipNextTokenStart(const char *buf) const
420
 
{
421
 
    if (buf)
422
 
        while (*buf && (isspace(*buf) || *buf == ',' || *buf == '}' || *buf == '='))
423
 
            buf++;
424
 
 
425
 
    return buf;
426
 
}
427
 
 
428
 
// **************************************************************************
429
 
// **************************************************************************
430
 
// **************************************************************************
431
 
 
432
 
}