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

« back to all changes in this revision

Viewing changes to debuggers/gdb/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 <kdebug.h>
 
18
 
 
19
#include <QRegExp>
 
20
#include <QByteArray>
 
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 QByteArray(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(QByteArray(start, *buf - start + 1).data());
 
85
    return value;
 
86
}
 
87
 
 
88
QString GDBParser::undecorateValue(DataType type, const QString& s)
 
89
{
 
90
    QByteArray l8 = s.toLocal8Bit();
 
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 QByteArray(start+1, end - start - 2);
 
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(QByteArray(start, end - start + 1).data());
 
135
 
 
136
    value = value.trimmed();
 
137
 
 
138
    if (value[0] == '@')
 
139
    {
 
140
        // It's a reference, we need to show just the value.
 
141
        if (int i = value.indexOf(":"))
 
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.indexOf("Cannot access memory") == 0)
 
153
        value = "(inaccessible)";
 
154
  
 
155
    return value.trimmed();
 
156
}
 
157
 
 
158
QString GDBParser::undecorateValue(const QString& s)
 
159
{
 
160
    DataType dataType = determineType(s.toLocal8Bit());
 
161
    QString r = undecorateValue(dataType, s.toLocal8Bit());
 
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
}