libcsdbg  1.28
C++ exception (and generic) stack trace debug library
symtab.cpp
Go to the documentation of this file.
1 #include "../include/symtab.hpp"
2 #include "../include/util.hpp"
3 
10 namespace csdbg {
11 
22 symtab::symtab(const i8 *path, mem_addr_t base):
23 m_path(NULL),
24 m_base(base),
25 m_table(NULL)
26 {
27  if ( unlikely(path == NULL) )
28  throw exception("invalid argument: path (=%p)", path);
29 
30  m_path = new i8[strlen(path) + 1];
31  strcpy(m_path, path);
32 
33  bfd *fd = NULL;
34  asymbol **tbl = NULL;
35  i8 *nm = NULL;
36  symbol *sym = NULL;
37 
38  /* If an exception occurs, release resources and rethrow it */
39  try {
40  /* Open the binary file and obtain a descriptor (the bfd) */
41  fd = bfd_openr(m_path, NULL);
42  if ( unlikely(fd == NULL) ) {
43  bfd_error bfd_errno = bfd_get_error();
44  throw exception(
45  "failed to open file '%s' (bfd errno %d - %s)",
46  m_path,
47  bfd_errno,
48  bfd_errmsg(bfd_errno)
49  );
50  }
51 
52  /* Verify that the file contains objective code */
53  if ( unlikely(!bfd_check_format(fd, bfd_object)) ) {
54  bfd_error bfd_errno = bfd_get_error();
55  throw exception(
56  "failed to verify file '%s' (bfd errno %d - %s)",
57  m_path,
58  bfd_errno,
59  bfd_errmsg(bfd_errno)
60  );
61  }
62 
63  /* Get the symbol table storage size */
64  i32 sz = bfd_get_symtab_upper_bound(fd);
65  if ( unlikely(sz == 0) )
66  throw exception("file '%s' is stripped", m_path);
67 
68  else if ( unlikely(sz < 0) ) {
69  bfd_error bfd_errno = bfd_get_error();
70  throw exception(
71  "failed to parse file '%s' (bfd errno %d - %s)",
72  m_path,
73  bfd_errno,
74  bfd_errmsg(bfd_errno)
75  );
76  }
77 
78  /* Canonicalize the symbol table and get the symbol count */
79  tbl = new asymbol*[sz];
80  i32 cnt = bfd_canonicalize_symtab(fd, tbl);
81  if ( unlikely(cnt == 0) )
82  throw exception("file '%s' is stripped", m_path);
83 
84  else if ( unlikely(cnt < 0) ) {
85  bfd_error bfd_errno = bfd_get_error();
86  throw exception(
87  "failed to canonicalize the symbol table of '%s' (bfd errno %d - %s)",
88  m_path,
89  bfd_errno,
90  bfd_errmsg(bfd_errno)
91  );
92  }
93 
94  /* Traverse the symbol table, discard non function symbols */
95  m_table = new chain<symbol>;
96  for (i32 i = 0; likely(i < cnt); i++) {
97  const asymbol *cur = tbl[i];
98 
99  /* If the entry is not in a code section */
100  if ( likely((cur->section->flags & SEC_CODE) == 0) )
101  continue;
102 
103  /* If the entry is not a function symbol */
104  if ( likely((cur->flags & BSF_FUNCTION) == 0) )
105  continue;
106 
107  /*
108  * A symbol runtime address is the load address, plus the section virtual
109  * memory address, plus the offset from the section base
110  */
111  mem_addr_t addr = m_base;
112  addr += bfd_get_section_vma(fd, cur->section);
113  addr += cur->value;
114 
115  /* Demangle and store the symbol */
116  nm = abi::__cxa_demangle(cur->name, NULL, NULL, NULL);
117  if ( likely(nm != NULL) ) {
118  sym = new symbol(addr, nm);
119  delete[] nm;
120  nm = NULL;
121  }
122  else
123  sym = new symbol(addr, cur->name);
124 
125  m_table->add(sym);
126  sym = NULL;
127  }
128 
129  delete[] tbl;
130  bfd_close(fd);
131 
132 #if CSDBG_DBG_LEVEL & CSDBG_DBGL_INFO
133  util::dbg_info("loaded the symbol table of '%s'", m_path);
134  util::dbg_info(" base address @ %p", m_base);
135  util::dbg_info(" number of symbols: %d", cnt);
136  util::dbg_info(" number of function symbols: %d", m_table->size());
137 #endif
138  }
139 
140  catch (...) {
141  delete[] m_path;
142  delete[] tbl;
143  delete[] nm;
144 
145  delete m_table;
146  delete sym;
147 
148  m_path = NULL;
149  m_table = NULL;
150 
151  if ( likely(fd != NULL) )
152  bfd_close(fd);
153 
154  throw;
155  }
156 }
157 
158 
167 try:
168 m_path(NULL),
169 m_base(src.m_base),
170 m_table(NULL)
171 {
172  m_table = src.m_table->clone();
173  m_path = new i8[strlen(src.m_path) + 1];
174  strcpy(m_path, src.m_path);
175 }
176 
177 catch (...) {
178  delete m_table;
179  m_table = NULL;
180 }
181 
182 
187 {
188  delete[] m_path;
189  delete m_table;
190  m_path = NULL;
191  m_table = NULL;
192 }
193 
194 
202 inline symtab* symtab::clone() const
203 {
204  return new symtab(*this);
205 }
206 
207 
213 inline const i8* symtab::path() const
214 {
215  return m_path;
216 }
217 
218 
224 inline mem_addr_t symtab::base() const
225 {
226  return m_base;
227 }
228 
229 
240 {
241  if ( unlikely(this == &rval) )
242  return *this;
243 
244  u32 len = strlen(rval.m_path);
245  if (len > strlen(m_path)) {
246  delete[] m_path;
247  m_path = NULL;
248  m_path = new i8[len + 1];
249  }
250 
251  strcpy(m_path, rval.m_path);
252  m_base = rval.m_base;
253  *m_table = *rval.m_table;
254 
255  return *this;
256 }
257 
258 
264 inline u32 symtab::size() const
265 {
266  return m_table->size();
267 }
268 
269 
281 const i8* symtab::lookup(mem_addr_t addr) const
282 {
283  for (u32 i = 0, sz = m_table->size(); likely(i < sz); i++) {
284  const symbol *sym = m_table->at(i);
285  if ( unlikely(sym->addr() == addr) )
286  return sym->name();
287  }
288 
289  /* The address was not resolved */
290  return NULL;
291 }
292 
293 
301 inline bool symtab::exists(mem_addr_t addr) const
302 {
303  return lookup(addr) != NULL;
304 }
305 
306 
314 inline symtab& symtab::foreach(void (*pfunc)(u32, symbol*)) const
315 {
316  m_table->foreach(pfunc);
317  return const_cast<symtab&> (*this);
318 }
319 
320 }
321 
virtual bool exists(mem_addr_t) const
Probe if a symbol exists.
Definition: symtab.cpp:301
virtual symtab & foreach(void(*)(u32, symbol *)) const
Traverse the symbol table with a callback for each symbol.
Definition: symtab.cpp:314
This class represents a program/library function symbol.
Definition: symbol.hpp:17
virtual symtab & operator=(const symtab &)
Assignment operator.
Definition: symtab.cpp:239
Lightweight, templated, doubly-linked list (using XOR linking)
Definition: chain.hpp:33
virtual ~symtab()
Object destructor.
Definition: symtab.cpp:186
char i8
8-bit signed integer
Definition: config.hpp:72
mem_addr_t m_base
Load base address.
Definition: symtab.hpp:35
#define likely(expr)
Offer a hint (positive) to the pipeline branch predictor.
Definition: config.hpp:344
This class represents a program/library symbol table (symtab section)
Definition: symtab.hpp:27
virtual const i8 * lookup(mem_addr_t) const
Lookup an address to resolve a symbol.
Definition: symtab.cpp:281
virtual mem_addr_t addr() const
Get the symbol address.
Definition: symbol.cpp:79
virtual const i8 * name() const
Get the symbol name.
Definition: symbol.cpp:90
unsigned int u32
32-bit unsigned integer
Definition: config.hpp:102
virtual symtab * clone() const
Object virtual copy constructor.
Definition: symtab.cpp:202
int i32
32-bit signed integer
Definition: config.hpp:82
virtual const i8 * path() const
Get the objective code file path.
Definition: symtab.cpp:213
chain< symbol > * m_table
Function symbol table.
Definition: symtab.hpp:37
virtual u32 size() const
Get the number of symbols.
Definition: symtab.cpp:264
unsigned long long mem_addr_t
64-bit memory address
Definition: config.hpp:120
i8 * m_path
Objective code file path.
Definition: symtab.hpp:33
This class is a throwable with a textual description of an error.
Definition: exception.hpp:26
#define unlikely(expr)
Offer a hint (negative) to the pipeline branch predictor.
Definition: config.hpp:349
static void dbg_info(const i8 *,...)
Print an informational debug message on the standard error stream.
Definition: util.cpp:680
virtual mem_addr_t base() const
Get the load base address.
Definition: symtab.cpp:224
symtab(const i8 *, mem_addr_t=0)
Object constructor.
Definition: symtab.cpp:22