Last active
February 27, 2019 01:32
-
-
Save lwerdna/404575245eb65be0511c5cac3529d743 to your computer and use it in GitHub Desktop.
libopcodes command-line invocation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
## loctool: (libopcode tool) programmatically call the same disassembler objdump uses | |
* depends: libiberty, libbfd, libopcodes all from binutils | |
## setup | |
* get [binutils 2.30](https://ftp.gnu.org/gnu/binutils/binutils-2.30.tar.gz) and decompress. | |
* enter the libiberty directory, `./configure && make` then `cp libiberty.a /usr/local/lib` | |
* enter the bfd directory, edit configure and set all_targets=true then `./configure && make && make install` | |
* enter the opcodes directory, edit configure and set all_targets=true then `./configure && make && make install` | |
## compile/link | |
* `gcc loctool.c -o loctool -lopcodes -lbfd -liberty -lz` | |
*/ | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#define PACKAGE "bfd" | |
#define PACKAGE_VERSION "2.30" | |
#include <bfd.h> // for bfd_arch_arm, etc. ~/downloads/binutils-2.30/bfd/bfd.h | |
#include <dis-asm.h> // for struct disassemble_info, etc. ~/downloads/binutils-2.30/include/dis-asm.h | |
int cb_fprintf(void *stream, const char *fmt, ...) | |
{ | |
va_list args; | |
va_start(args, fmt); | |
//printf("cb_fprintf(stream, \"%s\")\n", fmt); | |
char *built_str = (char *)stream; | |
char buf[1024]; | |
int rc = vsnprintf(buf, sizeof(buf)-1, fmt, args); | |
va_end(args); | |
strcat((char *)built_str, buf); | |
return rc; | |
} | |
int disasm_libopcodes(uint8_t *data, int len, uint64_t addr, char *result) | |
{ | |
disassemble_info dinfo = {0}; | |
/* create disassemble_info */ | |
init_disassemble_info(&dinfo, NULL, NULL); | |
dinfo.flavour = bfd_target_unknown_flavour; | |
dinfo.arch = bfd_arch_mips; | |
dinfo.mach = bfd_mach_mipsisa32r6; | |
dinfo.endian = BFD_ENDIAN_BIG; | |
disassemble_init_for_target(&dinfo); // reads dinfo.arch and populate extra stuff | |
/* use the stream pointer as our private data | |
(the buffer that fprintf() should append to) */ | |
dinfo.stream = (void *)result; | |
/* create disassembler */ | |
disassembler_ftype disasm = disassembler(bfd_arch_mips, TRUE, bfd_mach_mipsisa32r6, NULL); | |
if(!disasm) { | |
printf("ERROR: disassembler() returned no function\n"); | |
return -1; | |
} | |
/* call disassembler | |
will use callbacks in dinfo (like .read_memory_func, .print_addr_func, etc.) | |
and the defaults are fine for this use case, see the defaults in a debugger | |
or look at especially buffer_read_memory() in dis-buf.c for details */ | |
dinfo.fprintf_func = cb_fprintf; | |
dinfo.octets_per_byte = 1; | |
dinfo.buffer_vma = addr; | |
dinfo.stop_vma = addr + len; | |
/* source data */ | |
dinfo.buffer = data; | |
dinfo.buffer_length = len; | |
result[0] = '\0'; | |
disasm((bfd_vma)addr, &dinfo); | |
return 0; | |
} | |
int main(int ac, char **av) | |
{ | |
char result[1024]; | |
//uint8_t data[4] = {0x11, 0x22, 0x33, 0x44}; | |
uint8_t data[4]; | |
if(ac<2) { | |
printf("supply instruction word\n"); | |
return -1; | |
} | |
uint32_t insword = strtoul(av[1], NULL, 16); | |
data[0] = (insword >> 24) & 0xff; | |
data[1] = (insword >> 16) & 0xFF; | |
data[2] = (insword >> 8) & 0xFF; | |
data[3] = (insword) & 0xFF; | |
printf("disassembling %02X%02X%02X%02X...\n", | |
data[0], data[1], data[2], data[3]); | |
if(disasm_libopcodes(data, 4, 0, result)) { | |
printf("ERROR: disasm_libopcodes()\n"); | |
return -1; | |
} | |
printf("%s\n", result); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment