capstone: deal properly with symbols outside .text section

Especially for dynamically linked ELF binaries (such as those in the
testing/ subdirectory), symbols with a start address outside the .text
section may exist.  This change skips any symbol that is not fully within
this section (and assigns a reasonable size to a zero-sized last symbol
within the symbol table), and turns green all Capstone-related test cases.

Change-Id: I2b51d0f21f325e6052ebc36d9533621bdf9aa38d
This commit is contained in:
Horst Schirmeier
2020-03-16 15:44:08 +01:00
committed by Robin Thunig
parent 4e07ba50bd
commit b94ef2acec
2 changed files with 26 additions and 18 deletions

View File

@ -28,8 +28,8 @@ CapstoneToFailTranslator *CapstoneDisassembler::getTranslator() {
return ctofail;
}
std::map<uint64_t, uint64_t> CapstoneDisassembler::get_symtab_map(uint32_t sect_size) {
// Make a list of all the symbols in this section.
std::map<uint64_t, uint64_t> CapstoneDisassembler::get_symtab_map(uint64_t sect_addr, uint64_t sect_size) {
// Make a list of all the symbols (virtual address, size) in this section.
std::vector<std::pair<uint64_t, uint64_t> > symbols;
for (ElfReader::container_t::const_iterator it = m_elf->sym_begin(); it != m_elf->sym_end(); ++it) {
@ -46,25 +46,35 @@ std::map<uint64_t, uint64_t> CapstoneDisassembler::get_symtab_map(uint32_t sect_
// Sort the symbols by address, just in case they didn't come in that way.
std::sort(symbols.begin(), symbols.end());
std::map<uint64_t, uint64_t> symtab_map;
std::map<uint64_t, uint64_t> symtab_map; // start (virtual address), size
uint64_t start;
uint64_t end; // exclusive
uint64_t size;
for (unsigned si = 0, se = symbols.size(); si != se; ++si) {
start = symbols[si].first;
if (symbols[si].second == 0) {
// The end is either the size of the section or the beginning of the next symbol.
size = symbols[si].second;
// only admit symbols that start within this section
if (start < sect_addr || sect_addr + sect_size <= start) {
continue;
}
if (size == 0) {
// The end is either the end of the section or the beginning of the next symbol.
if (si == se - 1)
end = sect_size;
// Make sure this symbol takes up space.
// Last symbol? Span until section end.
size = sect_addr + sect_size - start;
else if (symbols[si + 1].first != start)
end = symbols[si + 1].first;
// There is distance to the next symbol? Cover it.
size = symbols[si + 1].first - start;
else
// This symbol has the same address as the next symbol. Skip it.
continue;
symbols[si].second = end - start;
symbols[si].second = size;
}
symtab_map[symbols[si].first] = symbols[si].second;
// limit the symbol size to within this section
if (start + size > sect_addr + sect_size) {
size = sect_addr + sect_size - start;
}
symtab_map[symbols[si].first] = size;
}
#if 0
for (std::map<uint64_t, uint64_t>::iterator it=symtab_map.begin(); it!=symtab_map.end(); ++it)
@ -113,12 +123,10 @@ int CapstoneDisassembler::disassemble_section(Elf_Data *data, Elf32_Shdr *shdr32
for (std::map<uint64_t, uint64_t>::iterator it=symtab_map.begin(); it!=symtab_map.end(); ++it) {
if (m_elf->m_elfclass == ELFCLASS32) {
count = cs_disasm(handle,
(uint8_t *) ((uint64_t) data->d_buf + (uint64_t) it->first - (uint64_t) shdr32->sh_addr),
count = cs_disasm(handle, (uint8_t *) data->d_buf + it->first - shdr32->sh_addr,
it->second, it->first, 0, &insn);
} else {
count = cs_disasm(handle,
(uint8_t *) ((uint64_t) data->d_buf + (uint64_t) it->first - (uint64_t) shdr64->sh_addr),
count = cs_disasm(handle, (uint8_t *) data->d_buf + it->first - shdr64->sh_addr,
it->second, it->first, 0, &insn);
}
@ -274,9 +282,9 @@ void CapstoneDisassembler::disassemble() {
}
std::map<uint64_t, uint64_t> symtab_map;
if (m_elf->m_elfclass == ELFCLASS32) {
symtab_map = get_symtab_map(shdr32->sh_size);
symtab_map = get_symtab_map(shdr32->sh_addr, shdr32->sh_size);
} else if (m_elf->m_elfclass == ELFCLASS64) {
symtab_map = get_symtab_map(shdr64->sh_size);
symtab_map = get_symtab_map(shdr64->sh_addr, shdr64->sh_size);
}
disassemble_section(data, shdr32, shdr64, symtab_map);

View File

@ -76,7 +76,7 @@ public:
private:
int disassemble_section(Elf_Data *data, Elf32_Shdr *shdr, Elf64_Shdr *shdr64, std::map<uint64_t, uint64_t> symtab_map);
std::map<uint64_t, uint64_t> get_symtab_map(uint32_t sect_size);
std::map<uint64_t, uint64_t> get_symtab_map(uint64_t sect_addr, uint64_t sect_size);
};
}