[llvm-commits] [compiler-rt] r159652 - in /compiler-rt/trunk/lib: asan/asan_stack.cc sanitizer_common/sanitizer_common.h sanitizer_common/sanitizer_linux.cc sanitizer_common/sanitizer_mac.cc sanitizer_common/sanitizer_posix.cc sanitizer_common/sanitizer_procmaps.h sanitizer_common/sanitizer_symbolizer.cc sanitizer_common/sanitizer_symbolizer.h sanitizer_common/sanitizer_win.cc

Alexey Samsonov samsonov at google.com
Tue Jul 3 01:24:14 PDT 2012


Author: samsonov
Date: Tue Jul  3 03:24:14 2012
New Revision: 159652

URL: http://llvm.org/viewvc/llvm-project?rev=159652&view=rev
Log:
[Sanitizer] Extend a symbolizer code. Implemented for Linux only. Use dl_iterate_phdr to get virtual addresses of mapped module sections. To symbolize an address from a module, map this module to memory and obtain pointers to debug info sections. Later these pointers can be passed to constructor of DWARF context-in-memory from LLVM DebugInfo lib.

Modified:
    compiler-rt/trunk/lib/asan/asan_stack.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc

Modified: compiler-rt/trunk/lib/asan/asan_stack.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_stack.cc?rev=159652&r1=159651&r2=159652&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_stack.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_stack.cc Tue Jul  3 03:24:14 2012
@@ -46,14 +46,20 @@
     AddressInfo addr_frames[64];
     uptr addr_frames_num = 0;
     if (FLAG_symbolize) {
-      addr_frames_num = SymbolizeCode(pc, addr_frames,
+      bool last_frame = (i == size - 1) || !addr[i + 1];
+      addr_frames_num = SymbolizeCode(pc - !last_frame, addr_frames,
                                       ASAN_ARRAY_SIZE(addr_frames));
     }
     if (addr_frames_num > 0) {
       for (uptr j = 0; j < addr_frames_num; j++) {
         AddressInfo &info = addr_frames[j];
         AsanPrintf("    #%zu 0x%zx", frame_num, pc);
-        if (info.module) {
+        if (info.function) {
+          AsanPrintf(" %s", info.function);
+        }
+        if (info.file) {
+          AsanPrintf(" %s:%d:%d", info.file, info.line, info.column);
+        } else if (info.module) {
           AsanPrintf(" (%s+0x%zx)", info.module, info.module_offset);
         }
         AsanPrintf("\n");

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h?rev=159652&r1=159651&r2=159652&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h Tue Jul  3 03:24:14 2012
@@ -64,6 +64,11 @@
 // Returns the number of read bytes or 0 if file can not be opened.
 uptr ReadFileToBuffer(const char *file_name, char **buff,
                       uptr *buff_size, uptr max_len);
+// Maps given file to virtual memory, and returns pointer to it
+// (or NULL if the mapping failes). Stores the size of mmaped region
+// in '*buff_size'.
+void *MapFileToMemory(const char *file_name, uptr *buff_size);
+
 const char *GetEnv(const char *name);
 const char *GetPwd();
 

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc?rev=159652&r1=159651&r2=159652&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc Tue Jul  3 03:24:14 2012
@@ -16,9 +16,13 @@
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
+#include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
+#include "sanitizer_symbolizer.h"
 
+#include <elf.h>
 #include <fcntl.h>
+#include <link.h>
 #include <pthread.h>
 #include <sched.h>
 #include <sys/mman.h>
@@ -63,9 +67,15 @@
 }
 
 uptr internal_filesize(fd_t fd) {
-  struct stat st = {};
+#if __WORDSIZE == 64
+  struct stat st;
   if (syscall(__NR_fstat, fd, &st))
     return -1;
+#else
+  struct stat64 st;
+  if (syscall(__NR_fstat64, fd, &st))
+    return -1;
+#endif
   return (uptr)st.st_size;
 }
 
@@ -153,6 +163,81 @@
   return 0;  // Not found.
 }
 
+// ------------------ sanitizer_symbolizer.h
+typedef ElfW(Ehdr) Elf_Ehdr;
+typedef ElfW(Shdr) Elf_Shdr;
+
+bool FindDWARFSection(uptr object_file_addr, const char *section_name,
+                      DWARFSection *section) {
+  Elf_Ehdr *exe = (Elf_Ehdr*)object_file_addr;
+  Elf_Shdr *sections = (Elf_Shdr*)(object_file_addr + exe->e_shoff);
+  uptr section_names = object_file_addr +
+                       sections[exe->e_shstrndx].sh_offset;
+  for (int i = 0; i < exe->e_shnum; i++) {
+    Elf_Shdr *current_section = &sections[i];
+    const char *current_name = (const char*)section_names +
+                               current_section->sh_name;
+    if (IsFullNameOfDWARFSection(current_name, section_name)) {
+      section->data = (const char*)object_file_addr +
+                      current_section->sh_offset;
+      section->size = current_section->sh_size;
+      return true;
+    }
+  }
+  return false;
+}
+
+#ifdef ANDROID
+uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules) {
+  UNIMPLEMENTED();
+}
+#else  // ANDROID
+struct DlIteratePhdrData {
+  ModuleDIContext *modules;
+  uptr current_n;
+  uptr max_n;
+};
+
+static const uptr kMaxPathLength = 512;
+
+static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
+  DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
+  if (data->current_n == data->max_n)
+    return 0;
+  char *module_name = 0;
+  if (data->current_n == 0) {
+    // First module is the binary itself.
+    module_name = (char*)InternalAlloc(kMaxPathLength);
+    uptr module_name_len = readlink("/proc/self/exe",
+                                    module_name, kMaxPathLength);
+    CHECK_NE(module_name_len, (uptr)-1);
+    CHECK_LT(module_name_len, kMaxPathLength);
+    module_name[module_name_len] = '\0';
+  } else if (info->dlpi_name) {
+    module_name = internal_strdup(info->dlpi_name);
+  }
+  if (module_name == 0 || module_name[0] == '\0')
+    return 0;
+  void *mem = &data->modules[data->current_n];
+  ModuleDIContext *cur_module = new(mem) ModuleDIContext(module_name);
+  data->current_n++;
+  for (int i = 0; i < info->dlpi_phnum; i++) {
+    uptr cur_beg = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
+    uptr cur_end = cur_beg + info->dlpi_phdr[i].p_memsz;
+    cur_module->addAddressRange(cur_beg, cur_end);
+  }
+  InternalFree(module_name);
+  return 0;
+}
+
+uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules) {
+  CHECK(modules);
+  DlIteratePhdrData data = {modules, 0, max_modules};
+  dl_iterate_phdr(dl_iterate_phdr_cb, &data);
+  return data.current_n;
+}
+#endif  // ANDROID
+
 // ----------------- sanitizer_procmaps.h
 ProcessMaps::ProcessMaps() {
   proc_self_maps_buff_len_ =

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc?rev=159652&r1=159651&r2=159652&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc Tue Jul  3 03:24:14 2012
@@ -18,6 +18,7 @@
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_procmaps.h"
+#include "sanitizer_symbolizer.h"
 
 #include <crt_externs.h>  // for _NSGetEnviron
 #include <fcntl.h>
@@ -106,6 +107,17 @@
   return 0;
 }
 
