Changes to handle elf image bases / text link-at addresses (#21)

Figure out the text offset for elf files. When testing on a system that
did not use ASLR by default a user found addr2line being invoked with
the wrong addresses.
This commit is contained in:
Jeremy Rifkin 2023-07-24 21:51:52 -04:00 committed by GitHub
parent d589f2a609
commit 72228ab5e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 96 additions and 7 deletions

View File

@ -250,6 +250,7 @@ static_assert(n_digits(10) == 2, "n_digits utility producing the wrong result");
static_assert(n_digits(11) == 2, "n_digits utility producing the wrong result");
static_assert(n_digits(1024) == 4, "n_digits utility producing the wrong result");
// TODO: Re-evaluate use of off_t
template<typename T, typename std::enable_if<std::is_pod<T>::value, int>::type = 0>
T load_bytes(FILE* obj_file, off_t offset) {
T object;

87
src/platform/elf.hpp Normal file
View File

@ -0,0 +1,87 @@
#ifndef ELF_HPP
#define ELF_HPP
#include "common.hpp"
#if IS_LINUX
#include <array>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <elf.h>
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
T elf_byteswap_if_needed(T value, bool elf_is_little) {
if(is_little_endian() == elf_is_little) {
return value;
} else {
return byteswap(value);
}
}
// TODO: Re-evaluate use of off_t
// I think we can rely on PT_PHDR https://stackoverflow.com/q/61568612/15675011...
static uintptr_t elf_get_module_image_base_from_program_table(
FILE* file,
bool is_64,
bool is_little_endian,
off_t e_phoff,
off_t e_phentsize,
int e_phnum
) {
for(int i = 0; i < e_phnum; i++) {
if(is_64) {
Elf64_Phdr program_header = load_bytes<Elf64_Phdr>(file, e_phoff + e_phentsize * i);
if(elf_byteswap_if_needed(program_header.p_type, is_little_endian) == PT_PHDR) {
return elf_byteswap_if_needed(program_header.p_vaddr, is_little_endian)
- elf_byteswap_if_needed(program_header.p_offset, is_little_endian);
}
} else {
Elf32_Phdr program_header = load_bytes<Elf32_Phdr>(file, e_phoff + e_phentsize * i);
if(elf_byteswap_if_needed(program_header.p_type, is_little_endian) == PT_PHDR) {
return elf_byteswap_if_needed(program_header.p_vaddr, is_little_endian)
- elf_byteswap_if_needed(program_header.p_offset, is_little_endian);
}
}
}
return 0;
}
static uintptr_t elf_get_module_image_base(const std::string& obj_path) {
FILE* file = fopen(obj_path.c_str(), "rb");
// Initial checks/metadata
auto magic = load_bytes<std::array<char, 4>>(file, 0);
internal_verify(magic == (std::array<char, 4>{0x7F, 'E', 'L', 'F'}));
bool is_64 = load_bytes<uint8_t>(file, 4) == 2;
bool is_little_endian = load_bytes<uint8_t>(file, 5) == 1;
internal_verify(load_bytes<uint8_t>(file, 6) == 1, "Unexpected ELF version");
//
if(is_64) {
Elf64_Ehdr file_header = load_bytes<Elf64_Ehdr>(file, 0);
internal_verify(file_header.e_ehsize == sizeof(Elf64_Ehdr));
return elf_get_module_image_base_from_program_table(
file,
is_64,
is_little_endian,
elf_byteswap_if_needed(file_header.e_phoff, is_little_endian),
elf_byteswap_if_needed(file_header.e_phentsize, is_little_endian),
elf_byteswap_if_needed(file_header.e_phnum, is_little_endian)
);
} else {
Elf32_Ehdr file_header = load_bytes<Elf32_Ehdr>(file, 0);
internal_verify(file_header.e_ehsize == sizeof(Elf32_Ehdr));
return elf_get_module_image_base_from_program_table(
file,
is_64,
is_little_endian,
elf_byteswap_if_needed(file_header.e_phoff, is_little_endian),
elf_byteswap_if_needed(file_header.e_phentsize, is_little_endian),
elf_byteswap_if_needed(file_header.e_phnum, is_little_endian)
);
}
}
#endif
#endif

View File

@ -1,13 +1,13 @@
#ifndef MACHO_HPP
#define MACHO_HPP
#include "common.hpp"
#if IS_APPLE
#include <cstdio>
#include <cstring>
#include <type_traits>
#include "common.hpp"
#include <mach-o/loader.h>
#include <mach-o/swap.h>
#include <mach-o/fat.h>

View File

@ -1,15 +1,15 @@
#ifndef PE_HPP
#define PE_HPP
#include "common.hpp"
#if IS_WINDOWS
#include <array>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <string>
#include "common.hpp"
#if IS_WINDOWS
#include <windows.h>
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>

View File

@ -21,6 +21,8 @@
#include <sys/wait.h>
#if IS_APPLE
#include "../platform/mach-o.hpp"
#else
#include "../platform/elf.hpp"
#endif
#elif IS_WINDOWS
#include "../platform/pe.hpp"
@ -166,8 +168,7 @@ namespace cpptrace {
#if !IS_APPLE
uintptr_t get_module_image_base(const dlframe &entry) {
(void)entry;
return 0;
return elf_get_module_image_base(entry.obj_path);
}
#else
uintptr_t get_module_image_base(const dlframe &entry) {