Added support for splitted debug info; advancements

This commit is contained in:
Alexey Milovidov 2019-07-30 19:12:53 +03:00
parent 1d289b5b49
commit 72e0fbd861
2 changed files with 29 additions and 10 deletions

View File

@ -16,7 +16,10 @@ namespace
{
/// Notes: "PHDR" is "Program Headers".
/// To look at program headers, you can run: objdump -p ./clickhouse-server
/// To look at program headers, run:
/// readelf -l ./clickhouse-server
/// To look at section headers, run:
/// readelf -S ./clickhouse-server
/// Also look at: https://wiki.osdev.org/ELF
/// Also look at: man elf
/// http://www.linker-aliens.org/blogs/ali/entry/inside_elf_symbol_tables/
@ -25,11 +28,14 @@ namespace
/// Based on the code of musl-libc and the answer of Kanalpiroge on
/// https://stackoverflow.com/questions/15779185/list-all-the-functions-symbols-on-the-fly-in-c-code-on-a-linux-architecture
/// It does not extract all the symbols (but only public - exported and used for dynamic linking),
/// but will work if we cannot find or parse ELF files.
void collectSymbolsFromProgramHeaders(dl_phdr_info * info,
std::vector<SymbolIndex::Symbol> & symbols)
{
/* Iterate over all headers of the current shared lib
* (first call is for the executable itself) */
* (first call is for the executable itself)
*/
for (size_t header_index = 0; header_index < info->dlpi_phnum; ++header_index)
{
/* Further processing is only needed if the dynamic section is reached
@ -223,11 +229,16 @@ void collectSymbolsFromELF(dl_phdr_info * info,
object_name = "/proc/self/exe";
std::error_code ec;
object_name = std::filesystem::canonical(object_name, ec);
std::filesystem::path canonical_path = std::filesystem::canonical(object_name, ec);
if (ec)
return;
/// Debug info and symbol table sections may be splitted to separate binary.
std::filesystem::path debug_info_path = std::filesystem::path("/usr/lib/debug") / canonical_path;
object_name = std::filesystem::exists(debug_info_path) ? debug_info_path : canonical_path;
SymbolIndex::Object object;
object.elf = std::make_unique<Elf>(object_name);
object.address_begin = reinterpret_cast<const void *>(info->dlpi_addr);
@ -248,10 +259,6 @@ void collectSymbolsFromELF(dl_phdr_info * info,
*/
int collectSymbols(dl_phdr_info * info, size_t, void * data_ptr)
{
/* ElfW is a macro that creates proper typenames for the used system architecture
* (e.g. on a 32 bit system, ElfW(Dyn*) becomes "Elf32_Dyn*")
*/
SymbolIndex::Data & data = *reinterpret_cast<SymbolIndex::Data *>(data_ptr);
collectSymbolsFromProgramHeaders(info, data.symbols);
@ -287,7 +294,15 @@ const T * find(const void * address, const std::vector<T> & vec)
void SymbolIndex::update()
{
dl_iterate_phdr(collectSymbols, &data.symbols);
std::sort(data.objects.begin(), data.objects.end(), [](const Object & a, const Object & b) { return a.address_begin < b.address_begin; });
std::sort(data.symbols.begin(), data.symbols.end(), [](const Symbol & a, const Symbol & b) { return a.address_begin < b.address_begin; });
/// We found symbols both from loaded program headers and from ELF symbol tables.
data.symbols.erase(std::unique(data.symbols.begin(), data.symbols.end(), [](const Symbol & a, const Symbol & b)
{
return a.address_begin == b.address_begin && a.address_end == b.address_end;
}), data.symbols.end());
}
const SymbolIndex::Symbol * SymbolIndex::findSymbol(const void * address) const

View File

@ -1,12 +1,16 @@
#include <Common/SymbolIndex.h>
#include <Common/Elf.h>
#include <Common/Dwarf.h>
#include <Core/Defines.h>
#include <common/demangle.h>
#include <iostream>
#include <dlfcn.h>
void f() {}
NO_INLINE const void * getAddress()
{
return __builtin_return_address(0);
}
using namespace DB;
@ -37,8 +41,8 @@ int main(int argc, char ** argv)
else
std::cerr << "dladdr: Not found\n";
Elf elf("/proc/self/exe");
Dwarf dwarf(elf);
auto object = symbol_index.findObject(getAddress());
Dwarf dwarf(*object->elf);
Dwarf::LocationInfo location;
if (dwarf.findAddress(uintptr_t(address), location, Dwarf::LocationInfoMode::FAST))