1 /* 2 * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. 3 * This file may be used under the terms of the MIT License. 4 */ 5 6 7 #include <ctype.h> 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <TypeConstants.h> 12 13 #include <debug.h> 14 15 16 //#define TRACE_GCC2_DEMANGLER 17 #ifdef TRACE_GCC2_DEMANGLER 18 # define TRACE(x...) kprintf(x) 19 #else 20 # define TRACE(x...) ; 21 #endif 22 23 24 enum { 25 TYPE_FUNCTION, 26 TYPE_METHOD, 27 }; 28 29 30 static void 31 ignore_qualifiers(const char** _arg) 32 { 33 while (isupper(**_arg)) { 34 if (**_arg == 'Q') { 35 // argument has namespaces 36 break; 37 } 38 if (**_arg == 'F') { 39 // skip function declaration 40 while (**_arg && **_arg != '_') 41 (*_arg)++; 42 } 43 44 (*_arg)++; 45 } 46 } 47 48 49 static uint32 50 argument_type(const char* arg, size_t& length) 51 { 52 length = sizeof(int); 53 54 switch (char type = arg[0]) { 55 case 'P': // pointer 56 case 'R': // reference 57 length = sizeof(void*); 58 ignore_qualifiers(&arg); 59 if (arg[0] == 'c') 60 return B_STRING_TYPE; 61 if (arg[0] == 't') { 62 // TODO: templates are not yet supported 63 return 0; 64 } 65 66 return type == 'P' ? B_POINTER_TYPE : B_REF_TYPE; 67 case 'x': 68 length = sizeof(long long); 69 return B_INT64_TYPE; 70 case 'l': 71 if (sizeof(long) == 4) 72 return B_INT32_TYPE; 73 return B_INT64_TYPE; 74 case 'i': 75 return B_INT32_TYPE; 76 case 's': 77 return B_INT16_TYPE; 78 case 'c': 79 return B_INT8_TYPE; 80 case 'b': 81 return B_BOOL_TYPE; 82 case 'U': 83 switch (arg[1]) { 84 case 'x': 85 length = sizeof(long long); 86 return B_UINT64_TYPE; 87 case 'l': 88 if (sizeof(long) == 4) 89 return B_UINT32_TYPE; 90 return B_UINT64_TYPE; 91 case 'i': 92 return B_UINT32_TYPE; 93 case 's': 94 return B_UINT16_TYPE; 95 case 'c': 96 return B_UINT8_TYPE; 97 default: 98 return B_UINT32_TYPE; 99 } 100 break; 101 102 case 'f': 103 return B_FLOAT_TYPE; 104 case 'd': 105 length = sizeof(double); 106 return B_DOUBLE_TYPE; 107 case 'r': 108 // TODO: is "long double" supported under Haiku at all? 109 return 0; 110 111 case 't': 112 // TODO: templates are not yet supported 113 return 0; 114 115 default: 116 return B_ANY_TYPE; 117 } 118 } 119 120 121 static uint32 122 parse_number(const char** _arg, bool numberLeft) 123 { 124 const char* arg = *_arg; 125 126 while (isdigit(arg[0])) 127 arg++; 128 129 uint32 value; 130 131 if (arg[0] == '_' && (!numberLeft || isdigit(arg[1]))) { 132 // long value 133 value = strtoul(*_arg, (char**)_arg, 10); 134 if (**_arg == '_') 135 (*_arg)++; 136 } else { 137 value = **_arg - '0'; 138 (*_arg)++; 139 } 140 141 return value; 142 } 143 144 145 static uint32 146 parse_repeats(const char** _arg, uint32& index) 147 { 148 if (**_arg != 'N') 149 return 0; 150 151 (*_arg)++; 152 153 uint32 count = parse_number(_arg, true); 154 index = parse_number(_arg, false); 155 156 return count; 157 } 158 159 160 static void 161 skip_numbers(const char** _arg, int32 count) 162 { 163 // skip leading character 164 (*_arg)++; 165 166 while (count-- > 0) { 167 parse_number(_arg, count != 0); 168 } 169 } 170 171 172 static uint32 173 count_namespaces(const char** _mangled) 174 { 175 const char* mangled = *_mangled; 176 177 int32 namespaces = 0; 178 if (mangled[0] == 'Q') { 179 // more than one namespace 180 if (mangled[1] == '_') { 181 // more than 9 namespaces 182 namespaces = strtoul(mangled + 2, (char**)&mangled, 10); 183 if (mangled[0] != '_') 184 namespaces = 0; 185 186 mangled++; 187 } else { 188 namespaces = mangled[1] - '0'; 189 mangled += 2; 190 } 191 } else if (isdigit(mangled[0])) 192 namespaces = 1; 193 194 *_mangled = mangled; 195 return namespaces; 196 } 197 198 199 static void 200 skip_namespaces(const char** _mangled) 201 { 202 const char* mangled = *_mangled; 203 int32 namespaces = count_namespaces(&mangled); 204 205 while (namespaces-- > 0) { 206 if (!isdigit(mangled[0])) 207 break; 208 209 mangled += strtoul(mangled, (char**)&mangled, 10); 210 } 211 212 *_mangled = mangled; 213 } 214 215 216 static bool 217 has_named_argument(const char** _arg) 218 { 219 ignore_qualifiers(_arg); 220 221 // See if it's a built-in type 222 return **_arg == 'Q' || isdigit(**_arg); 223 } 224 225 226 static uint32 227 argument_length(const char** _arg) 228 { 229 if (**_arg == 'N') { 230 // skip repeats 231 skip_numbers(_arg, 2); 232 return 0; 233 } else if (**_arg == 'T') { 234 // skip reference 235 skip_numbers(_arg, 1); 236 return 0; 237 } 238 239 ignore_qualifiers(_arg); 240 241 // See if it's a built-in type 242 if (**_arg != 'Q' && !isdigit(**_arg)) 243 return 1; 244 245 const char* mangled = *_arg; 246 skip_namespaces(&mangled); 247 248 return mangled - *_arg; 249 } 250 251 252 static const char* 253 next_argument(const char* arg) 254 { 255 if (arg == NULL) 256 return NULL; 257 258 uint32 length = argument_length(&arg); 259 arg += length; 260 261 if (!arg[0]) 262 return NULL; 263 264 return arg; 265 } 266 267 268 static const char* 269 first_argument(const char* mangled) 270 { 271 skip_namespaces(&mangled); 272 273 return mangled; 274 } 275 276 277 static const char* 278 mangled_start(const char* name, size_t* _symbolLength, int32* _symbolType) 279 { 280 if (name == NULL) 281 return NULL; 282 283 // search '__' starting from the end, don't accept them at the start 284 size_t pos = strlen(name) - 1; 285 const char* mangled = NULL; 286 287 while (pos > 1) { 288 if (name[pos] == '_') { 289 if (name[pos - 1] == '_') { 290 mangled = name + pos + 1; 291 break; 292 } else 293 pos--; 294 } 295 pos--; 296 } 297 298 if (mangled == NULL) 299 return NULL; 300 301 if (mangled[0] == 'H') { 302 // TODO: we don't support templates yet 303 return NULL; 304 } 305 306 if (_symbolLength != NULL) 307 *_symbolLength = pos - 1; 308 309 if (mangled[0] == 'F') { 310 if (_symbolType != NULL) 311 *_symbolType = TYPE_FUNCTION; 312 return mangled + 1; 313 } 314 315 if (_symbolType != NULL) 316 *_symbolType = TYPE_METHOD; 317 return mangled; 318 } 319 320 321 static status_t 322 get_next_argument_internal(uint32* _cookie, const char* symbol, char* name, 323 size_t nameSize, int32* _type, size_t* _argumentLength, bool repeating) 324 { 325 const char* mangled = mangled_start(symbol, NULL, NULL); 326 if (mangled == NULL) 327 return B_BAD_VALUE; 328 329 const char* arg = first_argument(mangled); 330 331 // (void) is not an argument 332 if (arg != NULL && arg[0] == 'v') 333 return B_ENTRY_NOT_FOUND; 334 335 uint32 current = *_cookie; 336 if (current > 32) 337 return B_TOO_MANY_ARGS; 338 339 for (uint32 i = 0; i < current; i++) { 340 arg = next_argument(arg); 341 if (arg != NULL && arg[0] == 'N') { 342 // repeat argument 'count' times 343 uint32 index; 344 uint32 count = parse_repeats(&arg, index); 345 if (current <= i + count) { 346 if (repeating) 347 return B_LINK_LIMIT; 348 349 // it's a repeat case 350 status_t status = get_next_argument_internal(&index, symbol, name, 351 nameSize, _type, _argumentLength, true); 352 if (status == B_OK) 353 (*_cookie)++; 354 return status; 355 } 356 357 i += count - 1; 358 } 359 } 360 361 if (arg == NULL) 362 return B_ENTRY_NOT_FOUND; 363 364 TRACE("\n\targ %ld: %s\n", current, arg); 365 366 if (arg[0] == 'T') { 367 // duplicate argument 368 if (repeating) 369 return B_LINK_LIMIT; 370 371 arg++; 372 uint32 index = parse_number(&arg, false); 373 status_t status = get_next_argument_internal(&index, symbol, name, 374 nameSize, _type, _argumentLength, true); 375 if (status == B_OK) 376 (*_cookie)++; 377 return status; 378 } 379 380 (*_cookie)++; 381 382 size_t argumentLength; 383 int32 type = argument_type(arg, argumentLength); 384 if (type == 0) 385 return B_NOT_SUPPORTED; 386 387 if (_type != NULL) 388 *_type = type; 389 if (_argumentLength != NULL) 390 *_argumentLength = argumentLength; 391 392 name[0] = '\0'; 393 if (!has_named_argument(&arg)) 394 return B_OK; 395 396 const char* namespaceStart = arg; 397 int32 namespaces = count_namespaces(&namespaceStart); 398 399 while (namespaces-- > 0) { 400 if (namespaceStart[0] == 't') { 401 // It's a template class after all 402 return B_BAD_TYPE; 403 } 404 if (!isdigit(namespaceStart[0])) 405 break; 406 407 uint32 length = strtoul(namespaceStart, (char**)&namespaceStart, 10); 408 uint32 max = strlen(name) + length + 1; 409 strlcat(name, namespaceStart, min_c(max, nameSize)); 410 if (namespaces > 0) 411 strlcat(name, "::", nameSize); 412 namespaceStart += length; 413 } 414 415 return B_OK; 416 } 417 418 419 // #pragma mark - 420 421 422 const char* 423 demangle_symbol(const char* name, char* buffer, size_t bufferSize, 424 bool* _isObjectMethod) 425 { 426 size_t nameLength; 427 int32 type; 428 const char* mangled = mangled_start(name, &nameLength, &type); 429 if (mangled == NULL) 430 return NULL; 431 432 if (mangled[0] == 'C') { 433 // ignore const method 434 type = TYPE_METHOD; 435 mangled++; 436 } 437 438 if (_isObjectMethod != NULL) { 439 // we can only guess with GCC2 mangling 440 *_isObjectMethod = type == TYPE_METHOD; 441 } 442 443 const char* namespaceStart = mangled; 444 int32 namespaces = count_namespaces(&namespaceStart); 445 446 buffer[0] = '\0'; 447 448 while (namespaces-- > 0) { 449 if (namespaceStart[0] == 't') { 450 // It's a template class after all 451 return NULL; 452 } 453 if (!isdigit(namespaceStart[0])) 454 break; 455 456 uint32 length = strtoul(namespaceStart, (char**)&namespaceStart, 10); 457 uint32 max = strlen(buffer) + length + 1; 458 strlcat(buffer, namespaceStart, min_c(max, bufferSize)); 459 strlcat(buffer, "::", bufferSize); 460 namespaceStart += length; 461 } 462 463 size_t max = strlen(buffer) + nameLength + 1; 464 strlcat(buffer, name, min_c(max, bufferSize)); 465 return buffer; 466 } 467 468 469 status_t 470 get_next_argument(uint32* _cookie, const char* symbol, char* name, 471 size_t nameSize, int32* _type, size_t* _argumentLength) 472 { 473 return get_next_argument_internal(_cookie, symbol, name, nameSize, _type, 474 _argumentLength, false); 475 } 476 477 478 static status_t 479 std_ops(int32 op, ...) 480 { 481 #if __GNUC__ != 2 482 return B_NOT_SUPPORTED; 483 #else 484 switch (op) { 485 case B_MODULE_INIT: 486 case B_MODULE_UNINIT: 487 return B_OK; 488 } 489 490 return B_BAD_VALUE; 491 #endif 492 } 493 494 495 static struct debugger_demangle_module_info sModuleInfo = { 496 { 497 "debugger/demangle/gcc2/v1", 498 0, 499 std_ops 500 }, 501 502 demangle_symbol, 503 get_next_argument, 504 }; 505 506 module_info *modules[] = { 507 (module_info *)&sModuleInfo, 508 NULL 509 }; 510 511