Skip to content

Commit

Permalink
loader: finish binary loading and add loader_demo
Browse files Browse the repository at this point in the history
Signed-off-by: Andy Roulin <[email protected]>
  • Loading branch information
aroulin committed Jun 14, 2019
1 parent 23fab59 commit 224e336
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 22 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ set(CMAKE_CXX_STANDARD 11)
add_definitions(-DPACKAGE)
add_definitions(-DPACKAGE_VERSION)

add_executable(loader_demo main.cpp loader.h loader.cc)
add_executable(loader_demo loader_demo.cc loader.h loader.cc)

target_link_libraries(loader_demo bfd)
226 changes: 214 additions & 12 deletions loader.cc
Original file line number Diff line number Diff line change
@@ -1,26 +1,149 @@
#include <bfd.h>
#include "loader.h"

int load_binary_bfd(std::string &fname, Binary *bin, Binary::BinaryType type)
static int load_sections_bfd(bfd *bfd_h, Binary *bin)
{
int bfd_flags;
uint64_t vma, size;
const char *secname;
asection *bfd_sec; /* asection is struct bfd_session */
Section *sec;
Section::SectionType sectype;

for (bfd_sec = bfd_h->sections; bfd_sec; bfd_sec = bfd_sec->next) {
bfd_flags = bfd_get_section_flags(bfd_h, bfd_sec);

sectype = Section::SEC_TYPE_NONE;
if (bfd_flags & SEC_CODE)
sectype = Section::SEC_TYPE_CODE;
else if (bfd_flags & SEC_DATA)
sectype = Section::SEC_TYPE_DATA;
else
continue;

vma = bfd_section_vma(bfd_h, bfd_sec);
size = bfd_section_size(bfd_h, bfd_sec);
secname = bfd_section_name(bfd_h, bfd_sec);
if (!secname)
secname = "<unnamed>";

bin->sections.push_back(Section());
sec = &bin->sections.back();

sec->binary = bin;
sec->name = std::string(secname);
sec->type = sectype;
sec->vma = vma;
sec->bytes = (uint8_t *) malloc(size);
if (!sec->bytes) {
fprintf(stderr, "out of memory\n");
return -1;
}

if (!bfd_get_section_contents(bfd_h, bfd_sec, sec->bytes, 0, size)) {
fprintf(stderr, "failed to read section '%s' (%s)\n",
secname, bfd_errmsg(bfd_get_error()));
return -1;
}
}

return 0;
}

