Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: base/third_party/symbolize/symbolize.cc

Issue 180163013: Copying the following files AS-IS from google.glog r141: (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/third_party/symbolize/symbolize.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006, Google Inc. 1 // Copyright (c) 2006, Google Inc.
2 // All rights reserved. 2 // All rights reserved.
3 // 3 //
4 // Redistribution and use in source and binary forms, with or without 4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are 5 // modification, are permitted provided that the following conditions are
6 // met: 6 // met:
7 // 7 //
8 // * Redistributions of source code must retain the above copyright 8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer. 9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above 10 // * Redistributions in binary form must reproduce the above
(...skipping 27 matching lines...) Expand all
38 // Here are some numbers collected with GCC 4.1.0 on x86: 38 // Here are some numbers collected with GCC 4.1.0 on x86:
39 // - sizeof(Elf32_Sym) = 16 39 // - sizeof(Elf32_Sym) = 16
40 // - sizeof(Elf32_Shdr) = 40 40 // - sizeof(Elf32_Shdr) = 40
41 // - sizeof(Elf64_Sym) = 24 41 // - sizeof(Elf64_Sym) = 24
42 // - sizeof(Elf64_Shdr) = 64 42 // - sizeof(Elf64_Shdr) = 64
43 // 43 //
44 // This implementation is intended to be async-signal-safe but uses 44 // This implementation is intended to be async-signal-safe but uses
45 // some functions which are not guaranteed to be so, such as memchr() 45 // some functions which are not guaranteed to be so, such as memchr()
46 // and memmove(). We assume they are async-signal-safe. 46 // and memmove(). We assume they are async-signal-safe.
47 // 47 //
48 // Additional header can be specified by the GLOG_BUILD_CONFIG_INCLUDE
49 // macro to add platform specific defines (e.g. OS_OPENBSD).
48 50
49 #include "build/build_config.h" 51 #ifdef GLOG_BUILD_CONFIG_INCLUDE
52 #include GLOG_BUILD_CONFIG_INCLUDE
53 #endif // GLOG_BUILD_CONFIG_INCLUDE
54
50 #include "utilities.h" 55 #include "utilities.h"
51 56
52 #if defined(HAVE_SYMBOLIZE) 57 #if defined(HAVE_SYMBOLIZE)
53 58
54 #include <limits> 59 #include <limits>
55 60
56 #include "symbolize.h" 61 #include "symbolize.h"
57 #include "demangle.h" 62 #include "demangle.h"
58 63
59 _START_GOOGLE_NAMESPACE_ 64 _START_GOOGLE_NAMESPACE_
60 65
61 // We don't use assert() since it's not guaranteed to be 66 // We don't use assert() since it's not guaranteed to be
62 // async-signal-safe. Instead we define a minimal assertion 67 // async-signal-safe. Instead we define a minimal assertion
63 // macro. So far, we don't need pretty printing for __FILE__, etc. 68 // macro. So far, we don't need pretty printing for __FILE__, etc.
64 69
65 // A wrapper for abort() to make it callable in ? :. 70 // A wrapper for abort() to make it callable in ? :.
66 static int AssertFail() { 71 static int AssertFail() {
67 abort(); 72 abort();
68 return 0; // Should not reach. 73 return 0; // Should not reach.
69 } 74 }
70 75
71 #define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail()) 76 #define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
72 77
73 static SymbolizeCallback g_symbolize_callback = NULL; 78 static SymbolizeCallback g_symbolize_callback = NULL;
74 void InstallSymbolizeCallback(SymbolizeCallback callback) { 79 void InstallSymbolizeCallback(SymbolizeCallback callback) {
75 g_symbolize_callback = callback; 80 g_symbolize_callback = callback;
76 } 81 }
77 82
83 static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
84 NULL;
85 void InstallSymbolizeOpenObjectFileCallback(
86 SymbolizeOpenObjectFileCallback callback) {
87 g_symbolize_open_object_file_callback = callback;
88 }
89
78 // This function wraps the Demangle function to provide an interface 90 // This function wraps the Demangle function to provide an interface
79 // where the input symbol is demangled in-place. 91 // where the input symbol is demangled in-place.
80 // To keep stack consumption low, we would like this function to not 92 // To keep stack consumption low, we would like this function to not
81 // get inlined. 93 // get inlined.
82 static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) { 94 static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
83 char demangled[256]; // Big enough for sane demangled symbols. 95 char demangled[256]; // Big enough for sane demangled symbols.
84 if (Demangle(out, demangled, sizeof(demangled))) { 96 if (Demangle(out, demangled, sizeof(demangled))) {
85 // Demangling succeeded. Copy to out if the space allows. 97 // Demangling succeeded. Copy to out if the space allows.
86 int len = strlen(demangled); 98 size_t len = strlen(demangled);
87 if (len + 1 <= out_size) { // +1 for '\0'. 99 if (len + 1 <= (size_t)out_size) { // +1 for '\0'.
88 SAFE_ASSERT(len < sizeof(demangled)); 100 SAFE_ASSERT(len < sizeof(demangled));
89 memmove(out, demangled, len + 1); 101 memmove(out, demangled, len + 1);
90 } 102 }
91 } 103 }
92 } 104 }
93 105
94 _END_GOOGLE_NAMESPACE_ 106 _END_GOOGLE_NAMESPACE_
95 107
96 #if defined(__ELF__) 108 #if defined(__ELF__)
97 109
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after
476 (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) { 488 (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
477 *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9); 489 *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
478 } else { // Encountered the first non-hex character. 490 } else { // Encountered the first non-hex character.
479 break; 491 break;
480 } 492 }
481 } 493 }
482 SAFE_ASSERT(p <= end); 494 SAFE_ASSERT(p <= end);
483 return const_cast<char *>(p); 495 return const_cast<char *>(p);
484 } 496 }
485 497
486 // Search for the object file (from /proc/self/maps) that contains 498 // Searches for the object file (from /proc/self/maps) that contains
487 // the specified pc. If found, open this file and return the file handle, 499 // the specified pc. If found, sets |start_address| to the start address
488 // and also set start_address to the start address of where this object 500 // of where this object file is mapped in memory, sets the module base
489 // file is mapped to in memory. Otherwise, return -1. 501 // address into |base_address|, copies the object file name into
502 // |out_file_name|, and attempts to open the object file. If the object
503 // file is opened successfully, returns the file descriptor. Otherwise,
504 // returns -1. |out_file_name_size| is the size of the file name buffer
505 // (including the null-terminator).
490 static ATTRIBUTE_NOINLINE int 506 static ATTRIBUTE_NOINLINE int
491 OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, 507 OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
492 uint64_t &start_address) { 508 uint64_t &start_address,
509 uint64_t &base_address,
510 char *out_file_name,
511 int out_file_name_size) {
493 int object_fd; 512 int object_fd;
494 513
495 // Open /proc/self/maps. 514 // Open /proc/self/maps.
496 int maps_fd; 515 int maps_fd;
497 NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY)); 516 NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
498 FileDescriptor wrapped_maps_fd(maps_fd); 517 FileDescriptor wrapped_maps_fd(maps_fd);
499 if (wrapped_maps_fd.get() < 0) { 518 if (wrapped_maps_fd.get() < 0) {
500 return -1; 519 return -1;
501 } 520 }
502 521
503 // Iterate over maps and look for the map containing the pc. Then 522 // Iterate over maps and look for the map containing the pc. Then
504 // look into the symbol tables inside. 523 // look into the symbol tables inside.
505 char buf[1024]; // Big enough for line of sane /proc/self/maps 524 char buf[1024]; // Big enough for line of sane /proc/self/maps
525 int num_maps = 0;
506 LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf)); 526 LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
507 while (true) { 527 while (true) {
528 num_maps++;
508 const char *cursor; 529 const char *cursor;
509 const char *eol; 530 const char *eol;
510 if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line. 531 if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
511 return -1; 532 return -1;
512 } 533 }
513 534
514 // Start parsing line in /proc/self/maps. Here is an example: 535 // Start parsing line in /proc/self/maps. Here is an example:
515 // 536 //
516 // 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat 537 // 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat
517 // 538 //
(...skipping 29 matching lines...) Expand all
547 if (cursor == eol || cursor < flags_start + 4) { 568 if (cursor == eol || cursor < flags_start + 4) {
548 return -1; // Malformed line. 569 return -1; // Malformed line.
549 } 570 }
550 571
551 // Check flags. We are only interested in "r-x" maps. 572 // Check flags. We are only interested in "r-x" maps.
552 if (memcmp(flags_start, "r-x", 3) != 0) { // Not a "r-x" map. 573 if (memcmp(flags_start, "r-x", 3) != 0) { // Not a "r-x" map.
553 continue; // We skip this map. 574 continue; // We skip this map.
554 } 575 }
555 ++cursor; // Skip ' '. 576 ++cursor; // Skip ' '.
556 577
557 // Skip to file name. "cursor" now points to file offset. We need to 578 // Read file offset.
558 // skip at least three spaces for file offset, dev, and inode. 579 uint64_t file_offset;
580 cursor = GetHex(cursor, eol, &file_offset);
581 if (cursor == eol || *cursor != ' ') {
582 return -1; // Malformed line.
583 }
584 ++cursor; // Skip ' '.
585
586 // Don't subtract 'start_address' from the first entry:
587 // * If a binary is compiled w/o -pie, then the first entry in
588 // process maps is likely the binary itself (all dynamic libs
589 // are mapped higher in address space). For such a binary,
590 // instruction offset in binary coincides with the actual
591 // instruction address in virtual memory (as code section
592 // is mapped to a fixed memory range).
593 // * If a binary is compiled with -pie, all the modules are
594 // mapped high at address space (in particular, higher than
595 // shadow memory of the tool), so the module can't be the
596 // first entry.
597 base_address = ((num_maps == 1) ? 0U : start_address) - file_offset;
598
599 // Skip to file name. "cursor" now points to dev. We need to
600 // skip at least two spaces for dev and inode.
559 int num_spaces = 0; 601 int num_spaces = 0;
560 while (cursor < eol) { 602 while (cursor < eol) {
561 if (*cursor == ' ') { 603 if (*cursor == ' ') {
562 ++num_spaces; 604 ++num_spaces;
563 } else if (num_spaces >= 3) { 605 } else if (num_spaces >= 2) {
564 // The first non-space character after skipping three spaces 606 // The first non-space character after skipping two spaces
565 // is the beginning of the file name. 607 // is the beginning of the file name.
566 break; 608 break;
567 } 609 }
568 ++cursor; 610 ++cursor;
569 } 611 }
570 if (cursor == eol) { 612 if (cursor == eol) {
571 return -1; // Malformed line. 613 return -1; // Malformed line.
572 } 614 }
573 615
574 // Finally, "cursor" now points to file name of our interest. 616 // Finally, "cursor" now points to file name of our interest.
575 NO_INTR(object_fd = open(cursor, O_RDONLY)); 617 NO_INTR(object_fd = open(cursor, O_RDONLY));
576 if (object_fd < 0) { 618 if (object_fd < 0) {
619 // Failed to open object file. Copy the object file name to
620 // |out_file_name|.
621 strncpy(out_file_name, cursor, out_file_name_size);
622 // Making sure |out_file_name| is always null-terminated.
623 out_file_name[out_file_name_size - 1] = '\0';
577 return -1; 624 return -1;
578 } 625 }
579 return object_fd; 626 return object_fd;
580 } 627 }
581 } 628 }
582 629
630 // POSIX doesn't define any async-signal safe function for converting
631 // an integer to ASCII. We'll have to define our own version.
632 // itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
633 // conversion was successful or NULL otherwise. It never writes more than "sz"
634 // bytes. Output will be truncated as needed, and a NUL character is always
635 // appended.
636 // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
637 char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
638 // Make sure we can write at least one NUL byte.
639 size_t n = 1;
640 if (n > sz)
641 return NULL;
642
643 if (base < 2 || base > 16) {
644 buf[0] = '\000';
645 return NULL;
646 }
647
648 char *start = buf;
649
650 uintptr_t j = i;
651
652 // Handle negative numbers (only for base 10).
653 if (i < 0 && base == 10) {
654 j = -i;
655
656 // Make sure we can write the '-' character.
657 if (++n > sz) {
658 buf[0] = '\000';
659 return NULL;
660 }
661 *start++ = '-';
662 }
663
664 // Loop until we have converted the entire number. Output at least one
665 // character (i.e. '0').
666 char *ptr = start;
667 do {
668 // Make sure there is still enough space left in our output buffer.
669 if (++n > sz) {
670 buf[0] = '\000';
671 return NULL;
672 }
673
674 // Output the next digit.
675 *ptr++ = "0123456789abcdef"[j % base];
676 j /= base;
677
678 if (padding > 0)
679 padding--;
680 } while (j > 0 || padding > 0);
681
682 // Terminate the output with a NUL character.
683 *ptr = '\000';
684
685 // Conversion to ASCII actually resulted in the digits being in reverse
686 // order. We can't easily generate them in forward order, as we can't tell
687 // the number of characters needed until we are done converting.
688 // So, now, we reverse the string (except for the possible "-" sign).
689 while (--ptr > start) {
690 char ch = *ptr;
691 *ptr = *start;
692 *start++ = ch;
693 }
694 return buf;
695 }
696
697 // Safely appends string |source| to string |dest|. Never writes past the
698 // buffer size |dest_size| and guarantees that |dest| is null-terminated.
699 void SafeAppendString(const char* source, char* dest, int dest_size) {
700 int dest_string_length = strlen(dest);
701 SAFE_ASSERT(dest_string_length < dest_size);
702 dest += dest_string_length;
703 dest_size -= dest_string_length;
704 strncpy(dest, source, dest_size);
705 // Making sure |dest| is always null-terminated.
706 dest[dest_size - 1] = '\0';
707 }
708
709 // Converts a 64-bit value into a hex string, and safely appends it to |dest|.
710 // Never writes past the buffer size |dest_size| and guarantees that |dest| is
711 // null-terminated.
712 void SafeAppendHexNumber(uint64_t value, char* dest, int dest_size) {
713 // 64-bit numbers in hex can have up to 16 digits.
714 char buf[17] = {'\0'};
715 SafeAppendString(itoa_r(value, buf, sizeof(buf), 16, 0), dest, dest_size);
716 }
717
583 // The implementation of our symbolization routine. If it 718 // The implementation of our symbolization routine. If it
584 // successfully finds the symbol containing "pc" and obtains the 719 // successfully finds the symbol containing "pc" and obtains the
585 // symbol name, returns true and write the symbol name to "out". 720 // symbol name, returns true and write the symbol name to "out".
586 // Otherwise, returns false. If Callback function is installed via 721 // Otherwise, returns false. If Callback function is installed via
587 // InstallSymbolizeCallback(), the function is also called in this function, 722 // InstallSymbolizeCallback(), the function is also called in this function,
588 // and "out" is used as its output. 723 // and "out" is used as its output.
589 // To keep stack consumption low, we would like this function to not 724 // To keep stack consumption low, we would like this function to not
590 // get inlined. 725 // get inlined.
591 static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out, 726 static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
592 int out_size) { 727 int out_size) {
593 uint64_t pc0 = reinterpret_cast<uintptr_t>(pc); 728 uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
594 uint64_t start_address = 0; 729 uint64_t start_address = 0;
730 uint64_t base_address = 0;
731 int object_fd = -1;
595 732
596 int object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, 733 if (out_size < 1) {
597 start_address); 734 return false;
598 if (object_fd == -1) { 735 }
736 out[0] = '\0';
737 SafeAppendString("(", out, out_size);
738
739 if (g_symbolize_open_object_file_callback) {
740 object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
741 base_address, out + 1,
742 out_size - 1);
743 } else {
744 object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
745 base_address,
746 out + 1,
747 out_size - 1);
748 }
749
750 // Check whether a file name was returned.
751 if (object_fd < 0) {
752 if (out[1]) {
753 // The object file containing PC was determined successfully however the
754 // object file was not opened successfully. This is still considered
755 // success because the object file name and offset are known and tools
756 // like asan_symbolize.py can be used for the symbolization.
757 out[out_size - 1] = '\0'; // Making sure |out| is always null-terminated.
758 SafeAppendString("+0x", out, out_size);
759 SafeAppendHexNumber(pc0 - base_address, out, out_size);
760 SafeAppendString(")", out, out_size);
761 return true;
762 }
763 // Failed to determine the object file containing PC. Bail out.
599 return false; 764 return false;
600 } 765 }
601 FileDescriptor wrapped_object_fd(object_fd); 766 FileDescriptor wrapped_object_fd(object_fd);
602 int elf_type = FileGetElfType(wrapped_object_fd.get()); 767 int elf_type = FileGetElfType(wrapped_object_fd.get());
603 if (elf_type == -1) { 768 if (elf_type == -1) {
604 return false; 769 return false;
605 } 770 }
606 if (g_symbolize_callback) { 771 if (g_symbolize_callback) {
607 // Run the call back if it's installed. 772 // Run the call back if it's installed.
608 // Note: relocation (and much of the rest of this code) will be 773 // Note: relocation (and much of the rest of this code) will be
(...skipping 23 matching lines...) Expand all
632 797
633 #include <dlfcn.h> 798 #include <dlfcn.h>
634 #include <string.h> 799 #include <string.h>
635 800
636 _START_GOOGLE_NAMESPACE_ 801 _START_GOOGLE_NAMESPACE_
637 802
638 static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out, 803 static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
639 int out_size) { 804 int out_size) {
640 Dl_info info; 805 Dl_info info;
641 if (dladdr(pc, &info)) { 806 if (dladdr(pc, &info)) {
642 if (strlen(info.dli_sname) < out_size) { 807 if ((int)strlen(info.dli_sname) < out_size) {
643 strcpy(out, info.dli_sname); 808 strcpy(out, info.dli_sname);
644 // Symbolization succeeded. Now we try to demangle the symbol. 809 // Symbolization succeeded. Now we try to demangle the symbol.
645 DemangleInplace(out, out_size); 810 DemangleInplace(out, out_size);
646 return true; 811 return true;
647 } 812 }
648 } 813 }
649 return false; 814 return false;
650 } 815 }
651 816
652 _END_GOOGLE_NAMESPACE_ 817 _END_GOOGLE_NAMESPACE_
(...skipping 21 matching lines...) Expand all
674 839
675 // TODO: Support other environments. 840 // TODO: Support other environments.
676 bool Symbolize(void *pc, char *out, int out_size) { 841 bool Symbolize(void *pc, char *out, int out_size) {
677 assert(0); 842 assert(0);
678 return false; 843 return false;
679 } 844 }
680 845
681 _END_GOOGLE_NAMESPACE_ 846 _END_GOOGLE_NAMESPACE_
682 847
683 #endif 848 #endif
OLDNEW
« no previous file with comments | « base/third_party/symbolize/symbolize.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698