vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / debugger / demangle / gcc2.cpp
bloba35a2923888deb0ce8af092585c599f343ea6210
1 /*
2 * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de.
3 * This file may be used under the terms of the MIT License.
4 */
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <string.h>
11 #include <TypeConstants.h>
13 #ifdef _KERNEL_MODE
14 # include <debug.h>
15 #endif
17 #include "demangle.h"
20 //#define TRACE_GCC2_DEMANGLER
21 #ifdef TRACE_GCC2_DEMANGLER
22 # define TRACE(x...) kprintf(x)
23 #else
24 # define TRACE(x...) ;
25 #endif
28 enum {
29 TYPE_FUNCTION,
30 TYPE_METHOD,
34 static void
35 ignore_qualifiers(const char** _arg)
37 while (isupper(**_arg)) {
38 if (**_arg == 'Q') {
39 // argument has namespaces
40 break;
42 if (**_arg == 'F') {
43 // skip function declaration
44 while (**_arg && **_arg != '_')
45 (*_arg)++;
47 if (**_arg == 0)
48 break;
51 (*_arg)++;
56 static uint32
57 argument_type(const char* arg, size_t& length)
59 length = sizeof(int);
61 switch (char type = arg[0]) {
62 case 'P': // pointer
63 case 'R': // reference
64 length = sizeof(void*);
65 ignore_qualifiers(&arg);
66 if (arg[0] == 'c')
67 return B_STRING_TYPE;
68 if (arg[0] == 't') {
69 // TODO: templates are not yet supported
70 return 0;
73 return type == 'P' ? B_POINTER_TYPE : B_REF_TYPE;
74 case 'x':
75 length = sizeof(long long);
76 return B_INT64_TYPE;
77 case 'l':
78 if (sizeof(long) == 4)
79 return B_INT32_TYPE;
80 return B_INT64_TYPE;
81 case 'i':
82 return B_INT32_TYPE;
83 case 's':
84 return B_INT16_TYPE;
85 case 'c':
86 return B_INT8_TYPE;
87 case 'b':
88 return B_BOOL_TYPE;
89 case 'U':
90 switch (arg[1]) {
91 case 'x':
92 length = sizeof(long long);
93 return B_UINT64_TYPE;
94 case 'l':
95 if (sizeof(long) == 4)
96 return B_UINT32_TYPE;
97 return B_UINT64_TYPE;
98 case 'i':
99 return B_UINT32_TYPE;
100 case 's':
101 return B_UINT16_TYPE;
102 case 'c':
103 return B_UINT8_TYPE;
104 default:
105 return B_UINT32_TYPE;
107 break;
109 case 'f':
110 return B_FLOAT_TYPE;
111 case 'd':
112 length = sizeof(double);
113 return B_DOUBLE_TYPE;
114 case 'r':
115 // TODO: is "long double" supported under Haiku at all?
116 return 0;
118 case 't':
119 // TODO: templates are not yet supported
120 return 0;
122 default:
123 return B_ANY_TYPE;
128 static uint32
129 parse_number(const char** _arg, bool numberLeft)
131 const char* arg = *_arg;
133 while (isdigit(arg[0]))
134 arg++;
136 uint32 value;
138 if (arg[0] == '_' && (!numberLeft || isdigit(arg[1]))) {
139 // long value
140 value = strtoul(*_arg, (char**)_arg, 10);
141 if (**_arg == '_')
142 (*_arg)++;
143 } else {
144 value = **_arg - '0';
145 (*_arg)++;
148 return value;
152 static uint32
153 parse_repeats(const char** _arg, uint32& index)
155 if (**_arg != 'N')
156 return 0;
158 (*_arg)++;
160 uint32 count = parse_number(_arg, true);
161 index = parse_number(_arg, false);
163 return count;
167 static void
168 skip_numbers(const char** _arg, int32 count)
170 // skip leading character
171 (*_arg)++;
173 while (count-- > 0) {
174 parse_number(_arg, count != 0);
179 static uint32
180 count_namespaces(const char** _mangled)
182 const char* mangled = *_mangled;
184 int32 namespaces = 0;
185 if (mangled[0] == 'Q') {
186 // more than one namespace
187 if (mangled[1] == '_') {
188 // more than 9 namespaces
189 namespaces = strtoul(mangled + 2, (char**)&mangled, 10);
190 if (mangled[0] != '_')
191 namespaces = 0;
193 mangled++;
194 } else {
195 namespaces = mangled[1] - '0';
196 mangled += 2;
198 } else if (isdigit(mangled[0]))
199 namespaces = 1;
201 *_mangled = mangled;
202 return namespaces;
206 static void
207 skip_namespaces(const char** _mangled)
209 const char* mangled = *_mangled;
210 int32 namespaces = count_namespaces(&mangled);
212 while (namespaces-- > 0) {
213 if (!isdigit(mangled[0]))
214 break;
216 mangled += strtoul(mangled, (char**)&mangled, 10);
219 *_mangled = mangled;
223 static bool
224 has_named_argument(const char** _arg)
226 ignore_qualifiers(_arg);
228 // See if it's a built-in type
229 return **_arg == 'Q' || isdigit(**_arg);
233 static uint32
234 argument_length(const char** _arg)
236 if (**_arg == 'N') {
237 // skip repeats
238 skip_numbers(_arg, 2);
239 return 0;
240 } else if (**_arg == 'T') {
241 // skip reference
242 skip_numbers(_arg, 1);
243 return 0;
246 ignore_qualifiers(_arg);
248 if (!**_arg)
249 return 0;
251 // See if it's a built-in type
252 if (**_arg != 'Q' && !isdigit(**_arg))
253 return 1;
255 const char* mangled = *_arg;
256 skip_namespaces(&mangled);
258 return mangled - *_arg;
262 static const char*
263 next_argument(const char* arg)
265 if (arg == NULL || !arg[0])
266 return NULL;
268 uint32 length = argument_length(&arg);
269 arg += length;
271 if (!arg[0])
272 return NULL;
274 return arg;
278 static const char*
279 first_argument(const char* mangled)
281 skip_namespaces(&mangled);
283 return mangled;
287 static const char*
288 mangled_start(const char* name, size_t* _symbolLength, int32* _symbolType)
290 if (name == NULL)
291 return NULL;
293 // search '__' starting from the end, don't accept them at the start
294 size_t pos = strlen(name) - 1;
295 const char* mangled = NULL;
297 while (pos > 1) {
298 if (name[pos] == '_') {
299 if (name[pos - 1] == '_') {
300 mangled = name + pos + 1;
301 break;
302 } else
303 pos--;
305 pos--;
308 if (mangled == NULL)
309 return NULL;
311 if (mangled[0] == 'H') {
312 // TODO: we don't support templates yet
313 return NULL;
316 if (_symbolLength != NULL)
317 *_symbolLength = pos - 1;
319 if (mangled[0] == 'F') {
320 if (_symbolType != NULL)
321 *_symbolType = TYPE_FUNCTION;
322 return mangled + 1;
325 if (_symbolType != NULL)
326 *_symbolType = TYPE_METHOD;
327 return mangled;
331 static status_t
332 get_next_argument_internal(uint32* _cookie, const char* symbol, char* name,
333 size_t nameSize, int32* _type, size_t* _argumentLength, bool repeating)
335 const char* mangled = mangled_start(symbol, NULL, NULL);
336 if (mangled == NULL)
337 return B_BAD_VALUE;
339 const char* arg = first_argument(mangled);
341 // (void) is not an argument
342 if (arg[0] == 'v')
343 return B_ENTRY_NOT_FOUND;
345 uint32 current = *_cookie;
346 if (current > 32)
347 return B_TOO_MANY_ARGS;
349 for (uint32 i = 0; i < current; i++) {
350 arg = next_argument(arg);
351 if (arg != NULL && arg[0] == 'N') {
352 // repeat argument 'count' times
353 uint32 index;
354 uint32 count = parse_repeats(&arg, index);
355 if (current <= i + count) {
356 if (repeating)
357 return B_LINK_LIMIT;
359 // it's a repeat case
360 status_t status = get_next_argument_internal(&index, symbol,
361 name, nameSize, _type, _argumentLength, true);
362 if (status == B_OK)
363 (*_cookie)++;
364 return status;
367 i += count - 1;
371 if (arg == NULL)
372 return B_ENTRY_NOT_FOUND;
374 TRACE("\n\targ %ld: %s\n", current, arg);
376 if (arg[0] == 'T') {
377 // duplicate argument
378 if (repeating)
379 return B_LINK_LIMIT;
381 arg++;
382 uint32 index = parse_number(&arg, false);
383 status_t status = get_next_argument_internal(&index, symbol, name,
384 nameSize, _type, _argumentLength, true);
385 if (status == B_OK)
386 (*_cookie)++;
387 return status;
390 (*_cookie)++;
392 size_t argumentLength;
393 int32 type = argument_type(arg, argumentLength);
394 if (type == 0)
395 return B_NOT_SUPPORTED;
397 if (_type != NULL)
398 *_type = type;
399 if (_argumentLength != NULL)
400 *_argumentLength = argumentLength;
402 name[0] = '\0';
403 if (!has_named_argument(&arg))
404 return B_OK;
406 const char* namespaceStart = arg;
407 int32 namespaces = count_namespaces(&namespaceStart);
409 while (namespaces-- > 0) {
410 if (namespaceStart[0] == 't') {
411 // It's a template class after all
412 return B_BAD_TYPE;
414 if (!isdigit(namespaceStart[0]))
415 break;
417 uint32 length = strtoul(namespaceStart, (char**)&namespaceStart, 10);
418 uint32 max = strlen(name) + length + 1;
419 strlcat(name, namespaceStart, min_c(max, nameSize));
420 if (namespaces > 0)
421 strlcat(name, "::", nameSize);
422 namespaceStart += length;
425 return B_OK;
429 // #pragma mark -
432 const char*
433 demangle_symbol_gcc2(const char* name, char* buffer, size_t bufferSize,
434 bool* _isObjectMethod)
436 size_t nameLength;
437 int32 type;
438 const char* mangled = mangled_start(name, &nameLength, &type);
439 if (mangled == NULL)
440 return NULL;
442 if (mangled[0] == 'C') {
443 // ignore const method
444 type = TYPE_METHOD;
445 mangled++;
448 if (_isObjectMethod != NULL) {
449 // we can only guess with GCC2 mangling
450 *_isObjectMethod = type == TYPE_METHOD;
453 const char* namespaceStart = mangled;
454 int32 namespaces = count_namespaces(&namespaceStart);
456 buffer[0] = '\0';
458 while (namespaces-- > 0) {
459 if (namespaceStart[0] == 't') {
460 // It's a template class after all
461 return NULL;
463 if (!isdigit(namespaceStart[0]))
464 break;
466 uint32 length = strtoul(namespaceStart, (char**)&namespaceStart, 10);
467 uint32 max = strlen(buffer) + length + 1;
468 strlcat(buffer, namespaceStart, min_c(max, bufferSize));
469 strlcat(buffer, "::", bufferSize);
470 namespaceStart += length;
473 size_t max = strlen(buffer) + nameLength + 1;
474 strlcat(buffer, name, min_c(max, bufferSize));
475 return buffer;
479 status_t
480 get_next_argument_gcc2(uint32* _cookie, const char* symbol, char* name,
481 size_t nameSize, int32* _type, size_t* _argumentLength)
483 status_t error = get_next_argument_internal(_cookie, symbol, name, nameSize,
484 _type, _argumentLength, false);
485 if (error != B_OK)
486 return error;
488 // append the missing '*'/'&' for pointer/ref types
489 if (name[0] != '\0' && (*_type == B_POINTER_TYPE || *_type == B_REF_TYPE))
490 strlcat(name, *_type == B_POINTER_TYPE ? "*" : "&", nameSize);
492 return B_OK;