1/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file. */
4
5/* XRay symbol table */
6
7#define _GNU_SOURCE
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13#if defined(__GLIBC__)
14#include <dlfcn.h>
15#endif
16
17#include "xray/xray_priv.h"
18#define PNACL_STRING_OFFSET (0x10000000)
19
20#if defined(XRAY)
21
22bool g_symtable_debug = false;
23
24struct XRayFrameInfo {
25  int times_called;
26  int total_ticks;
27};
28
29
30struct XRaySymbol {
31  const char* name;
32  struct XRayFrameInfo frames[XRAY_MAX_FRAMES];
33};
34
35
36struct XRaySymbolPoolNode {
37  struct XRaySymbolPoolNode* next;
38  struct XRaySymbol symbols[XRAY_SYMBOL_POOL_NODE_SIZE];
39};
40
41
42struct XRaySymbolPool {
43  struct XRaySymbolPoolNode* head;
44  struct XRaySymbolPoolNode* current;
45  int index;
46};
47
48
49struct XRaySymbolTable {
50  int num_symbols;
51  struct XRayHashTable* hash_table;
52  struct XRayStringPool* string_pool;
53  struct XRaySymbolPool* symbol_pool;
54};
55
56
57const char* XRaySymbolGetName(struct XRaySymbol* symbol) {
58  return (NULL == symbol) ? "(null)" : symbol->name;
59}
60
61
62struct XRaySymbol* XRaySymbolCreate(struct XRaySymbolPool* sympool,
63                                    const char* name)
64{
65  struct XRaySymbol* symbol;
66  symbol = XRaySymbolPoolAlloc(sympool);
67  symbol->name = name;
68  return symbol;
69}
70
71
72struct XRaySymbol* XRaySymbolPoolAlloc(struct XRaySymbolPool* sympool) {
73  struct XRaySymbol* symbol;
74  if (sympool->index >= XRAY_SYMBOL_POOL_NODE_SIZE) {
75    struct XRaySymbolPoolNode* new_pool;
76    new_pool = (struct XRaySymbolPoolNode*)XRayMalloc(sizeof(*new_pool));
77    sympool->current->next = new_pool;
78    sympool->current = new_pool;
79    sympool->index = 0;
80  }
81  symbol = &sympool->current->symbols[sympool->index];
82  ++sympool->index;
83  return symbol;
84}
85
86
87struct XRaySymbolPool* XRaySymbolPoolCreate() {
88  struct XRaySymbolPool* sympool;
89  struct XRaySymbolPoolNode* node;
90  sympool = (struct XRaySymbolPool*)XRayMalloc(sizeof(*sympool));
91  node = (struct XRaySymbolPoolNode*)XRayMalloc(sizeof(*node));
92  sympool->head = node;
93  sympool->current = node;
94  sympool->index = 0;
95  return sympool;
96}
97
98
99void XRaySymbolPoolFree(struct XRaySymbolPool* pool) {
100  struct XRaySymbolPoolNode* n = pool->head;
101  while (NULL != n) {
102    struct XRaySymbolPoolNode* c = n;
103    n = n->next;
104    XRayFree(c);
105  }
106  XRayFree(pool);
107}
108
109
110int XRaySymbolTableGetCount(struct XRaySymbolTable* symtab) {
111  return XRayHashTableGetCount(symtab->hash_table);
112}
113
114
115struct XRaySymbol* XRaySymbolTableAtIndex(struct XRaySymbolTable* symtab,
116                                          int i) {
117  return (struct XRaySymbol*)XRayHashTableAtIndex(symtab->hash_table, i);
118}
119
120struct XRaySymbol* XRaySymbolTableAdd(struct XRaySymbolTable* symtab,
121                                      struct XRaySymbol* symbol,
122                                      uint32_t addr) {
123  struct XRaySymbol* sym = (struct XRaySymbol*)
124      XRayHashTableInsert(symtab->hash_table, symbol, addr);
125  symtab->num_symbols = XRayHashTableGetCount(symtab->hash_table);
126  return sym;
127}
128
129struct XRaySymbol* XRaySymbolTableAddByName(struct XRaySymbolTable* symtab,
130                                            const char* name, uint32_t addr) {
131  char* recorded_name;
132  struct XRaySymbol* symbol;
133  char buffer[XRAY_LINE_SIZE];
134  const char* demangled_name = XRayDemangle(buffer, XRAY_LINE_SIZE, name);
135  /* record the demangled symbol name into the string pool */
136  recorded_name = XRayStringPoolAppend(symtab->string_pool, demangled_name);
137  if (g_symtable_debug)
138    printf("adding symbol %s\n", recorded_name);
139  /* construct a symbol and put it in the symbol table */
140  symbol = XRaySymbolCreate(symtab->symbol_pool, recorded_name);
141  return XRaySymbolTableAdd(symtab, symbol, addr);
142}
143
144struct XRaySymbol* XRaySymbolTableLookup(struct XRaySymbolTable* symtab,
145                                         uint32_t addr) {
146  void *x = XRayHashTableLookup(symtab->hash_table, addr);
147  struct XRaySymbol* r = (struct XRaySymbol*)x;
148
149#if defined(__pnacl__)
150  if (r == NULL) {
151    /* Addresses are trimed to 24 bits for internal storage, so we need to
152     * add this offset back in order to get the real address.
153     */
154    addr |= PNACL_STRING_OFFSET;
155    const char* name = (const char*)addr;
156    struct XRaySymbol* symbol = XRaySymbolCreate(symtab->symbol_pool, name);
157    r = XRaySymbolTableAdd(symtab, symbol, addr);
158  }
159#endif
160
161#if defined(__GLIBC__)
162  if (r == NULL) {
163    Dl_info info;
164    if (dladdr((const void*)addr, &info) != 0)
165      if (info.dli_sname)
166        r = XRaySymbolTableAddByName(symtab, info.dli_sname, addr);
167  }
168#endif
169  return r;
170}
171
172
173/* Returns total number of symbols in the table. */
174int XRaySymbolCount(struct XRaySymbolTable* symtab) {
175  return symtab->num_symbols;
176}
177
178
179/* Creates and inializes a symbol table. */
180struct XRaySymbolTable* XRaySymbolTableCreate(int size) {
181  struct XRaySymbolTable* symtab;
182  symtab = (struct XRaySymbolTable*)XRayMalloc(sizeof(*symtab));
183  symtab->num_symbols = 0;
184  symtab->string_pool = XRayStringPoolCreate();
185  symtab->hash_table = XRayHashTableCreate(size);
186  symtab->symbol_pool = XRaySymbolPoolCreate();
187  return symtab;
188}
189
190
191/* Frees a symbol table. */
192void XRaySymbolTableFree(struct XRaySymbolTable* symtab) {
193  XRayStringPoolFree(symtab->string_pool);
194  XRaySymbolPoolFree(symtab->symbol_pool);
195  XRayHashTableFree(symtab->hash_table);
196  symtab->num_symbols = 0;
197  XRayFree(symtab);
198}
199
200#endif  /* XRAY */
201