mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Don't use debug info from ELF file if it doesn't correspond to the running binary.
This commit is contained in:
parent
f53da4d36b
commit
4a052f60c7
@ -54,6 +54,18 @@ Elf::Elf(const std::string & path)
|
||||
throw Exception("The ELF is truncated (section names string table points after end of file)", ErrorCodes::CANNOT_PARSE_ELF);
|
||||
|
||||
section_names = reinterpret_cast<const char *>(mapped + section_names_offset);
|
||||
|
||||
/// Get program headers
|
||||
|
||||
ElfOff program_header_offset = header->e_phoff;
|
||||
uint16_t program_header_num_entries = header->e_phnum;
|
||||
|
||||
if (!program_header_offset
|
||||
|| !program_header_num_entries
|
||||
|| program_header_offset + program_header_num_entries * sizeof(ElfPhdr) > elf_size)
|
||||
throw Exception("The ELF is truncated (program header points after end of file)", ErrorCodes::CANNOT_PARSE_ELF);
|
||||
|
||||
program_headers = reinterpret_cast<const ElfPhdr *>(mapped + program_header_offset);
|
||||
}
|
||||
|
||||
|
||||
@ -104,6 +116,40 @@ std::optional<Elf::Section> Elf::findSectionByName(const char * name) const
|
||||
}
|
||||
|
||||
|
||||
String Elf::getBuildID() const
|
||||
{
|
||||
for (size_t idx = 0; idx < header->e_phnum; ++idx)
|
||||
{
|
||||
const ElfPhdr & phdr = program_headers[idx];
|
||||
|
||||
if (phdr.p_type == PT_NOTE)
|
||||
return getBuildID(mapped + phdr.p_offset, phdr.p_filesz);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
String Elf::getBuildID(const char * nhdr_pos, size_t size)
|
||||
{
|
||||
const char * nhdr_end = nhdr_pos + size;
|
||||
|
||||
while (nhdr_pos < nhdr_end)
|
||||
{
|
||||
const ElfNhdr & nhdr = *reinterpret_cast<const ElfNhdr *>(nhdr_pos);
|
||||
|
||||
nhdr_pos += sizeof(ElfNhdr) + nhdr.n_namesz;
|
||||
if (nhdr.n_type == NT_GNU_BUILD_ID)
|
||||
{
|
||||
const char * build_id = nhdr_pos;
|
||||
return {build_id, nhdr.n_descsz};
|
||||
}
|
||||
nhdr_pos += nhdr.n_descsz;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
const char * Elf::Section::name() const
|
||||
{
|
||||
if (!elf.section_names)
|
||||
|
@ -17,6 +17,7 @@ using ElfEhdr = ElfW(Ehdr);
|
||||
using ElfOff = ElfW(Off);
|
||||
using ElfPhdr = ElfW(Phdr);
|
||||
using ElfShdr = ElfW(Shdr);
|
||||
using ElfNhdr = ElfW(Nhdr);
|
||||
using ElfSym = ElfW(Sym);
|
||||
|
||||
|
||||
@ -53,12 +54,18 @@ public:
|
||||
const char * end() const { return mapped + elf_size; }
|
||||
size_t size() const { return elf_size; }
|
||||
|
||||
/// Obtain build id from PT_NOTES section of program headers. Return empty string if does not exist.
|
||||
/// The string is returned in binary. Note that "readelf -n ./clickhouse-server" prints it in hex.
|
||||
String getBuildID() const;
|
||||
static String getBuildID(const char * nhdr_pos, size_t size);
|
||||
|
||||
private:
|
||||
MMapReadBufferFromFile in;
|
||||
size_t elf_size;
|
||||
const char * mapped;
|
||||
const ElfEhdr * header;
|
||||
const ElfShdr * section_headers;
|
||||
const ElfPhdr * program_headers;
|
||||
const char * section_names = nullptr;
|
||||
};
|
||||
|
||||
|
@ -196,6 +196,20 @@ void collectSymbolsFromProgramHeaders(dl_phdr_info * info,
|
||||
}
|
||||
|
||||
|
||||
String getBuildIDFromProgramHeaders(dl_phdr_info * info)
|
||||
{
|
||||
for (size_t header_index = 0; header_index < info->dlpi_phnum; ++header_index)
|
||||
{
|
||||
const ElfPhdr & phdr = info->dlpi_phdr[header_index];
|
||||
if (phdr.p_type != PT_NOTE)
|
||||
continue;
|
||||
|
||||
return Elf::getBuildID(reinterpret_cast<const char *>(info->dlpi_addr + phdr.p_vaddr), phdr.p_memsz);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
void collectSymbolsFromELFSymbolTable(
|
||||
dl_phdr_info * info,
|
||||
const Elf & elf,
|
||||
@ -283,8 +297,31 @@ void collectSymbolsFromELF(dl_phdr_info * info,
|
||||
|
||||
object_name = std::filesystem::exists(debug_info_path) ? debug_info_path : canonical_path;
|
||||
|
||||
/// But we have to compare Build ID to check that debug info corresponds to the same executable.
|
||||
String our_build_id = getBuildIDFromProgramHeaders(info);
|
||||
|
||||
SymbolIndex::Object object;
|
||||
object.elf = std::make_unique<Elf>(object_name);
|
||||
|
||||
String file_build_id = object.elf->getBuildID();
|
||||
|
||||
if (our_build_id != file_build_id)
|
||||
{
|
||||
/// If debug info doesn't correspond to our binary, fallback to the info in our binary.
|
||||
if (object_name != canonical_path)
|
||||
{
|
||||
object_name = canonical_path;
|
||||
object.elf = std::make_unique<Elf>(object_name);
|
||||
|
||||
/// But it can still be outdated, for example, if executable file was deleted from filesystem and replaced by another file.
|
||||
file_build_id = object.elf->getBuildID();
|
||||
if (our_build_id != file_build_id)
|
||||
return;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
object.address_begin = reinterpret_cast<const void *>(info->dlpi_addr);
|
||||
object.address_end = reinterpret_cast<const void *>(info->dlpi_addr + object.elf->size());
|
||||
object.name = object_name;
|
||||
|
Loading…
Reference in New Issue
Block a user