| | 266 | |
|---|
| | 267 | #if defined(VPR_OS_Darwin) |
|---|
| | 268 | struct CrawlFrame |
|---|
| | 269 | { |
|---|
| | 270 | unsigned int pc; |
|---|
| | 271 | size_t frame; |
|---|
| | 272 | std::string name; |
|---|
| | 273 | unsigned int offset; |
|---|
| | 274 | }; |
|---|
| | 275 | |
|---|
| | 276 | const mach_header* findOwnerOfPC(const unsigned int pc) |
|---|
| | 277 | { |
|---|
| | 278 | const unsigned int count = _dyld_image_count(); |
|---|
| | 279 | for ( unsigned int index = 0; index < count; ++index ) |
|---|
| | 280 | { |
|---|
| | 281 | const mach_header* header = _dyld_get_image_header(index); |
|---|
| | 282 | const unsigned int offset = _dyld_get_image_vmaddr_slide(index); |
|---|
| | 283 | const load_command* cmd = |
|---|
| | 284 | reinterpret_cast<const load_command*>( |
|---|
| | 285 | reinterpret_cast<const char*>(header) + sizeof(mach_header) |
|---|
| | 286 | ); |
|---|
| | 287 | |
|---|
| | 288 | for ( unsigned int cmdex = 0; |
|---|
| | 289 | cmdex < header->ncmds; |
|---|
| | 290 | ++cmdex, cmd = reinterpret_cast<const load_command*>(reinterpret_cast<const char*>(cmd) + cmd->cmdsize)) |
|---|
| | 291 | { |
|---|
| | 292 | switch (cmd->cmd) |
|---|
| | 293 | { |
|---|
| | 294 | case LC_SEGMENT: |
|---|
| | 295 | { |
|---|
| | 296 | const segment_command* seg = |
|---|
| | 297 | reinterpret_cast<const segment_command*>(cmd); |
|---|
| | 298 | if ( pc >= (seg->vmaddr + offset) && |
|---|
| | 299 | pc < (seg->vmaddr + offset + seg->vmsize) ) |
|---|
| | 300 | { |
|---|
| | 301 | return header; |
|---|
| | 302 | } |
|---|
| | 303 | } |
|---|
| | 304 | break; |
|---|
| | 305 | } |
|---|
| | 306 | } |
|---|
| | 307 | } |
|---|
| | 308 | |
|---|
| | 309 | return NULL; |
|---|
| | 310 | } |
|---|
| | 311 | |
|---|
| | 312 | std::string getFunctionName(const unsigned int pc, unsigned int* offset) |
|---|
| | 313 | { |
|---|
| | 314 | const mach_header* header = findOwnerOfPC(pc); |
|---|
| | 315 | if ( header != NULL ) |
|---|
| | 316 | { |
|---|
| | 317 | const segment_command* seg_linkedit(NULL); |
|---|
| | 318 | const segment_command* seg_text(NULL); |
|---|
| | 319 | const symtab_command* symtab(NULL); |
|---|
| | 320 | |
|---|
| | 321 | const load_command* cmd = |
|---|
| | 322 | reinterpret_cast<const load_command*>( |
|---|
| | 323 | reinterpret_cast<const char*>(header) + sizeof(mach_header) |
|---|
| | 324 | ); |
|---|
| | 325 | |
|---|
| | 326 | for ( unsigned int index = 0; |
|---|
| | 327 | index < header->ncmds; |
|---|
| | 328 | ++index, cmd = reinterpret_cast<const load_command*>(reinterpret_cast<const char*>(cmd) + cmd->cmdsize) ) |
|---|
| | 329 | { |
|---|
| | 330 | switch (cmd->cmd) |
|---|
| | 331 | { |
|---|
| | 332 | case LC_SEGMENT: |
|---|
| | 333 | if ( ! strncmp(reinterpret_cast<const segment_command*>(cmd)->segname, SEG_TEXT, 16) ) |
|---|
| | 334 | { |
|---|
| | 335 | seg_text = reinterpret_cast<const segment_command*>(cmd); |
|---|
| | 336 | } |
|---|
| | 337 | else if ( ! strncmp(reinterpret_cast<const segment_command*>(cmd)->segname, SEG_LINKEDIT, 16) ) |
|---|
| | 338 | { |
|---|
| | 339 | seg_linkedit = reinterpret_cast<const segment_command*>(cmd); |
|---|
| | 340 | } |
|---|
| | 341 | break; |
|---|
| | 342 | |
|---|
| | 343 | case LC_SYMTAB: |
|---|
| | 344 | symtab = reinterpret_cast<const symtab_command*>(cmd); |
|---|
| | 345 | break; |
|---|
| | 346 | } |
|---|
| | 347 | } |
|---|
| | 348 | |
|---|
| | 349 | if ( seg_text == NULL || seg_linkedit == NULL || symtab == NULL ) |
|---|
| | 350 | { |
|---|
| | 351 | *offset = 0; |
|---|
| | 352 | return NULL; |
|---|
| | 353 | } |
|---|
| | 354 | |
|---|
| | 355 | size_t vm_slide = reinterpret_cast<size_t>(header) - seg_text->vmaddr; |
|---|
| | 356 | const size_t file_slide = (seg_linkedit->vmaddr - seg_text->vmaddr) - |
|---|
| | 357 | seg_linkedit->fileoff; |
|---|
| | 358 | struct nlist* symbase = |
|---|
| | 359 | reinterpret_cast<struct nlist*>( |
|---|
| | 360 | reinterpret_cast<size_t>(header) + symtab->symoff + file_slide |
|---|
| | 361 | ); |
|---|
| | 362 | char* strings = |
|---|
| | 363 | reinterpret_cast<char*>( |
|---|
| | 364 | reinterpret_cast<size_t>(header) + symtab->stroff + file_slide |
|---|
| | 365 | ); |
|---|
| | 366 | |
|---|
| | 367 | // Look for a global symbol. |
|---|
| | 368 | unsigned int index; |
|---|
| | 369 | struct nlist* sym(NULL); |
|---|
| | 370 | for ( index = 0, sym = symbase; index < symtab->nsyms; ++index, ++sym ) |
|---|
| | 371 | { |
|---|
| | 372 | if ( sym->n_type != N_FUN ) |
|---|
| | 373 | { |
|---|
| | 374 | continue; |
|---|
| | 375 | } |
|---|
| | 376 | |
|---|
| | 377 | char* name = sym->n_un.n_strx ? (strings + sym->n_un.n_strx) : NULL; |
|---|
| | 378 | const unsigned int base = sym->n_value + vm_slide; |
|---|
| | 379 | |
|---|
| | 380 | for ( index += 1, sym += 1; index < symtab->nsyms; ++index, ++sym ) |
|---|
| | 381 | { |
|---|
| | 382 | if ( sym->n_type == N_FUN ) |
|---|
| | 383 | { |
|---|
| | 384 | break; |
|---|
| | 385 | } |
|---|
| | 386 | } |
|---|
| | 387 | |
|---|
| | 388 | if ( pc >= base && pc <= (base + sym->n_value) && name != NULL && |
|---|
| | 389 | std::strlen(name) > 0 ) |
|---|
| | 390 | { |
|---|
| | 391 | *offset = pc - base; |
|---|
| | 392 | return std::string(name); |
|---|
| | 393 | } |
|---|
| | 394 | } |
|---|
| | 395 | |
|---|
| | 396 | // Look for a reasonably close private symbol. |
|---|
| | 397 | char* name; |
|---|
| | 398 | unsigned int base; |
|---|
| | 399 | for ( name = NULL, base = 0xFFFFFFFF, index = 0, sym = symbase; |
|---|
| | 400 | index < symtab->nsyms; |
|---|
| | 401 | ++index, ++sym ) |
|---|
| | 402 | { |
|---|
| | 403 | if ( (sym->n_type & 0x0E) != 0x0E ) |
|---|
| | 404 | { |
|---|
| | 405 | continue; |
|---|
| | 406 | } |
|---|
| | 407 | |
|---|
| | 408 | if ( (sym->n_value + vm_slide) > pc ) |
|---|
| | 409 | { |
|---|
| | 410 | continue; |
|---|
| | 411 | } |
|---|
| | 412 | |
|---|
| | 413 | if ( base != 0xFFFFFFFF && |
|---|
| | 414 | (pc - (sym->n_value + vm_slide)) >= (pc - base) ) |
|---|
| | 415 | { |
|---|
| | 416 | continue; |
|---|
| | 417 | } |
|---|
| | 418 | |
|---|
| | 419 | name = sym->n_un.n_strx ? (strings + sym->n_un.n_strx) : NULL; |
|---|
| | 420 | base = sym->n_value + vm_slide; |
|---|
| | 421 | } |
|---|
| | 422 | |
|---|
| | 423 | *offset = pc - base; |
|---|
| | 424 | return (name != NULL) ? std::string(name) : std::string(); |
|---|
| | 425 | } |
|---|
| | 426 | |
|---|
| | 427 | *offset = 0; |
|---|
| | 428 | return std::string(); |
|---|
| | 429 | } |
|---|
| | 430 | #endif /* VPR_OS_Darwin */ |
|---|
| | 459 | |
|---|
| | 460 | ret_stack = trace_stream.str(); |
|---|
| | 461 | #elif defined(VPR_OS_Darwin) |
|---|
| | 462 | #if defined(__ppc__) || defined(__ppc64__) |
|---|
| | 463 | struct StackFrame |
|---|
| | 464 | { |
|---|
| | 465 | unsigned int savedSP; |
|---|
| | 466 | unsigned int savedCR; |
|---|
| | 467 | unsigned int savedLR; |
|---|
| | 468 | unsigned int reserved[2]; |
|---|
| | 469 | unsigned int savedRTOC; |
|---|
| | 470 | }; |
|---|
| | 471 | #elif defined(__i386__) |
|---|
| | 472 | struct StackFrame |
|---|
| | 473 | { |
|---|
| | 474 | unsigned int savedSP; |
|---|
| | 475 | unsigned int savedLR; |
|---|
| | 476 | }; |
|---|
| | 477 | #else |
|---|
| | 478 | #error Unknown platform |
|---|
| | 479 | #endif |
|---|
| | 480 | |
|---|
| | 481 | std::ostringstream trace_stream; |
|---|
| | 482 | trace_stream << "Stack trace for process: " << getpid() << std::endl; |
|---|
| | 483 | |
|---|
| | 484 | std::vector<CrawlFrame> stack; |
|---|
| | 485 | StackFrame* frame(NULL); |
|---|
| | 486 | |
|---|
| | 487 | #if defined(__ppc__) || defined(__ppc64__) |
|---|
| | 488 | frame = *(StackFrame**) __builtin_frame_address(0); |
|---|
| | 489 | #elif defined(__i386__) |
|---|
| | 490 | frame = (StackFrame*) __builtin_frame_address(0); |
|---|
| | 491 | #endif |
|---|
| | 492 | |
|---|
| | 493 | for ( ; frame != NULL; frame = (StackFrame*) frame->savedSP) |
|---|
| | 494 | { |
|---|
| | 495 | if ( (frame->savedLR & ~3) == 0 || (~(frame->savedLR) & ~3) == 0 ) |
|---|
| | 496 | { |
|---|
| | 497 | break; |
|---|
| | 498 | } |
|---|
| | 499 | |
|---|
| | 500 | CrawlFrame cur_frame; |
|---|
| | 501 | cur_frame.pc = frame->savedLR; |
|---|
| | 502 | cur_frame.frame = reinterpret_cast<size_t>(frame); |
|---|
| | 503 | cur_frame.name = getFunctionName(frame->savedLR, &cur_frame.offset); |
|---|
| | 504 | |
|---|
| | 505 | if ( cur_frame.pc != 0 ) |
|---|
| | 506 | { |
|---|
| | 507 | cur_frame.pc -= 4; |
|---|
| | 508 | } |
|---|
| | 509 | |
|---|
| | 510 | stack.push_back(cur_frame); |
|---|
| | 511 | } |
|---|
| | 512 | |
|---|
| | 513 | typedef std::vector<CrawlFrame>::reverse_iterator iter_type; |
|---|
| | 514 | for ( iter_type i = stack.rbegin(); i != stack.rend(); ++i ) |
|---|
| | 515 | { |
|---|
| | 516 | std::string func_name("(unknown)"); |
|---|
| | 517 | |
|---|
| | 518 | if ( ! (*i).name.empty() ) |
|---|
| | 519 | { |
|---|
| | 520 | typedef std::string::size_type size_type; |
|---|
| | 521 | const size_type name_len((*i).name.size()); |
|---|
| | 522 | for ( size_type j = 0; j < name_len; ++j ) |
|---|
| | 523 | { |
|---|
| | 524 | bool objc(false); |
|---|
| | 525 | if ( j == 1 && (*i).name[j] == '[' ) |
|---|
| | 526 | { |
|---|
| | 527 | objc = true; |
|---|
| | 528 | } |
|---|
| | 529 | |
|---|
| | 530 | if ( objc && (*i).name[j] == ']' ) |
|---|
| | 531 | { |
|---|
| | 532 | objc = false; |
|---|
| | 533 | } |
|---|
| | 534 | |
|---|
| | 535 | if ( ! objc && (*i).name[j] == ':' ) |
|---|
| | 536 | { |
|---|
| | 537 | break; |
|---|
| | 538 | } |
|---|
| | 539 | } |
|---|
| | 540 | |
|---|
| | 541 | std::ostringstream func_stream; |
|---|
| | 542 | func_stream << (*i).name << "+" << std::hex << (*i).offset; |
|---|
| | 543 | func_name = func_stream.str(); |
|---|
| | 544 | } |
|---|
| | 545 | |
|---|
| | 546 | const char fill_char(trace_stream.fill()); |
|---|
| | 547 | const std::ios::fmtflags fmt_flags(trace_stream.flags()); |
|---|
| | 548 | trace_stream.fill('0'); |
|---|
| | 549 | trace_stream.setf(std::ios::uppercase); |
|---|
| | 550 | trace_stream.setf(std::ios::hex | std::ios::right, |
|---|
| | 551 | std::ios::adjustfield | std::ios::basefield); |
|---|
| | 552 | trace_stream << " " << std::setw(sizeof(void*) * 2) << (*i).frame |
|---|
| | 553 | << " " << std::setw(sizeof(void*) * 2) << (*i).pc; |
|---|
| | 554 | trace_stream.flags(fmt_flags); |
|---|
| | 555 | trace_stream.fill(fill_char); |
|---|
| | 556 | trace_stream << " " << func_name << std::endl; |
|---|
| | 557 | } |
|---|