summaryrefslogtreecommitdiffstats
path: root/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cc
blob: d7bb65294ef4963c3255b022e1ccafdd7830d3d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//===-- sanitizer_symbolizer.cc -------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is a stub for LLVM-based symbolizer.
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries. See sanitizer.h for details.
//===----------------------------------------------------------------------===//

#include "sanitizer_common.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_symbolizer.h"

namespace __sanitizer {

void AddressInfo::Clear() {
  InternalFree(module);
  InternalFree(function);
  InternalFree(file);
  internal_memset(this, 0, sizeof(AddressInfo));
}

static const int kMaxModuleNameLength = 4096;

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++;
    }
  }
};

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;
    if (modules_ == 0) {
      GetModuleDescriptions();
    }
    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;
      }
      first = false;
    }
    return 0;
  }

 private:
  ModuleDesc *modules_;  // List of module descriptions is leaked.
};

static Symbolizer symbolizer;

uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames) {
  return symbolizer.SymbolizeCode(address, frames, max_frames);
}

}  // namespace __sanitizer
OpenPOWER on IntegriCloud