std::string ToString() const {
std::string s = "0x";
for (size_t i = 0; i < BUILD_ID_SIZE; ++i) {
- s += android::base::StringPrintf("0x%02x", data_[i]);
+ s += android::base::StringPrintf("%02x", data_[i]);
}
return s;
}
" include pid, tid, comm, dso, symbol, dso_from, dso_to, symbol_from\n"
" symbol_to. dso_from, dso_to, symbol_from, symbol_to can only be\n"
" used with -b option. Default keys are \"comm,pid,tid,dso,symbol\"\n"
- " --symfs <dir> Look for files with symbols relative to this directory.\n"),
+ " --symfs <dir> Look for files with symbols relative to this directory.\n"
+ " --vmlinux <file>\n"
+ " Parse kernel symbols from <file>.\n"),
record_filename_("perf.data"),
use_branch_address_(false),
accumulate_callchain_(false),
bool ReportCommand::ParseOptions(const std::vector<std::string>& args) {
bool demangle = true;
std::string symfs_dir;
+ std::string vmlinux;
bool print_sample_count = false;
std::vector<std::string> sort_keys = {"comm", "pid", "tid", "dso", "symbol"};
for (size_t i = 0; i < args.size(); ++i) {
return false;
}
symfs_dir = args[i];
+ } else if (args[i] == "--vmlinux") {
+ if (!NextArgumentOrError(args, &i)) {
+ return false;
+ }
+ vmlinux = args[i];
} else {
ReportUnknownOption(args, i);
return false;
}
}
- DsoFactory::SetDemangle(demangle);
- if (!DsoFactory::SetSymFsDir(symfs_dir)) {
+ DsoFactory::GetInstance()->SetDemangle(demangle);
+ if (!DsoFactory::GetInstance()->SetSymFsDir(symfs_dir)) {
return false;
}
+ if (!vmlinux.empty()) {
+ DsoFactory::GetInstance()->SetVmlinux(vmlinux);
+ }
if (!accumulate_callchain_) {
displayable_items_.push_back(
for (auto& r : records) {
build_ids.push_back(std::make_pair(r.filename, r.build_id));
}
- DsoFactory::SetBuildIds(build_ids);
+ DsoFactory::GetInstance()->SetBuildIds(build_ids);
std::string arch = record_file_reader_->ReadFeatureString(PerfFileFormat::FEAT_ARCH);
if (!arch.empty()) {
return nullptr;
}
-bool DsoFactory::demangle = true;
+DsoFactory* DsoFactory::GetInstance() {
+ static DsoFactory dso_factory;
+ return &dso_factory;
+}
-void DsoFactory::SetDemangle(bool demangle) {
- DsoFactory::demangle = demangle;
+DsoFactory::DsoFactory() : demangle_(true) {
}
-std::string DsoFactory::symfs_dir;
+void DsoFactory::SetDemangle(bool demangle) {
+ demangle_ = demangle;
+}
bool DsoFactory::SetSymFsDir(const std::string& symfs_dir) {
std::string dirname = symfs_dir;
return false;
}
}
- DsoFactory::symfs_dir = dirname;
+ symfs_dir_ = dirname;
return true;
}
-std::unordered_map<std::string, BuildId> DsoFactory::build_id_map;
+void DsoFactory::SetVmlinux(const std::string& vmlinux) {
+ vmlinux_ = vmlinux;
+}
void DsoFactory::SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids) {
std::unordered_map<std::string, BuildId> map;
LOG(DEBUG) << "build_id_map: " << pair.first << ", " << pair.second.ToString();
map.insert(pair);
}
- build_id_map = std::move(map);
+ build_id_map_ = std::move(map);
}
static bool IsKernelFunctionSymbol(const KernelSymbol& symbol) {
return false;
}
+static void VmlinuxSymbolCallback(const ElfFileSymbol& elf_symbol, DsoEntry* dso) {
+ if (elf_symbol.is_func) {
+ SymbolEntry* symbol = new SymbolEntry{
+ elf_symbol.name, // name
+ elf_symbol.vaddr, // addr
+ elf_symbol.len, // len
+ };
+ dso->symbols.insert(std::unique_ptr<SymbolEntry>(symbol));
+ }
+}
+
static void FixupSymbolLength(DsoEntry* dso) {
SymbolEntry* prev_symbol = nullptr;
for (auto& symbol : dso->symbols) {
}
}
-// TODO: Fix the way to get kernel symbols. See b/22179177.
std::unique_ptr<DsoEntry> DsoFactory::LoadKernel() {
std::unique_ptr<DsoEntry> dso(new DsoEntry);
dso->path = "[kernel.kallsyms]";
BuildId build_id = GetExpectedBuildId(DEFAULT_KERNEL_FILENAME_FOR_BUILD_ID);
- BuildId real_build_id;
- GetKernelBuildId(&real_build_id);
- bool match = (build_id == real_build_id);
- LOG(DEBUG) << "check kernel build id (" << (match ? "match" : "mismatch") << "): expected "
- << build_id.ToString() << ", real " << real_build_id.ToString();
- if (match) {
- ProcessKernelSymbols("/proc/kallsyms",
- std::bind(&KernelSymbolCallback, std::placeholders::_1, dso.get()));
+ if (!vmlinux_.empty()) {
+ ParseSymbolsFromElfFile(vmlinux_, build_id,
+ std::bind(VmlinuxSymbolCallback, std::placeholders::_1, dso.get()));
+ } else {
+ BuildId real_build_id;
+ GetKernelBuildId(&real_build_id);
+ bool match = (build_id == real_build_id);
+ LOG(DEBUG) << "check kernel build id (" << (match ? "match" : "mismatch") << "): expected "
+ << build_id.ToString() << ", real " << real_build_id.ToString();
+ if (match) {
+ ProcessKernelSymbols("/proc/kallsyms",
+ std::bind(&KernelSymbolCallback, std::placeholders::_1, dso.get()));
+ }
}
FixupSymbolLength(dso.get());
return dso;
std::unique_ptr<DsoEntry> dso(new DsoEntry);
dso->path = dso_path;
BuildId build_id = GetExpectedBuildId(dso_path);
- ParseSymbolsFromElfFile(symfs_dir + dso_path, build_id,
+ ParseSymbolsFromElfFile(symfs_dir_ + dso_path, build_id,
std::bind(ParseSymbolCallback, std::placeholders::_1, dso.get(),
SymbolFilterForKernelModule));
FixupSymbolLength(dso.get());
dso->path = dso_path;
BuildId build_id = GetExpectedBuildId(dso_path);
ParseSymbolsFromElfFile(
- symfs_dir + dso_path, build_id,
+ symfs_dir_ + dso_path, build_id,
std::bind(ParseSymbolCallback, std::placeholders::_1, dso.get(), SymbolFilterForDso));
- if (demangle) {
+ if (demangle_) {
for (auto& symbol : dso->symbols) {
DemangleInPlace(&symbol->name);
}
}
BuildId DsoFactory::GetExpectedBuildId(const std::string& filename) {
- auto it = build_id_map.find(filename);
- if (it != build_id_map.end()) {
+ auto it = build_id_map_.find(filename);
+ if (it != build_id_map_.end()) {
return it->second;
}
return BuildId();
class DsoFactory {
public:
- static void SetDemangle(bool demangle);
- static bool SetSymFsDir(const std::string& symfs_dir);
- static void SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids);
- static std::unique_ptr<DsoEntry> LoadKernel();
- static std::unique_ptr<DsoEntry> LoadKernelModule(const std::string& dso_path);
- static std::unique_ptr<DsoEntry> LoadDso(const std::string& dso_path);
+ static DsoFactory* GetInstance();
+ void SetDemangle(bool demangle);
+ bool SetSymFsDir(const std::string& symfs_dir);
+ void SetVmlinux(const std::string& vmlinux);
+ void SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids);
+ std::unique_ptr<DsoEntry> LoadKernel();
+ std::unique_ptr<DsoEntry> LoadKernelModule(const std::string& dso_path);
+ std::unique_ptr<DsoEntry> LoadDso(const std::string& dso_path);
private:
- static BuildId GetExpectedBuildId(const std::string& filename);
+ DsoFactory();
+ BuildId GetExpectedBuildId(const std::string& filename);
- static bool demangle;
- static std::string symfs_dir;
- static std::unordered_map<std::string, BuildId> build_id_map;
+ bool demangle_;
+ std::string symfs_dir_;
+ std::string vmlinux_;
+ std::unordered_map<std::string, BuildId> build_id_map_;
};
#endif // SIMPLE_PERF_DSO_H_
if (symbol.name.empty()) {
continue;
}
-
+ symbol.vaddr = elf_symbol.st_value;
symbol.start_in_file = elf_symbol.st_value - shdr->sh_addr + shdr->sh_offset;
if ((symbol.start_in_file & 1) != 0 && is_arm) {
// Arm sets bit 0 to mark it as thumb code, remove the flag.
static const std::string linker_prefix = "__dl_";
struct ElfFileSymbol {
+ uint64_t vaddr;
uint64_t start_in_file;
uint64_t len;
bool is_func;
DsoEntry* SampleTree::FindKernelDsoOrNew(const std::string& filename) {
if (filename == DEFAULT_KERNEL_MMAP_NAME) {
if (kernel_dso_ == nullptr) {
- kernel_dso_ = DsoFactory::LoadKernel();
+ kernel_dso_ = DsoFactory::GetInstance()->LoadKernel();
}
return kernel_dso_.get();
}
auto it = module_dso_tree_.find(filename);
if (it == module_dso_tree_.end()) {
- module_dso_tree_[filename] = DsoFactory::LoadKernelModule(filename);
+ module_dso_tree_[filename] = DsoFactory::GetInstance()->LoadKernelModule(filename);
it = module_dso_tree_.find(filename);
}
return it->second.get();
DsoEntry* SampleTree::FindUserDsoOrNew(const std::string& filename) {
auto it = user_dso_tree_.find(filename);
if (it == user_dso_tree_.end()) {
- user_dso_tree_[filename] = DsoFactory::LoadDso(filename);
+ user_dso_tree_[filename] = DsoFactory::GetInstance()->LoadDso(filename);
it = user_dso_tree_.find(filename);
}
return it->second.get();