2 * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de.
3 * This file may be used under the terms of the MIT License.
11 #include <TypeConstants.h>
20 //#define TRACE_GCC2_DEMANGLER
21 #ifdef TRACE_GCC2_DEMANGLER
22 # define TRACE(x...) kprintf(x)
24 # define TRACE(x...) ;
35 ignore_qualifiers(const char** _arg
)
37 while (isupper(**_arg
)) {
39 // argument has namespaces
43 // skip function declaration
44 while (**_arg
&& **_arg
!= '_')
57 argument_type(const char* arg
, size_t& length
)
61 switch (char type
= arg
[0]) {
63 case 'R': // reference
64 length
= sizeof(void*);
65 ignore_qualifiers(&arg
);
69 // TODO: templates are not yet supported
73 return type
== 'P' ? B_POINTER_TYPE
: B_REF_TYPE
;
75 length
= sizeof(long long);
78 if (sizeof(long) == 4)
92 length
= sizeof(long long);
95 if (sizeof(long) == 4)
101 return B_UINT16_TYPE
;
105 return B_UINT32_TYPE
;
112 length
= sizeof(double);
113 return B_DOUBLE_TYPE
;
115 // TODO: is "long double" supported under Haiku at all?
119 // TODO: templates are not yet supported
129 parse_number(const char** _arg
, bool numberLeft
)
131 const char* arg
= *_arg
;
133 while (isdigit(arg
[0]))
138 if (arg
[0] == '_' && (!numberLeft
|| isdigit(arg
[1]))) {
140 value
= strtoul(*_arg
, (char**)_arg
, 10);
144 value
= **_arg
- '0';
153 parse_repeats(const char** _arg
, uint32
& index
)
160 uint32 count
= parse_number(_arg
, true);
161 index
= parse_number(_arg
, false);
168 skip_numbers(const char** _arg
, int32 count
)
170 // skip leading character
173 while (count
-- > 0) {
174 parse_number(_arg
, count
!= 0);
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] != '_')
195 namespaces
= mangled
[1] - '0';
198 } else if (isdigit(mangled
[0]))
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]))
216 mangled
+= strtoul(mangled
, (char**)&mangled
, 10);
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
);
234 argument_length(const char** _arg
)
238 skip_numbers(_arg
, 2);
240 } else if (**_arg
== 'T') {
242 skip_numbers(_arg
, 1);
246 ignore_qualifiers(_arg
);
251 // See if it's a built-in type
252 if (**_arg
!= 'Q' && !isdigit(**_arg
))
255 const char* mangled
= *_arg
;
256 skip_namespaces(&mangled
);
258 return mangled
- *_arg
;
263 next_argument(const char* arg
)
265 if (arg
== NULL
|| !arg
[0])
268 uint32 length
= argument_length(&arg
);
279 first_argument(const char* mangled
)
281 skip_namespaces(&mangled
);
288 mangled_start(const char* name
, size_t* _symbolLength
, int32
* _symbolType
)
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
;
298 if (name
[pos
] == '_') {
299 if (name
[pos
- 1] == '_') {
300 mangled
= name
+ pos
+ 1;
311 if (mangled
[0] == 'H') {
312 // TODO: we don't support templates yet
316 if (_symbolLength
!= NULL
)
317 *_symbolLength
= pos
- 1;
319 if (mangled
[0] == 'F') {
320 if (_symbolType
!= NULL
)
321 *_symbolType
= TYPE_FUNCTION
;
325 if (_symbolType
!= NULL
)
326 *_symbolType
= TYPE_METHOD
;
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
);
339 const char* arg
= first_argument(mangled
);
341 // (void) is not an argument
343 return B_ENTRY_NOT_FOUND
;
345 uint32 current
= *_cookie
;
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
354 uint32 count
= parse_repeats(&arg
, index
);
355 if (current
<= i
+ count
) {
359 // it's a repeat case
360 status_t status
= get_next_argument_internal(&index
, symbol
,
361 name
, nameSize
, _type
, _argumentLength
, true);
372 return B_ENTRY_NOT_FOUND
;
374 TRACE("\n\targ %ld: %s\n", current
, arg
);
377 // duplicate argument
382 uint32 index
= parse_number(&arg
, false);
383 status_t status
= get_next_argument_internal(&index
, symbol
, name
,
384 nameSize
, _type
, _argumentLength
, true);
392 size_t argumentLength
;
393 int32 type
= argument_type(arg
, argumentLength
);
395 return B_NOT_SUPPORTED
;
399 if (_argumentLength
!= NULL
)
400 *_argumentLength
= argumentLength
;
403 if (!has_named_argument(&arg
))
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
414 if (!isdigit(namespaceStart
[0]))
417 uint32 length
= strtoul(namespaceStart
, (char**)&namespaceStart
, 10);
418 uint32 max
= strlen(name
) + length
+ 1;
419 strlcat(name
, namespaceStart
, min_c(max
, nameSize
));
421 strlcat(name
, "::", nameSize
);
422 namespaceStart
+= length
;
433 demangle_symbol_gcc2(const char* name
, char* buffer
, size_t bufferSize
,
434 bool* _isObjectMethod
)
438 const char* mangled
= mangled_start(name
, &nameLength
, &type
);
442 if (mangled
[0] == 'C') {
443 // ignore const method
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
);
458 while (namespaces
-- > 0) {
459 if (namespaceStart
[0] == 't') {
460 // It's a template class after all
463 if (!isdigit(namespaceStart
[0]))
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
));
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);
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
);