diff options
Diffstat (limited to 'src/common/linux/elfutils.cc')
-rw-r--r-- | src/common/linux/elfutils.cc | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/src/common/linux/elfutils.cc b/src/common/linux/elfutils.cc index ee2f4ac0..1fd504d9 100644 --- a/src/common/linux/elfutils.cc +++ b/src/common/linux/elfutils.cc @@ -75,6 +75,35 @@ void FindElfClassSection(const char *elf_base, } } +template<typename ElfClass> +void FindElfClassSegment(const char *elf_base, + typename ElfClass::Word segment_type, + const void **segment_start, + int *segment_size) { + typedef typename ElfClass::Ehdr Ehdr; + typedef typename ElfClass::Phdr Phdr; + + assert(elf_base); + assert(segment_start); + assert(segment_size); + + assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0); + + const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base); + assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass); + + const Phdr* phdrs = + GetOffset<ElfClass,Phdr>(elf_header, elf_header->e_phoff); + + for (int i = 0; i < elf_header->e_phnum; ++i) { + if (phdrs[i].p_type == segment_type) { + *segment_start = elf_base + phdrs[i].p_offset; + *segment_size = phdrs[i].p_filesz; + return; + } + } +} + } // namespace bool IsValidElf(const void* elf_base) { @@ -126,4 +155,40 @@ bool FindElfSection(const void *elf_mapped_base, return false; } +bool FindElfSegment(const void *elf_mapped_base, + uint32_t segment_type, + const void **segment_start, + int *segment_size, + int *elfclass) { + assert(elf_mapped_base); + assert(segment_start); + assert(segment_size); + + *segment_start = NULL; + *segment_size = 0; + + if (!IsValidElf(elf_mapped_base)) + return false; + + int cls = ElfClass(elf_mapped_base); + if (elfclass) { + *elfclass = cls; + } + + const char* elf_base = + static_cast<const char*>(elf_mapped_base); + + if (cls == ELFCLASS32) { + FindElfClassSegment<ElfClass32>(elf_base, segment_type, + segment_start, segment_size); + return *segment_start != NULL; + } else if (cls == ELFCLASS64) { + FindElfClassSegment<ElfClass64>(elf_base, segment_type, + segment_start, segment_size); + return *segment_start != NULL; + } + + return false; +} + } // namespace google_breakpad |