+// ------------------ sanitizer_symbolizer.h
+bool FindDWARFSection(uptr object_file_addr, const char *section_name,
+                      DWARFSection *section) {
+  UNIMPLEMENTED();
+  return false;
+}
+
+uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules) {
+  UNIMPLEMENTED();
+};
+
 // ----------------- sanitizer_procmaps.h
 
 ProcessMaps::ProcessMaps() {

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc?rev=159652&r1=159651&r2=159652&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc Tue Jul  3 03:24:14 2012
@@ -76,6 +76,18 @@
                        -1, 0);
 }
 
+void *MapFileToMemory(const char *file_name, uptr *buff_size) {
+  fd_t fd = internal_open(file_name, false);
+  CHECK_NE(fd, kInvalidFd);
+  uptr fsize = internal_filesize(fd);
+  CHECK_NE(fsize, (uptr)-1);
+  CHECK_GT(fsize, 0);
+  *buff_size = RoundUpTo(fsize, kPageSize);
+  void *map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
+  return (map == MAP_FAILED) ? 0 : map;
+}
+
+
 static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
                                         uptr start2, uptr end2) {
   CHECK(start1 <= end1);

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps.h?rev=159652&r1=159651&r2=159652&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps.h Tue Jul  3 03:24:14 2012
@@ -41,7 +41,17 @@
     for (int i = 0; Next(&start, &end, &file_offset, filename, filename_size);
          i++) {
       if (addr >= start && addr < end) {
-        // Don't subtract 'start' for the first entry. Don't ask me why.
+        // Don't subtract 'start' for the first entry:
+        // * If a binary is compiled w/o -pie, then the first entry in
+        //   process maps is likely the binary itself (all dynamic libs
+        //   are mapped higher in address space). For such a binary,
+        //   instruction offset in binary coincides with the actual
+        //   instruction address in virtual memory (as code section
+        //   is mapped to a fixed memory range).
+        // * If a binary is compiled with -pie, all the modules are
+        //   mapped high at address space (in particular, higher than
+        //   shadow memory of the tool), so the module can't be the
+        //   first entry.
         *offset = (addr - (i ? start : 0)) + file_offset;
         return true;
       }

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.cc?rev=159652&r1=159651&r2=159652&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.cc Tue Jul  3 03:24:14 2012
@@ -19,6 +19,18 @@
 
 namespace __sanitizer {
 
+bool IsFullNameOfDWARFSection(const char *full_name, const char *short_name) {
+  // Skip "__DWARF," prefix.
+  if (0 == internal_strncmp(full_name, "__DWARF,", 8)) {
+    full_name += 8;
+  }
+  // Skip . and _ prefices.
+  while (*full_name == '.' || *full_name == '_') {
+    full_name++;
+  }
+  return 0 == internal_strcmp(full_name, short_name);
+}
+
 void AddressInfo::Clear() {
   InternalFree(module);
   InternalFree(function);
@@ -26,97 +38,105 @@
   internal_memset(this, 0, sizeof(AddressInfo));
 }
 
-static const int kMaxModuleNameLength = 4096;
+ModuleDIContext::ModuleDIContext(const char *module_name) {
+  full_name_ = internal_strdup(module_name);
+  short_name_ = internal_strrchr(module_name, '/');
+  if (short_name_ == 0) {
+    short_name_ = full_name_;
+  } else {
+    short_name_++;
+  }
+  base_address_ = (uptr)-1;
+  n_ranges_ = 0;
+  mapped_addr_ = 0;
+  mapped_size_ = 0;
+}
 
-struct ModuleDesc {
-  ModuleDesc *next;
-  uptr start;
-  uptr end;
-  uptr offset;
-  char *full_name;
-  char *name;
-
-  ModuleDesc(uptr _start, uptr _end, uptr _offset, const char *module_name) {
-    next = 0;
-    start = _start;
-    end = _end;
-    offset = _offset;
-    full_name = internal_strdup(module_name);
-    name = internal_strrchr(module_name, '/');
-    if (name == 0) {
-      name = full_name;
-    } else {
-      name++;
-    }
+void ModuleDIContext::addAddressRange(uptr beg, uptr end) {
+  CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
+  ranges_[n_ranges_].beg = beg;
+  ranges_[n_ranges_].end = end;
+  base_address_ = Min(base_address_, beg);
+  n_ranges_++;
+}
+
+bool ModuleDIContext::containsAddress(uptr address) const {
+  for (uptr i = 0; i < n_ranges_; i++) {
+    if (ranges_[i].beg <= address && address < ranges_[i].end)
+      return true;
   }
-};
+  return false;
+}
+
+void ModuleDIContext::getAddressInfo(AddressInfo *info) {
+  info->module = internal_strdup(full_name_);
+  info->module_offset = info->address - base_address_;
+  if (mapped_addr_ == 0)
+    CreateDIContext();
+  // FIXME: Use the actual debug info context here.
+  info->function = 0;
+  info->file = 0;
+  info->line = 0;
+  info->column = 0;
+}
+
+void ModuleDIContext::CreateDIContext() {
+  mapped_addr_ = (uptr)MapFileToMemory(full_name_, &mapped_size_);
+  CHECK(mapped_addr_);
+  DWARFSection debug_info;
+  DWARFSection debug_abbrev;
+  DWARFSection debug_line;
+  DWARFSection debug_aranges;
+  DWARFSection debug_str;
+  FindDWARFSection(mapped_addr_, "debug_info", &debug_info);
+  FindDWARFSection(mapped_addr_, "debug_abbrev", &debug_abbrev);
+  FindDWARFSection(mapped_addr_, "debug_line", &debug_line);
+  FindDWARFSection(mapped_addr_, "debug_aranges", &debug_aranges);
+  FindDWARFSection(mapped_addr_, "debug_str", &debug_str);
+  // FIXME: Construct actual debug info context using mapped_addr,
+  // mapped_size and pointers to DWARF sections in memory.
+}
 
 class Symbolizer {
  public:
-  void GetModuleDescriptions() {
-    ProcessMaps proc_maps;
-    uptr start, end, offset;
-    char *module_name = (char*)InternalAlloc(kMaxModuleNameLength);
-    ModuleDesc *prev_module = 0;
-    while (proc_maps.Next(&start, &end, &offset, module_name,
-                          kMaxModuleNameLength)) {
-      void *mem = InternalAlloc(sizeof(ModuleDesc));
-      ModuleDesc *cur_module = new(mem) ModuleDesc(start, end, offset,
-                                                   module_name);
-      if (!prev_module) {
-        modules_ = cur_module;
-      } else {
-        prev_module->next = cur_module;
-      }
-      prev_module = cur_module;
-    }
-    InternalFree(module_name);
-  }
-
   uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
     if (max_frames == 0)
       return 0;
     AddressInfo *info = &frames[0];
     info->Clear();
     info->address = addr;
+    ModuleDIContext *module = FindModuleForAddress(addr);
+    if (module) {
+      module->getAddressInfo(info);
+      return 1;
+    }
+    return 0;
+  }
+
+ private:
+  ModuleDIContext *FindModuleForAddress(uptr address) {
     if (modules_ == 0) {
-      GetModuleDescriptions();
+      modules_ = (ModuleDIContext*)InternalAlloc(
+          kMaxNumberOfModuleContexts * sizeof(ModuleDIContext));
+      CHECK(modules_);
+      n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts);
+      CHECK_GT(n_modules_, 0);
+      CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
     }
-    bool first = true;
-    for (ModuleDesc *module = modules_; module; module = module->next) {
-      if (addr >= module->start && addr < module->end) {
-        info->module = internal_strdup(module->full_name);
-        // Don't subtract 'start' for the first entry:
-        // * If a binary is compiled w/o -pie, then the first entry in
-        //   process maps is likely the binary itself (all dynamic libs
-        //   are mapped higher in address space). For such a binary,
-        //   instruction offset in binary coincides with the actual
-        //   instruction address in virtual memory (as code section
-        //   is mapped to a fixed memory range).
-        // * If a binary is compiled with -pie, all the modules are
-        //   mapped high at address space (in particular, higher than
-        //   shadow memory of the tool), so the module can't be the
-        //   first entry.
-        info->module_offset = (addr - (first ? 0 : module->start)) +
-                              module->offset;
-        // FIXME: Fill other fields here as well: create debug
-        // context for a given module and fetch file/line info from it.
-        info->function = 0;
-        info->file = 0;
-        info->line = 0;
-        info->column = 0;
-        return 1;
+    for (uptr i = 0; i < n_modules_; i++) {
+      if (modules_[i].containsAddress(address)) {
+        return &modules_[i];
       }
-      first = false;
     }
     return 0;
   }
-
- private:
-  ModuleDesc *modules_;  // List of module descriptions is leaked.
+  static const uptr kMaxNumberOfModuleContexts = 256;
+  // Array of module debug info contexts is leaked.
+  ModuleDIContext *modules_;
+  uptr n_modules_;
 };
 
-static Symbolizer symbolizer;
+static Symbolizer symbolizer;  // Linker initialized.
 
 uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames) {
   return symbolizer.SymbolizeCode(address, frames, max_frames);

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.h?rev=159652&r1=159651&r2=159652&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_symbolizer.h Tue Jul  3 03:24:14 2012
@@ -52,6 +52,45 @@
 // This function should NOT be called from two threads simultaneously.
 uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames);
 
+// Debug info routines
+struct DWARFSection {
+  const char *data;
+  uptr size;
+};
+// Returns true on success.
+bool FindDWARFSection(uptr object_file_addr, const char *section_name,
+                      DWARFSection *section);
+bool IsFullNameOfDWARFSection(const char *full_name, const char *short_name);
+
+class ModuleDIContext {
+ public:
+  explicit ModuleDIContext(const char *module_name);
+  void addAddressRange(uptr beg, uptr end);
+  bool containsAddress(uptr address) const;
+  void getAddressInfo(AddressInfo *info);
+
+  const char *full_name() const { return full_name_; }
+
+ private:
+  void CreateDIContext();
+
+  struct AddressRange {
+    uptr beg;
+    uptr end;
+  };
+  char *full_name_;
+  char *short_name_;
+  uptr base_address_;
+  static const uptr kMaxNumberOfAddressRanges = 16;
+  AddressRange ranges_[kMaxNumberOfAddressRanges];
+  uptr n_ranges_;
+  uptr mapped_addr_;
+  uptr mapped_size_;
+};
+
+// OS-dependent function that gets the linked list of all loaded modules.
+uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules);
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_SYMBOLIZER_H

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc?rev=159652&r1=159651&r2=159652&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc Tue Jul  3 03:24:14 2012
@@ -16,6 +16,7 @@
 
 #include "sanitizer_common.h"
 #include "sanitizer_libc.h"
+#include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
@@ -75,6 +76,10 @@
   return true;
 }
 
+void *MapFileToMemory(const char *file_name, uptr *buff_size) {
+  UNIMPLEMENTED();
+}
+
 const char *GetEnv(const char *name) {
   static char env_buffer[32767] = {};
 
@@ -125,6 +130,17 @@
   return atexit(function);
 }
 
+// ------------------ sanitizer_symbolizer.h
+bool FindDWARFSection(uptr object_file_addr, const char *section_name,
+                      DWARFSection *section) {
+  UNIMPLEMENTED();
+  return false;
+}
+
+uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules) {
+  UNIMPLEMENTED();
+};
+
 // ------------------ sanitizer_libc.h
 void *internal_mmap(void *addr, uptr length, int prot, int flags,
                     int fd, u64 offset) {





More information about the llvm-commits mailing list