int load_binary(std::string &fname, Binary *bin, Binary::BinaryType type)
{
return load_binary_bfd(fname, bin, type);
static int load_symbols_bfd(bfd *bfd_h, Binary *bin) {
int ret;
long n, nsyms, i;
asymbol **bfd_symtab = NULL; /* asymbol is struct bfd_symbol */
Symbol *sym;

n = bfd_get_symtab_upper_bound(bfd_h);
if (n < 0) {
fprintf(stderr, "failed to read symtab (%s)\n",
bfd_errmsg(bfd_get_error()));
goto fail;
} else if (n) {
bfd_symtab = (asymbol **)malloc(n);
if (!bfd_symtab) {
fprintf(stderr, "out of memory\n");
goto fail;
}

nsyms = bfd_canonicalize_symtab(bfd_h, bfd_symtab);
if (nsyms < 0) {
fprintf(stderr, "failed to read symtab (%s)\n",
bfd_errmsg(bfd_get_error()));
goto fail;
}

for (i = 0; i < nsyms; i++) {
if (bfd_symtab[i]->flags & BSF_FUNCTION) {
bin->symbols.push_back(Symbol());
sym = &bin->symbols.back();
sym->type = Symbol::SYM_TYPE_FUN;
sym->name = std::string(bfd_symtab[i]->name);
sym->addr = bfd_asymbol_value(bfd_symtab[i]);
}
}
}

ret = 0;
goto cleanup;

fail:
ret = -1;
cleanup:
if (bfd_symtab)
free(bfd_symtab);

return ret;
}

void unload_binary(Binary *bin)
{
size_t i;
Section *sec;
static int load_dynsym_bfd(bfd *bfd_h, Binary *bin) {
int ret;
long n, nsyms, i;
asymbol **bfd_symtab = NULL; /* asymbol is struct bfd_symbol */
Symbol *sym;

for (i = 0; i < bin->sections.size(); i++) {
sec = &bin->sections[i];
if (sec->bytes)
free(sec->bytes);
n = bfd_get_dynamic_symtab_upper_bound(bfd_h);
if (n < 0) {
fprintf(stderr, "failed to read symtab (%s)\n",
bfd_errmsg(bfd_get_error()));
goto fail;
} else if (n) {
bfd_symtab = (asymbol **)malloc(n);
if (!bfd_symtab) {
fprintf(stderr, "out of memory\n");
goto fail;
}

nsyms = bfd_canonicalize_dynamic_symtab(bfd_h, bfd_symtab);
if (nsyms < 0) {
fprintf(stderr, "failed to read symtab (%s)\n",
bfd_errmsg(bfd_get_error()));
goto fail;
}

for (i = 0; i < nsyms; i++) {
if (bfd_symtab[i]->flags & BSF_FUNCTION) {
bin->symbols.push_back(Symbol());
sym = &bin->symbols.back();
sym->type = Symbol::SYM_TYPE_FUN;
sym->name = std::string(bfd_symtab[i]->name);
sym->addr = bfd_asymbol_value(bfd_symtab[i]);
}
}
}

ret = 0;
goto cleanup;

fail:
ret = -1;
cleanup:
if (bfd_symtab)
free(bfd_symtab);

return ret;
}

static bfd* open_bfd(std::string &fname)
Expand Down Expand Up @@ -61,3 +184,82 @@ static bfd* open_bfd(std::string &fname)
return bfd_h;
}

int load_binary_bfd(std::string &fname, Binary *bin, Binary::BinaryType type)
{
int ret;
bfd *bfd_h = NULL;
const bfd_arch_info_type *bfd_arch_info;

bfd_h = open_bfd(fname);
if (!bfd_h)
goto fail;

bin->filename = std::string(fname);
bin->entry = bfd_get_start_address(bfd_h);
bin->type_str = std::string(bfd_h->xvec->name);

switch(bfd_h->xvec->flavour) {
case bfd_target_elf_flavour:
bin->type = Binary::BIN_TYPE_ELF;
break;
case bfd_target_coff_flavour:
bin->type = Binary::BIN_TYPE_PE;
break;
case bfd_target_unknown_flavour:
default:
fprintf(stderr, "unsupported binary type (%s)\n", bfd_h->xvec->name);
goto fail;
}

bfd_arch_info = bfd_get_arch_info(bfd_h);
bin->arch_str = std::string(bfd_arch_info->printable_name);

switch(bfd_arch_info->mach) {
case bfd_mach_i386_i386:
bin->arch = Binary::ARCH_X86;
bin->bits = 32;
break;
case bfd_mach_x86_64:
bin->arch = Binary::ARCH_X86;
bin->bits = 64;
break;
default:
fprintf(stderr, "unsupported architecture (%s)\n",
bfd_arch_info->printable_name);
goto fail;
}

/* best effort symbol handling */
load_symbols_bfd(bfd_h, bin);
load_dynsym_bfd(bfd_h, bin);

if (load_sections_bfd(bfd_h, bin) < 0)
goto fail;

ret = 0;
goto cleanup;

fail:
ret = -1;
cleanup:
if (bfd_h)
bfd_close(bfd_h);

return ret;
}

int load_binary(std::string &fname, Binary *bin, Binary::BinaryType type)
{
return load_binary_bfd(fname, bin, type);
}

void unload_binary(Binary *bin) {
size_t i;
Section *sec;

for (i = 0; i < bin->sections.size(); i++) {
sec = &bin->sections[i];
if (sec->bytes)
free(sec->bytes);
}
}
5 changes: 3 additions & 2 deletions loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ class Binary {
std::vector<Section> sections;
std::vector<Symbol> symbols;

int load_binary(std::string &fname, Binary *bin, Binary::BinaryType type);
void unload_binary(Binary *bin);
};

int load_binary(std::string &fname, Binary *bin, Binary::BinaryType type);
void unload_binary(Binary *bin);

#endif /* LOADER_H */
46 changes: 46 additions & 0 deletions loader_demo.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <stdio.h>
#include <stdint.h>
#include <string>
#include "loader.h"

int main(int argc, char *argv[])
{
size_t i;
Binary bin;
Section *sec;
Symbol *sym;
std::string fname;

if(argc < 2) {
printf("Usage: %s <binary>\n", argv[0]);
return 1;
}

fname.assign(argv[1]);
if(load_binary(fname, &bin, Binary::BIN_TYPE_AUTO) < 0) {
return 1;
}

printf("loaded binary '%s' %s/%s (%u bits) entry@0x%016jx\n",
bin.filename.c_str(), bin.type_str.c_str(), bin.arch_str.c_str(),
bin.bits, bin.entry);

for(i = 0; i < bin.sections.size(); i++) {sec = &bin.sections[i];
printf(" 0x%016jx %-8ju %-20s %s\n",
sec->vma, sec->size, sec->name.c_str(),
sec->type == Section::SEC_TYPE_CODE ? "CODE" : "DATA");
}

if(bin.symbols.size() > 0) {
printf("scanned symbol tables\n");

for(i = 0; i < bin.symbols.size(); i++) {
sym = &bin.symbols[i];
printf(" %-40s 0x%016jx %s\n", sym->name.c_str(), sym->addr,
(sym->type & Symbol::SYM_TYPE_FUN) ? "FUNC" : "");
}
}

unload_binary(&bin);
return 0;
}
7 changes: 0 additions & 7 deletions main.cpp

This file was deleted.

0 comments on commit 224e336

Please sign in to comment.