diff --git a/src/cc/bcc_syms.cc b/src/cc/bcc_syms.cc index 3ea704e5860f..b656893da21b 100644 --- a/src/cc/bcc_syms.cc +++ b/src/cc/bcc_syms.cc @@ -13,56 +13,41 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include -#include -#include -#include -#include +#include #include +#include #include -#include -#include "bcc_syms.h" -#include "bcc_proc.h" #include "bcc_elf.h" +#include "bcc_proc.h" +#include "bcc_syms.h" -class SymbolCache { - public: - virtual void refresh() = 0; - virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym) = 0; - virtual bool resolve_name(const char *name, uint64_t *addr) = 0; -}; - -class KSyms : SymbolCache { - struct Symbol { - Symbol(const char *name, uint64_t addr) : name(name), addr(addr) {} - std::string name; - uint64_t addr; - - bool operator<(const Symbol &rhs) const { return addr < rhs.addr; } - }; - - std::vector syms_; - std::unordered_map symnames_; - static void _add_symbol(const char *, uint64_t, void *); - - public: - virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym); - virtual bool resolve_name(const char *name, uint64_t *addr); - virtual void refresh() { - if (syms_.empty()) { - bcc_procutils_each_ksym(_add_symbol, this); - std::sort(syms_.begin(), syms_.end()); - } - } -}; +#include "syms.h" + +ino_t ProcStat::getinode_() { + struct stat s; + return (!stat(procfs_.c_str(), &s)) ? s.st_ino : -1; +} + +ProcStat::ProcStat(int pid) : inode_(-1) { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "/proc/%d/exe", pid); + procfs_ = buffer; +} void KSyms::_add_symbol(const char *symname, uint64_t addr, void *p) { KSyms *ks = static_cast(p); ks->syms_.emplace_back(symname, addr); } +void KSyms::refresh() { + if (syms_.empty()) { + bcc_procutils_each_ksym(_add_symbol, this); + std::sort(syms_.begin(), syms_.end()); + } +} + bool KSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) { refresh(); @@ -80,7 +65,8 @@ bool KSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) { return true; } -bool KSyms::resolve_name(const char *name, uint64_t *addr) { +bool KSyms::resolve_name(const char *_unused, const char *name, + uint64_t *addr) { refresh(); if (syms_.size() != symnames_.size()) { @@ -98,65 +84,6 @@ bool KSyms::resolve_name(const char *name, uint64_t *addr) { return true; } -class ProcStat { - std::string procfs_; - ino_t inode_; - - ino_t getinode_() { - struct stat s; - return (!stat(procfs_.c_str(), &s)) ? s.st_ino : -1; - } - - public: - ProcStat(int pid) : inode_(-1) { - char buffer[128]; - snprintf(buffer, sizeof(buffer), "/proc/%d/exe", pid); - procfs_ = buffer; - } - - bool is_stale() { return inode_ != getinode_(); } - void reset() { inode_ = getinode_(); } -}; - -class ProcSyms : SymbolCache { - struct Symbol { - Symbol(const char *name, uint64_t start, uint64_t size, int flags = 0) - : name(name), start(start), size(size), flags(flags) {} - std::string name; - uint64_t start; - uint64_t size; - int flags; - }; - - struct Module { - Module(const char *name, uint64_t start, uint64_t end) - : name_(name), start_(start), end_(end) {} - std::string name_; - uint64_t start_; - uint64_t end_; - std::vector syms_; - - void load_sym_table(); - bool decode_sym(uint64_t addr, struct bcc_symbol *sym); - bool is_so() { return strstr(name_.c_str(), ".so") != nullptr; } - - static int _add_symbol(const char *symname, uint64_t start, uint64_t end, - int flags, void *p); - }; - - int pid_; - std::vector modules_; - ProcStat procstat_; - - static void _add_module(const char *, uint64_t, uint64_t, void *); - - public: - ProcSyms(int pid); - virtual void refresh(); - virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym); - virtual bool resolve_name(const char *name, uint64_t *addr); -}; - ProcSyms::ProcSyms(int pid) : pid_(pid), procstat_(pid) { refresh(); } void ProcSyms::refresh() { @@ -165,10 +92,11 @@ void ProcSyms::refresh() { procstat_.reset(); } -void ProcSyms::_add_module(const char *modname, uint64_t start, uint64_t end, - void *payload) { +int ProcSyms::_add_module(const char *modname, uint64_t start, uint64_t end, + void *payload) { ProcSyms *ps = static_cast(payload); ps->modules_.emplace_back(modname, start, end); + return 0; } bool ProcSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) { @@ -181,13 +109,20 @@ bool ProcSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) { for (Module &mod : modules_) { if (addr >= mod.start_ && addr <= mod.end_) - return mod.decode_sym(addr, sym); + return mod.find_addr(addr, sym); } return false; } -bool ProcSyms::resolve_name(const char *name, uint64_t *addr) { - *addr = 0x0; +bool ProcSyms::resolve_name(const char *module, const char *name, + uint64_t *addr) { + if (procstat_.is_stale()) + refresh(); + + for (Module &mod : modules_) { + if (mod.name_ == module) + return mod.find_name(name, addr); + } return false; } @@ -198,6 +133,10 @@ int ProcSyms::Module::_add_symbol(const char *symname, uint64_t start, return 0; } +bool ProcSyms::Module::is_so() const { + return strstr(name_.c_str(), ".so") != nullptr; +} + void ProcSyms::Module::load_sym_table() { if (syms_.size()) return; @@ -205,7 +144,19 @@ void ProcSyms::Module::load_sym_table() { bcc_elf_foreach_sym(name_.c_str(), _add_symbol, this); } -bool ProcSyms::Module::decode_sym(uint64_t addr, struct bcc_symbol *sym) { +bool ProcSyms::Module::find_name(const char *symname, uint64_t *addr) { + load_sym_table(); + + for (Symbol &s : syms_) { + if (s.name == symname) { + *addr = is_so() ? start_ + s.start : s.start; + return true; + } + } + return false; +} + +bool ProcSyms::Module::find_addr(uint64_t addr, struct bcc_symbol *sym) { uint64_t offset = is_so() ? (addr - start_) : addr; load_sym_table(); @@ -240,7 +191,7 @@ int bcc_symcache_resolve(void *resolver, uint64_t addr, int bcc_symcache_resolve_name(void *resolver, const char *name, uint64_t *addr) { SymbolCache *cache = static_cast(resolver); - return cache->resolve_name(name, addr) ? 0 : -1; + return cache->resolve_name(nullptr, name, addr) ? 0 : -1; } void bcc_symcache_refresh(void *resolver) { @@ -251,6 +202,7 @@ void bcc_symcache_refresh(void *resolver) { static int _find_sym(const char *symname, uint64_t addr, uint64_t end, int flags, void *payload) { struct bcc_symbol *sym = (struct bcc_symbol *)payload; + // TODO: check for actual function symbol in flags if (!strcmp(sym->name, symname)) { sym->offset = addr; return -1; @@ -258,6 +210,10 @@ static int _find_sym(const char *symname, uint64_t addr, uint64_t end, return 0; } +int bcc_find_symbol_addr(struct bcc_symbol *sym) { + return bcc_elf_foreach_sym(sym->module, _find_sym, sym); +} + int bcc_resolve_symname(const char *module, const char *symname, const uint64_t addr, struct bcc_symbol *sym) { uint64_t load_addr; @@ -286,8 +242,10 @@ int bcc_resolve_symname(const char *module, const char *symname, sym->name = symname; sym->offset = addr; - if (sym->name && sym->offset == 0x0) - bcc_elf_foreach_sym(sym->module, _find_sym, sym); + if (sym->name && sym->offset == 0x0) { + if (bcc_find_symbol_addr(sym) < 0) + return -1; + } if (sym->offset == 0x0) return -1; diff --git a/src/cc/bcc_syms.h b/src/cc/bcc_syms.h index 1ea2f93d16fb..d82054a97934 100644 --- a/src/cc/bcc_syms.h +++ b/src/cc/bcc_syms.h @@ -20,6 +20,8 @@ extern "C" { #endif +#include + struct bcc_symbol { const char *name; const char *module; @@ -31,6 +33,7 @@ int bcc_symcache_resolve(void *symcache, uint64_t addr, struct bcc_symbol *sym); int bcc_symcache_resolve_name(void *resolver, const char *name, uint64_t *addr); void bcc_symcache_refresh(void *resolver); +int bcc_find_symbol_addr(struct bcc_symbol *sym); int bcc_resolve_symname(const char *module, const char *symname, const uint64_t addr, struct bcc_symbol *sym); #ifdef __cplusplus diff --git a/src/cc/syms.h b/src/cc/syms.h new file mode 100644 index 000000000000..d5ddb5a67024 --- /dev/null +++ b/src/cc/syms.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016 GitHub, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include +#include +#include + +#include + +class ProcStat { + std::string procfs_; + ino_t inode_; + ino_t getinode_(); + +public: + ProcStat(int pid); + bool is_stale() { return inode_ != getinode_(); } + void reset() { inode_ = getinode_(); } +}; + +class SymbolCache { +public: + virtual void refresh() = 0; + virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym) = 0; + virtual bool resolve_name(const char *module, const char *name, + uint64_t *addr) = 0; +}; + +class KSyms : SymbolCache { + struct Symbol { + Symbol(const char *name, uint64_t addr) : name(name), addr(addr) {} + std::string name; + uint64_t addr; + + bool operator<(const Symbol &rhs) const { return addr < rhs.addr; } + }; + + std::vector syms_; + std::unordered_map symnames_; + static void _add_symbol(const char *, uint64_t, void *); + +public: + virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym); + virtual bool resolve_name(const char *unused, const char *name, + uint64_t *addr); + virtual void refresh(); +}; + +class ProcSyms : SymbolCache { + struct Symbol { + Symbol(const char *name, uint64_t start, uint64_t size, int flags = 0) + : name(name), start(start), size(size), flags(flags) {} + std::string name; + uint64_t start; + uint64_t size; + int flags; + }; + + struct Module { + Module(const char *name, uint64_t start, uint64_t end) + : name_(name), start_(start), end_(end) {} + std::string name_; + uint64_t start_; + uint64_t end_; + std::vector syms_; + + void load_sym_table(); + bool find_addr(uint64_t addr, struct bcc_symbol *sym); + bool find_name(const char *symname, uint64_t *addr); + bool is_so() const; + + static int _add_symbol(const char *symname, uint64_t start, uint64_t end, + int flags, void *p); + }; + + int pid_; + std::vector modules_; + ProcStat procstat_; + + static int _add_module(const char *, uint64_t, uint64_t, void *); + +public: + ProcSyms(int pid); + virtual void refresh(); + virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym); + virtual bool resolve_name(const char *module, const char *name, + uint64_t *addr); +};