• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016 GitHub, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <cxxabi.h>
18 #include <cstring>
19 #include <fcntl.h>
20 #include <linux/elf.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <sys/sysmacros.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <cstdio>
27 
28 #include "bcc_elf.h"
29 #include "bcc_perf_map.h"
30 #include "bcc_proc.h"
31 #include "bcc_syms.h"
32 #include "common.h"
33 #include "vendor/tinyformat.hpp"
34 
35 #include "syms.h"
36 
getinode_()37 ino_t ProcStat::getinode_() {
38   struct stat s;
39   return (!stat(procfs_.c_str(), &s)) ? s.st_ino : -1;
40 }
41 
is_stale()42 bool ProcStat::is_stale() {
43   ino_t cur_inode = getinode_();
44   return (cur_inode > 0) && (cur_inode != inode_);
45 }
46 
ProcStat(int pid)47 ProcStat::ProcStat(int pid)
48     : procfs_(tfm::format("/proc/%d/exe", pid)), inode_(getinode_()) {}
49 
_add_symbol(const char * symname,const char * modname,uint64_t addr,void * p)50 void KSyms::_add_symbol(const char *symname, const char *modname, uint64_t addr, void *p) {
51   KSyms *ks = static_cast<KSyms *>(p);
52   ks->syms_.emplace_back(symname, modname, addr);
53 }
54 
refresh()55 void KSyms::refresh() {
56   if (syms_.empty()) {
57     bcc_procutils_each_ksym(_add_symbol, this);
58     std::sort(syms_.begin(), syms_.end());
59   }
60 }
61 
resolve_addr(uint64_t addr,struct bcc_symbol * sym,bool demangle)62 bool KSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym, bool demangle) {
63   refresh();
64 
65   std::vector<Symbol>::iterator it;
66 
67   if (syms_.empty())
68     goto unknown_symbol;
69 
70   it = std::upper_bound(syms_.begin(), syms_.end(), Symbol("", "", addr));
71   if (it != syms_.begin()) {
72     it--;
73     sym->name = (*it).name.c_str();
74     if (demangle)
75       sym->demangle_name = sym->name;
76     sym->module = (*it).mod.c_str();
77     sym->offset = addr - (*it).addr;
78     return true;
79   }
80 
81 unknown_symbol:
82   memset(sym, 0, sizeof(struct bcc_symbol));
83   return false;
84 }
85 
resolve_name(const char * _unused,const char * name,uint64_t * addr)86 bool KSyms::resolve_name(const char *_unused, const char *name,
87                          uint64_t *addr) {
88   refresh();
89 
90   if (syms_.size() != symnames_.size()) {
91     symnames_.clear();
92     for (Symbol &sym : syms_) {
93       symnames_[sym.name] = sym.addr;
94     }
95   }
96 
97   auto it = symnames_.find(name);
98   if (it == symnames_.end())
99     return false;
100 
101   *addr = it->second;
102   return true;
103 }
104 
ProcSyms(int pid,struct bcc_symbol_option * option)105 ProcSyms::ProcSyms(int pid, struct bcc_symbol_option *option)
106     : pid_(pid), procstat_(pid) {
107   if (option)
108     std::memcpy(&symbol_option_, option, sizeof(bcc_symbol_option));
109   else
110     symbol_option_ = {
111       .use_debug_file = 1,
112       .check_debug_file_crc = 1,
113       .lazy_symbolize = 1,
114       .use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC)
115     };
116   load_modules();
117 }
118 
load_modules()119 void ProcSyms::load_modules() {
120   bcc_procutils_each_module(pid_, _add_module, this);
121 }
122 
refresh()123 void ProcSyms::refresh() {
124   modules_.clear();
125   load_modules();
126   procstat_.reset();
127 }
128 
_add_module(mod_info * mod,int enter_ns,void * payload)129 int ProcSyms::_add_module(mod_info *mod, int enter_ns, void *payload) {
130   ProcSyms *ps = static_cast<ProcSyms *>(payload);
131   std::string ns_relative_path = tfm::format("/proc/%d/root%s", ps->pid_, mod->name);
132   const char *modpath = enter_ns && ps->pid_ != -1 ? ns_relative_path.c_str() : mod->name;
133   auto it = std::find_if(
134       ps->modules_.begin(), ps->modules_.end(),
135       [=](const ProcSyms::Module &m) { return m.name_ == mod->name; });
136   if (it == ps->modules_.end()) {
137     auto module = Module(
138         mod->name, modpath, &ps->symbol_option_);
139 
140     // pid/maps doesn't account for file_offset of text within the ELF.
141     // It only gives the mmap offset. We need the real offset for symbol
142     // lookup.
143     if (module.type_ == ModuleType::SO) {
144       if (bcc_elf_get_text_scn_info(modpath, &module.elf_so_addr_,
145                                     &module.elf_so_offset_) < 0) {
146         fprintf(stderr, "WARNING: Couldn't find .text section in %s\n", modpath);
147         fprintf(stderr, "WARNING: BCC can't handle sym look ups for %s", modpath);
148       }
149     }
150 
151     if (!bcc_is_perf_map(modpath) || module.type_ != ModuleType::UNKNOWN)
152       // Always add the module even if we can't read it, so that we could
153       // report correct module name. Unless it's a perf map that we only
154       // add readable ones.
155       it = ps->modules_.insert(ps->modules_.end(), std::move(module));
156     else
157       return 0;
158   }
159   it->ranges_.emplace_back(mod->start_addr, mod->end_addr, mod->file_offset);
160   // perf-PID map is added last. We try both inside the Process's mount
161   // namespace + chroot, and in global /tmp. Make sure we only add one.
162   if (it->type_ == ModuleType::PERF_MAP)
163     return -1;
164 
165   return 0;
166 }
167 
resolve_addr(uint64_t addr,struct bcc_symbol * sym,bool demangle)168 bool ProcSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym,
169                             bool demangle) {
170   if (procstat_.is_stale())
171     refresh();
172 
173   memset(sym, 0, sizeof(struct bcc_symbol));
174 
175   const char *original_module = nullptr;
176   uint64_t offset;
177   bool only_perf_map = false;
178   for (Module &mod : modules_) {
179     if (only_perf_map && (mod.type_ != ModuleType::PERF_MAP))
180       continue;
181     if (mod.contains(addr, offset)) {
182       if (mod.find_addr(offset, sym)) {
183         if (demangle) {
184           if (sym->name && (!strncmp(sym->name, "_Z", 2) || !strncmp(sym->name, "___Z", 4)))
185             sym->demangle_name =
186                 abi::__cxa_demangle(sym->name, nullptr, nullptr, nullptr);
187           if (!sym->demangle_name)
188             sym->demangle_name = sym->name;
189         }
190         return true;
191       } else if (mod.type_ != ModuleType::PERF_MAP) {
192         // In this case, we found the address in the range of a module, but
193         // not able to find a symbol of that address in the module.
194         // Thus, we would try to find the address in perf map, and
195         // save the module's name in case we will need it later.
196         original_module = mod.name_.c_str();
197         only_perf_map = true;
198       }
199     }
200   }
201   // If we didn't find the symbol anywhere, the module name is probably
202   // set to be the perf map's name as it would be the last we tried.
203   // In this case, if we have found the address previously in a module,
204   // report the saved original module name instead.
205   if (original_module)
206     sym->module = original_module;
207   return false;
208 }
209 
resolve_name(const char * module,const char * name,uint64_t * addr)210 bool ProcSyms::resolve_name(const char *module, const char *name,
211                             uint64_t *addr) {
212   if (procstat_.is_stale())
213     refresh();
214 
215   for (Module &mod : modules_) {
216     if (mod.name_ == module)
217       return mod.find_name(name, addr);
218   }
219   return false;
220 }
221 
Module(const char * name,const char * path,struct bcc_symbol_option * option)222 ProcSyms::Module::Module(const char *name, const char *path,
223     struct bcc_symbol_option *option)
224     : name_(name),
225       path_(path),
226       loaded_(false),
227       symbol_option_(option),
228       type_(ModuleType::UNKNOWN) {
229   int elf_type = bcc_elf_get_type(path_.c_str());
230   // The Module is an ELF file
231   if (elf_type >= 0) {
232     if (elf_type == ET_EXEC)
233       type_ = ModuleType::EXEC;
234     else if (elf_type == ET_DYN)
235       type_ = ModuleType::SO;
236     return;
237   }
238   // Other symbol files
239   if (bcc_is_valid_perf_map(path_.c_str()) == 1)
240     type_ = ModuleType::PERF_MAP;
241   else if (bcc_elf_is_vdso(name_.c_str()) == 1)
242     type_ = ModuleType::VDSO;
243 
244   // Will be stored later
245   elf_so_offset_ = 0;
246   elf_so_addr_ = 0;
247 }
248 
_add_symbol(const char * symname,uint64_t start,uint64_t size,void * p)249 int ProcSyms::Module::_add_symbol(const char *symname, uint64_t start,
250                                   uint64_t size, void *p) {
251   Module *m = static_cast<Module *>(p);
252   auto res = m->symnames_.emplace(symname);
253   m->syms_.emplace_back(&*(res.first), start, size);
254   return 0;
255 }
256 
_add_symbol_lazy(size_t section_idx,size_t str_table_idx,size_t str_len,uint64_t start,uint64_t size,int debugfile,void * p)257 int ProcSyms::Module::_add_symbol_lazy(size_t section_idx, size_t str_table_idx,
258                                        size_t str_len, uint64_t start,
259                                        uint64_t size, int debugfile, void *p) {
260   Module *m = static_cast<Module *>(p);
261   m->syms_.emplace_back(
262       section_idx, str_table_idx, str_len, start, size, debugfile);
263   return 0;
264 }
265 
load_sym_table()266 void ProcSyms::Module::load_sym_table() {
267   if (loaded_)
268     return;
269   loaded_ = true;
270 
271   if (type_ == ModuleType::UNKNOWN)
272     return;
273 
274   if (type_ == ModuleType::PERF_MAP)
275     bcc_perf_map_foreach_sym(path_.c_str(), _add_symbol, this);
276   if (type_ == ModuleType::EXEC || type_ == ModuleType::SO) {
277     if (symbol_option_->lazy_symbolize)
278       bcc_elf_foreach_sym_lazy(path_.c_str(), _add_symbol_lazy, symbol_option_, this);
279     else
280       bcc_elf_foreach_sym(path_.c_str(), _add_symbol, symbol_option_, this);
281   }
282   if (type_ == ModuleType::VDSO)
283     bcc_elf_foreach_vdso_sym(_add_symbol, this);
284 
285   std::sort(syms_.begin(), syms_.end());
286 }
287 
contains(uint64_t addr,uint64_t & offset) const288 bool ProcSyms::Module::contains(uint64_t addr, uint64_t &offset) const {
289   for (const auto &range : ranges_) {
290     if (addr >= range.start && addr < range.end) {
291       if (type_ == ModuleType::SO || type_ == ModuleType::VDSO) {
292         // Offset within the mmap
293         offset = addr - range.start + range.file_offset;
294 
295         // Offset within the ELF for SO symbol lookup
296         offset += (elf_so_addr_ - elf_so_offset_);
297       } else {
298         offset = addr;
299       }
300 
301       return true;
302     }
303   }
304 
305   return false;
306 }
307 
find_name(const char * symname,uint64_t * addr)308 bool ProcSyms::Module::find_name(const char *symname, uint64_t *addr) {
309   struct Payload {
310     const char *symname;
311     uint64_t *out;
312     bool found;
313   };
314 
315   Payload payload;
316   payload.symname = symname;
317   payload.out = addr;
318   payload.found = false;
319 
320   auto cb = [](const char *name, uint64_t start, uint64_t size, void *p) {
321     Payload *payload = static_cast<Payload*>(p);
322 
323     if (!strcmp(payload->symname, name)) {
324       payload->found = true;
325       *(payload->out) = start;
326       return -1;  // Stop iteration
327     }
328 
329     return 0;
330   };
331 
332   if (type_ == ModuleType::PERF_MAP)
333     bcc_perf_map_foreach_sym(path_.c_str(), cb, &payload);
334   if (type_ == ModuleType::EXEC || type_ == ModuleType::SO)
335     bcc_elf_foreach_sym(path_.c_str(), cb, symbol_option_, &payload);
336   if (type_ == ModuleType::VDSO)
337     bcc_elf_foreach_vdso_sym(cb, &payload);
338 
339   if (!payload.found)
340     return false;
341 
342   if (type_ == ModuleType::SO)
343     *(payload.out) += start();
344 
345   return true;
346 }
347 
find_addr(uint64_t offset,struct bcc_symbol * sym)348 bool ProcSyms::Module::find_addr(uint64_t offset, struct bcc_symbol *sym) {
349   load_sym_table();
350 
351   sym->module = name_.c_str();
352   sym->offset = offset;
353 
354   auto it = std::upper_bound(syms_.begin(), syms_.end(), Symbol(nullptr, offset, 0));
355   if (it == syms_.begin())
356     return false;
357 
358   // 'it' points to the symbol whose start address is strictly greater than
359   // the address we're looking for. Start stepping backwards as long as the
360   // current symbol is still below the desired address, and see if the end
361   // of the current symbol (start + size) is above the desired address. Once
362   // we have a matching symbol, return it. Note that simply looking at '--it'
363   // is not enough, because symbols can be nested. For example, we could be
364   // looking for offset 0x12 with the following symbols available:
365   // SYMBOL   START   SIZE    END
366   // goo      0x0     0x6     0x0 + 0x6 = 0x6
367   // foo      0x6     0x10    0x6 + 0x10 = 0x16
368   // bar      0x8     0x4     0x8 + 0x4 = 0xc
369   // baz      0x16    0x10    0x16 + 0x10 = 0x26
370   // The upper_bound lookup will return baz, and then going one symbol back
371   // brings us to bar, which does not contain offset 0x12 and is nested inside
372   // foo. Going back one more symbol brings us to foo, which contains 0x12
373   // and is a match.
374   // However, we also don't want to walk through the entire symbol list for
375   // unknown / missing symbols. So we will break if we reach a function that
376   // doesn't cover the function immediately before 'it', which means it is
377   // not possibly a nested function containing the address we're looking for.
378   --it;
379   uint64_t limit = it->start;
380   for (; offset >= it->start; --it) {
381     if (offset < it->start + it->size) {
382       // Resolve and cache the symbol name if necessary
383       if (!it->is_name_resolved) {
384         std::string sym_name(it->data.name_idx.str_len + 1, '\0');
385         if (bcc_elf_symbol_str(path_.c_str(), it->data.name_idx.section_idx,
386               it->data.name_idx.str_table_idx, &sym_name[0], sym_name.size(),
387               it->data.name_idx.debugfile))
388           break;
389 
390         it->data.name = &*(symnames_.emplace(std::move(sym_name)).first);
391         it->is_name_resolved = true;
392       }
393 
394       sym->name = it->data.name->c_str();
395       sym->offset = (offset - it->start);
396       return true;
397     }
398     if (limit > it->start + it->size)
399       break;
400     // But don't step beyond begin()!
401     if (it == syms_.begin())
402       break;
403   }
404 
405   return false;
406 }
407 
load_sym_table()408 bool BuildSyms::Module::load_sym_table()
409 {
410   if (loaded_)
411     return true;
412 
413   symbol_option_ = {
414     .use_debug_file = 1,
415     .check_debug_file_crc = 1,
416     .lazy_symbolize = 1,
417     .use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC)
418   };
419 
420   bcc_elf_foreach_sym(module_name_.c_str(), _add_symbol, &symbol_option_, this);
421   std::sort(syms_.begin(), syms_.end());
422 
423   for(std::vector<Symbol>::iterator it = syms_.begin();
424       it != syms_.end(); ++it++) {
425   }
426   loaded_ = true;
427   return true;
428 }
429 
_add_symbol(const char * symname,uint64_t start,uint64_t size,void * p)430 int BuildSyms::Module::_add_symbol(const char *symname, uint64_t start,
431                                    uint64_t size, void *p)
432 {
433   BuildSyms::Module *m = static_cast<BuildSyms::Module *> (p);
434   auto res = m->symnames_.emplace(symname);
435   m->syms_.emplace_back(&*(res.first), start, size);
436   return 0;
437 }
438 
resolve_addr(uint64_t offset,struct bcc_symbol * sym,bool demangle)439 bool BuildSyms::Module::resolve_addr(uint64_t offset, struct bcc_symbol* sym,
440                                      bool demangle)
441 {
442   std::vector<Symbol>::iterator it;
443 
444   load_sym_table();
445 
446   if (syms_.empty())
447     goto unknown_symbol;
448 
449   it = std::upper_bound(syms_.begin(), syms_.end(), Symbol(nullptr, offset, 0));
450   if (it != syms_.begin()) {
451     it--;
452     sym->name = (*it).name->c_str();
453     if (demangle)
454       sym->demangle_name = sym->name;
455     sym->offset = offset - (*it).start;
456     sym->module = module_name_.c_str();
457     return true;
458   }
459 
460 unknown_symbol:
461   memset(sym, 0, sizeof(struct bcc_symbol));
462   return false;
463 }
464 
add_module(const std::string module_name)465 bool BuildSyms::add_module(const std::string module_name)
466 {
467   struct stat s;
468   char buildid[BPF_BUILD_ID_SIZE*2+1];
469 
470   if (stat(module_name.c_str(), &s) < 0)
471      return false;
472 
473   if (bcc_elf_get_buildid(module_name.c_str(), buildid) < 0)
474       return false;
475 
476   std::string elf_buildid(buildid);
477   std::unique_ptr<BuildSyms::Module> ptr(new BuildSyms::Module(module_name.c_str()));
478   buildmap_[elf_buildid] = std::move(ptr);
479   return true;
480 }
481 
resolve_addr(std::string build_id,uint64_t offset,struct bcc_symbol * sym,bool demangle)482 bool BuildSyms::resolve_addr(std::string build_id, uint64_t offset,
483                              struct bcc_symbol *sym, bool demangle)
484 {
485   std::unordered_map<std::string,std::unique_ptr<BuildSyms::Module> >::iterator it;
486 
487   it = buildmap_.find(build_id);
488   if (it == buildmap_.end())
489     /*build-id not added to the BuildSym*/
490     return false;
491 
492   BuildSyms::Module *mod = it->second.get();
493   return mod->resolve_addr(offset, sym, demangle);
494 }
495 
496 extern "C" {
497 
bcc_symcache_new(int pid,struct bcc_symbol_option * option)498 void *bcc_symcache_new(int pid, struct bcc_symbol_option *option) {
499   if (pid < 0)
500     return static_cast<void *>(new KSyms());
501   return static_cast<void *>(new ProcSyms(pid, option));
502 }
503 
bcc_free_symcache(void * symcache,int pid)504 void bcc_free_symcache(void *symcache, int pid) {
505   if (pid < 0)
506     delete static_cast<KSyms*>(symcache);
507   else
508     delete static_cast<ProcSyms*>(symcache);
509 }
510 
bcc_symbol_free_demangle_name(struct bcc_symbol * sym)511 void bcc_symbol_free_demangle_name(struct bcc_symbol *sym) {
512   if (sym->demangle_name && (sym->demangle_name != sym->name))
513     free(const_cast<char*>(sym->demangle_name));
514 }
515 
bcc_symcache_resolve(void * resolver,uint64_t addr,struct bcc_symbol * sym)516 int bcc_symcache_resolve(void *resolver, uint64_t addr,
517                          struct bcc_symbol *sym) {
518   SymbolCache *cache = static_cast<SymbolCache *>(resolver);
519   return cache->resolve_addr(addr, sym) ? 0 : -1;
520 }
521 
bcc_symcache_resolve_no_demangle(void * resolver,uint64_t addr,struct bcc_symbol * sym)522 int bcc_symcache_resolve_no_demangle(void *resolver, uint64_t addr,
523                                      struct bcc_symbol *sym) {
524   SymbolCache *cache = static_cast<SymbolCache *>(resolver);
525   return cache->resolve_addr(addr, sym, false) ? 0 : -1;
526 }
527 
bcc_symcache_resolve_name(void * resolver,const char * module,const char * name,uint64_t * addr)528 int bcc_symcache_resolve_name(void *resolver, const char *module,
529                               const char *name, uint64_t *addr) {
530   SymbolCache *cache = static_cast<SymbolCache *>(resolver);
531   return cache->resolve_name(module, name, addr) ? 0 : -1;
532 }
533 
bcc_symcache_refresh(void * resolver)534 void bcc_symcache_refresh(void *resolver) {
535   SymbolCache *cache = static_cast<SymbolCache *>(resolver);
536   cache->refresh();
537 }
538 
bcc_buildsymcache_new(void)539 void *bcc_buildsymcache_new(void) {
540   return static_cast<void *>(new BuildSyms());
541 }
542 
bcc_free_buildsymcache(void * symcache)543 void bcc_free_buildsymcache(void *symcache) {
544   delete static_cast<BuildSyms*>(symcache);
545 }
546 
bcc_buildsymcache_add_module(void * resolver,const char * module_name)547 int  bcc_buildsymcache_add_module(void *resolver, const char *module_name)
548 {
549   BuildSyms *bsym = static_cast<BuildSyms *>(resolver);
550   return  bsym->add_module(module_name) ? 0 : -1;
551 }
552 
bcc_buildsymcache_resolve(void * resolver,struct bpf_stack_build_id * trace,struct bcc_symbol * sym)553 int bcc_buildsymcache_resolve(void *resolver,
554                               struct bpf_stack_build_id *trace,
555                               struct bcc_symbol *sym)
556 {
557   std::string build_id;
558   unsigned char *c = &trace->build_id[0];
559   int idx = 0;
560 
561   /*cannot resolve in case of fallback*/
562   if (trace->status == BPF_STACK_BUILD_ID_EMPTY ||
563       trace->status == BPF_STACK_BUILD_ID_IP)
564     return 0;
565 
566   while( idx < 20) {
567     int nib1 = (c[idx]&0xf0)>>4;
568     int nib2 = (c[idx]&0x0f);
569     build_id += "0123456789abcdef"[nib1];
570     build_id += "0123456789abcdef"[nib2];
571     idx++;
572   }
573 
574   BuildSyms *bsym = static_cast<BuildSyms *>(resolver);
575   return bsym->resolve_addr(build_id, trace->offset, sym) ? 0 : -1;
576 }
577 
578 struct mod_search {
579   const char *name;
580   uint64_t inode;
581   uint64_t dev_major;
582   uint64_t dev_minor;
583   uint64_t addr;
584   uint8_t inode_match_only;
585 
586   uint64_t start;
587   uint64_t file_offset;
588 };
589 
_bcc_syms_find_module(mod_info * info,int enter_ns,void * p)590 int _bcc_syms_find_module(mod_info *info, int enter_ns, void *p) {
591   struct mod_search *mod = (struct mod_search *)p;
592   // use inode + dev to determine match if inode set
593   if (mod->inode) {
594     if (mod->inode != info->inode)
595       return 0;
596 
597     // look at comment on USDT::set_probe_matching_kludge
598     // in api/BPF.h for explanation of why this might be
599     // necessary
600     if (mod->inode_match_only)
601       goto file_match;
602 
603     if(mod->dev_major == info->dev_major
604         && mod->dev_minor == info->dev_minor)
605       goto file_match;
606 
607     return 0;
608   }
609 
610   // fallback to name match
611   if (!strcmp(info->name, mod->name))
612     goto file_match;
613 
614   return 0;
615 
616 file_match:
617   mod->start = info->start_addr;
618   mod->file_offset = info->file_offset;
619   return -1;
620 }
621 
bcc_resolve_global_addr(int pid,const char * module,const uint64_t address,uint8_t inode_match_only,uint64_t * global)622 int bcc_resolve_global_addr(int pid, const char *module, const uint64_t address,
623                             uint8_t inode_match_only, uint64_t *global) {
624   struct stat s;
625   if (stat(module, &s))
626     return -1;
627 
628   struct mod_search mod = {module, s.st_ino, major(s.st_dev), minor(s.st_dev),
629                            address, inode_match_only,
630                            0x0, 0x0};
631   if (bcc_procutils_each_module(pid, _bcc_syms_find_module, &mod) < 0 ||
632       mod.start == 0x0)
633     return -1;
634 
635   *global = mod.start - mod.file_offset + address;
636   return 0;
637 }
638 
_sym_cb_wrapper(const char * symname,uint64_t addr,uint64_t,void * payload)639 static int _sym_cb_wrapper(const char *symname, uint64_t addr, uint64_t,
640                            void *payload) {
641   SYM_CB cb = (SYM_CB) payload;
642   return cb(symname, addr);
643 }
644 
bcc_foreach_function_symbol(const char * module,SYM_CB cb)645 int bcc_foreach_function_symbol(const char *module, SYM_CB cb) {
646   if (module == 0 || cb == 0)
647     return -1;
648 
649   static struct bcc_symbol_option default_option = {
650     .use_debug_file = 1,
651     .check_debug_file_crc = 1,
652     .lazy_symbolize = 1,
653     .use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC)
654   };
655 
656   return bcc_elf_foreach_sym(
657       module, _sym_cb_wrapper, &default_option, (void *)cb);
658 }
659 
_find_sym(const char * symname,uint64_t addr,uint64_t,void * payload)660 static int _find_sym(const char *symname, uint64_t addr, uint64_t,
661                      void *payload) {
662   struct bcc_symbol *sym = (struct bcc_symbol *)payload;
663   if (!strcmp(sym->name, symname)) {
664     sym->offset = addr;
665     return -1;
666   }
667   return 0;
668 }
669 
670 struct load_addr_t {
671   uint64_t target_addr;
672   uint64_t binary_addr;
673 };
_find_load(uint64_t v_addr,uint64_t mem_sz,uint64_t file_offset,void * payload)674 int _find_load(uint64_t v_addr, uint64_t mem_sz, uint64_t file_offset,
675                        void *payload) {
676   struct load_addr_t *addr = static_cast<load_addr_t *>(payload);
677   if (addr->target_addr >= v_addr && addr->target_addr < (v_addr + mem_sz)) {
678     addr->binary_addr = addr->target_addr - v_addr + file_offset;
679     return -1;
680   }
681   return 0;
682 }
683 
bcc_resolve_symname(const char * module,const char * symname,const uint64_t addr,int pid,struct bcc_symbol_option * option,struct bcc_symbol * sym)684 int bcc_resolve_symname(const char *module, const char *symname,
685                         const uint64_t addr, int pid,
686                         struct bcc_symbol_option *option,
687                         struct bcc_symbol *sym) {
688   int module_type;
689   static struct bcc_symbol_option default_option = {
690     .use_debug_file = 1,
691     .check_debug_file_crc = 1,
692     .lazy_symbolize = 1,
693 #if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
694     .use_symbol_type = BCC_SYM_ALL_TYPES | (1 << STT_PPC64_ELFV2_SYM_LEP),
695 #else
696     .use_symbol_type = BCC_SYM_ALL_TYPES,
697 #endif
698   };
699 
700   if (module == NULL)
701     return -1;
702 
703   memset(sym, 0, sizeof(bcc_symbol));
704 
705   if (strchr(module, '/')) {
706     sym->module = strdup(module);
707   } else {
708     sym->module = bcc_procutils_which_so(module, pid);
709   }
710   if (sym->module == NULL)
711     return -1;
712   if (pid != 0 && pid != -1 && strstr(sym->module, "/proc") != sym->module){
713     char *temp = (char*)sym->module;
714     sym->module = strdup(tfm::format("/proc/%d/root%s", pid, sym->module).c_str());
715     free(temp);
716   }
717 
718   sym->name = symname;
719   sym->offset = addr;
720   if (option == NULL)
721     option = &default_option;
722 
723   if (sym->name && sym->offset == 0x0)
724     if (bcc_elf_foreach_sym(sym->module, _find_sym, option, sym) < 0)
725       goto invalid_module;
726   if (sym->offset == 0x0)
727     goto invalid_module;
728 
729   // For executable (ET_EXEC) binaries and shared objects (ET_DYN), translate
730   // the virtual address to physical address in the binary file.
731   module_type = bcc_elf_get_type(sym->module);
732   if (module_type == ET_EXEC || module_type == ET_DYN) {
733     struct load_addr_t addr = {
734       .target_addr = sym->offset,
735       .binary_addr = 0x0,
736     };
737     if (bcc_elf_foreach_load_section(sym->module, &_find_load, &addr) < 0)
738       goto invalid_module;
739     if (!addr.binary_addr)
740       goto invalid_module;
741     sym->offset = addr.binary_addr;
742   }
743   return 0;
744 
745 invalid_module:
746   if (sym->module) {
747     ::free(const_cast<char*>(sym->module));
748     sym->module = NULL;
749   }
750   return -1;
751 }
752 }
753