Last active
December 9, 2017 06:26
-
-
Save 303248153/f792ed53a4245b46900d4ce3926888e6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* g++ -Wall -Wextra --std=c++14 -g abc.cpp -lbfd && valgrind ./a.out */ | |
#include <bfd.h> | |
#include <elf.h> | |
#include <cassert> | |
#include <cstring> | |
#include <iostream> | |
#include <fstream> | |
#include <vector> | |
#include <string> | |
#include <array> | |
#include <algorithm> | |
struct LoadEntry { | |
std::size_t fileOffset; | |
std::size_t virtualAddressStart; | |
std::size_t virtualAddressEnd; | |
}; | |
template <class EHdr, class Phdr> | |
void loadLoadEntriesByElfClass(std::ifstream& file, std::vector<LoadEntry>& entries) { | |
EHdr header; | |
file.seekg(0); | |
if (!file.read((char*)&header, sizeof(header))) { | |
std::cout << "read header error" << std::endl; | |
return; | |
} | |
std::cout << "program headers: " << header.e_phnum << " at " << header.e_phoff << std::endl; | |
std::vector<Phdr> programHeaders; | |
programHeaders.resize(header.e_phnum); | |
file.seekg(header.e_phoff); | |
if (!file.read((char*)programHeaders.data(), sizeof(Phdr) * programHeaders.size())) { | |
std::cout << "read program header error" << std::endl; | |
return; | |
} | |
for (auto& programHeader : programHeaders) { | |
if (programHeader.p_type == PT_LOAD) { | |
std::cout << "found load entry" << std::endl; | |
entries.emplace_back(LoadEntry({ | |
programHeader.p_offset, | |
programHeader.p_vaddr, | |
programHeader.p_vaddr + programHeader.p_memsz | |
})); | |
} | |
} | |
} | |
void loadLoadEntries(const char* path, std::vector<LoadEntry>& entries) { | |
std::ifstream file(path); | |
std::array<char, EI_NIDENT> ident; | |
if (!file.read(ident.data(), ident.size())) { | |
std::cout << "read ident error" << std::endl; | |
return; | |
} | |
if (std::memcmp(ident.data(), ELFMAG, SELFMAG) != 0) { | |
std::cout << "magic not matched" << std::endl; | |
return; | |
} | |
std::size_t elfClass = ident.at(EI_CLASS); | |
if (elfClass == ELFCLASS32) { | |
loadLoadEntriesByElfClass<Elf32_Ehdr, Elf32_Phdr>(file, entries); | |
} else if (elfClass == ELFCLASS64) { | |
std::cout << "parse 64" << std::endl; | |
loadLoadEntriesByElfClass<Elf64_Ehdr, Elf64_Phdr>(file, entries); | |
} else { | |
std::cout << "unsupported elf class" << std::endl; | |
return; | |
} | |
} | |
int printFile(const char* path) { | |
std::vector<LoadEntry> entries; | |
loadLoadEntries(path, entries); | |
std::cout << "load entires: " << entries.size() << std::endl; | |
bfd* file = bfd_openr(path, nullptr); | |
if (file == nullptr) { | |
perror("bfd_openr"); | |
return -1; | |
} | |
char** matching = nullptr; | |
if (!bfd_check_format_matches(file, bfd_object, &matching)) { | |
std::cout << "not object file" << std::endl; | |
return -1; | |
} | |
void* minisyms = nullptr; | |
unsigned int size = 0; | |
long count = bfd_read_minisymbols(file, true, &minisyms, &size); | |
std::cout << "count: " << count << std::endl; | |
asymbol* store = bfd_make_empty_symbol(file); | |
auto from = (bfd_byte*)minisyms; | |
auto to = from + count * size; | |
std::vector<asymbol*> syms; | |
for (; from < to; from += size) { | |
asymbol* sym = bfd_minisymbol_to_symbol(file, true, from, store); | |
if (sym == nullptr) { | |
perror("bfd_minisymbol_to_symbol"); | |
return -1; | |
} | |
syms.emplace_back(sym); | |
} | |
std::sort(syms.begin(), syms.end(), [](const auto& a, const auto& b) { | |
// sort by symbol value, then by section vma | |
// see size_forward1 in nm.c in binutils | |
auto valueA = bfd_asymbol_value(a); | |
auto valueB = bfd_asymbol_value(b); | |
if (valueA != valueB) { | |
return valueA < valueB; | |
} | |
auto baseA = bfd_asymbol_base(a); // section->vma | |
auto baseB = bfd_asymbol_base(b); | |
if (baseA != baseB) { | |
return baseA < baseB; | |
} | |
return false; | |
}); | |
std::vector<std::size_t> sizes; | |
char* target = bfd_get_target(file); | |
bool isElf32 = std::strncmp(target, "elf32", 5) == 0; | |
bool isElf64 = std::strncmp(target, "elf64", 5) == 0; | |
std::cout << "isElf32: " << isElf32 << " isElf64: " << isElf64 << std::endl; | |
for (auto it = syms.begin(); it < syms.end(); ++it) { | |
asymbol* sym = *it; | |
std::size_t size = 0; | |
if ((sym->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) != 0) { | |
// don't have a full type set of data available, see nm.c for full explanation | |
} else if (isElf32) { | |
size = *(std::uint32_t*)(((char*)sym)+sizeof(asymbol)+8); | |
} else if (isElf64) { | |
size = *(std::uint64_t*)(((char*)sym)+sizeof(asymbol)+8); | |
} | |
std::size_t guestSize = 0; | |
asymbol* next = (it + 1 < syms.end()) ? *(it + 1) : nullptr; | |
if (next != nullptr && bfd_asymbol_base(sym) == bfd_asymbol_base(next)) { | |
guestSize = bfd_asymbol_value(next) - bfd_asymbol_value(sym); | |
} else { | |
guestSize = bfd_asymbol_base(sym) + | |
bfd_section_size(file, bfd_get_section(sym)) - | |
bfd_asymbol_value(sym); | |
} | |
// guestSize may be 0 if two symbol have same address | |
// guestSize may less than size if it's a variable and file only contains it's first part | |
// calculate the actual file offset with LOAD entry | |
std::size_t offset = bfd_asymbol_value(sym); | |
std::size_t offsetOriginal = offset; | |
for (auto& entry : entries) { | |
if (offset >= entry.virtualAddressStart && offset < entry.virtualAddressEnd) { | |
offset = offset - entry.virtualAddressStart + entry.fileOffset; | |
break; | |
} | |
} | |
std::cout << | |
std::hex << offset << "(" << offsetOriginal << ")" << std::dec << "\t" << | |
std::hex << size << std::dec << "\t" << | |
std::hex << guestSize << std::dec << "\t" << | |
bfd_asymbol_name(sym) << std::endl; | |
} | |
free(minisyms); | |
bfd_close(file); | |
return 0; | |
} | |
int main() { | |
printFile("/home/ubuntu/Downloads/live-profiler/tests/Build/LiveProfilerTest"); | |
//printFile("/lib/i386-linux-gnu/libpthread.so.0"); | |
//printFile("/lib/x86_64-linux-gnu/libc-2.26.so"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment