Skip to content

Commit

Permalink
disassembler: Add addSection, verify by address
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonKagstrom committed Feb 7, 2017
1 parent 709f28e commit 1e13fa4
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 24 deletions.
12 changes: 10 additions & 2 deletions src/include/disassembler.hh
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,21 @@ namespace kcov
*/
virtual void setup(const void *header, size_t headerSize) = 0;

/**
* Add an executable section
*
* @param sectionData the data of the section
* @param sectionSize the size of the section
* @param base address the virtual start address
*/
virtual void addSection(const void *sectionData, size_t sectionSize, uint64_t baseAddress) = 0;

/**
* Check if an address is a valid breakpoint "point".
*
* @return true if a breakpoint can be set on this address
*/
virtual bool verify(const void *sectionData, size_t sectionSize,
uint64_t offset) = 0;
virtual bool verify(uint64_t address) = 0;


static IDisassembler &getInstance();
Expand Down
38 changes: 20 additions & 18 deletions src/parsers/bfd-disassembler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,25 @@ class BfdDisassembler : public IDisassembler
m_info.mach = bfd_mach_i386_i386;
}

bool verify(const void *sectionData, size_t sectionSize, uint64_t offset)
void addSection(const void *sectionData, size_t sectionSize, uint64_t baseAddress)
{
SectionCache_t::iterator it = m_cache.find(sectionData);

// Not visited before, disassemble
if (it == m_cache.end()) {
// Insert and reference it
Section *cur = new Section(sectionData, sectionSize, 0);
Section *cur = new Section(sectionData, sectionSize, baseAddress);

cur->disassemble(m_info, m_disassembler);
cur->disassemble(*this, m_info, m_disassembler);

m_cache[sectionData] = cur;
it = m_cache.find(sectionData);
}
}

bool verify(uint64_t address)
{
// The address is valid there is an instruction starting at it
return it->second->getInstruction(offset) != NULL;
return getInstruction(address) != NULL;
}
private:
class Instruction
Expand All @@ -84,7 +86,7 @@ class BfdDisassembler : public IDisassembler
{
}

void disassemble(struct disassemble_info info, disassembler_ftype disassembler)
void disassemble(BfdDisassembler &target, struct disassemble_info info, disassembler_ftype disassembler)
{
if (m_disassembled)
return;
Expand All @@ -105,42 +107,42 @@ class BfdDisassembler : public IDisassembler
if (count < 0)
break;

m_instructions[pc + m_startAddress] = Instruction();
target.m_instructions[pc + m_startAddress] = Instruction();

pc += count;
} while (count > 0 && pc < m_size);
}

Instruction *getInstruction(uint64_t address)
{
if (m_instructions.find(address) == m_instructions.end())
return NULL;

return &m_instructions[address];
}

private:
typedef std::unordered_map<uint64_t, Instruction> InstructionAddressMap_t;

const void *m_data;
const size_t m_size;
const uint64_t m_startAddress;

bool m_disassembled; // Lazy disassembly once it's used
InstructionAddressMap_t m_instructions;
};


Instruction *getInstruction(uint64_t address)
{
if (m_instructions.find(address) == m_instructions.end())
return NULL;

return &m_instructions[address];
}

static int fprintFuncStatic(void *info, const char *fmt, ...)
{
// Do nothing - we're not interested in the actual encoding
return 0;
}
typedef std::unordered_map<const void *, Section *> SectionCache_t;
typedef std::unordered_map<uint64_t, Instruction> InstructionAddressMap_t;

struct disassemble_info m_info;
disassembler_ftype m_disassembler;

SectionCache_t m_cache;
InstructionAddressMap_t m_instructions;
};

IDisassembler &IDisassembler::getInstance()
Expand Down
6 changes: 5 additions & 1 deletion src/parsers/dummy-disassembler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ class DummyDisassembler : public IDisassembler
{
}

bool verify(const void *sectionData, size_t sectionSize, uint64_t offset)
void addSection(const void *sectionData, size_t sectionSize, uint64_t baseAddress)
{
}

bool verify(uint64_t offset)
{
/*
* ARM and PowerPC have fixed-length instructions, so this is actually
Expand Down
16 changes: 13 additions & 3 deletions src/parsers/elf-parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ class ElfInstance : public IFileParser, IFileParser::ILineListener
else
parseOneDwarf(relocation);

setupSections();

return true;
}

Expand Down Expand Up @@ -372,6 +374,15 @@ class ElfInstance : public IFileParser, IFileParser::ILineListener
}
}

void setupSections()
{
for (SegmentList_t::const_iterator it = m_executableSegments.begin();
it != m_executableSegments.end();
++it) {
m_addressVerifier.addSection(it->getData(), it->getSize(), it->getBase());
}
}

bool parseOneDwarf(unsigned long relocation)
{
unsigned invalidBreakpoints = 0;
Expand Down Expand Up @@ -593,6 +604,7 @@ class ElfInstance : public IFileParser, IFileParser::ILineListener
// If we have segments already, we can safely skip this
if (setupSegments)
m_curSegments.push_back(seg);

m_executableSegments.push_back(seg);
}

Expand Down Expand Up @@ -644,9 +656,7 @@ class ElfInstance : public IFileParser, IFileParser::ILineListener
bool out = true;

if (m_verifyAddresses) {
uint64_t offset = addr - it->getBase();

out = m_addressVerifier.verify(it->getData(),it->getSize(), offset);
out = m_addressVerifier.verify(addr);

if (!out) {
kcov_debug(ELF_MSG, "kcov: Address 0x%llx is not at an instruction boundary, skipping\n",
Expand Down

0 comments on commit 1e13fa4

Please sign in to comment.