Skip to content

Instantly share code, notes, and snippets.

@lwerdna
Last active February 27, 2019 01:32
Show Gist options
  • Save lwerdna/404575245eb65be0511c5cac3529d743 to your computer and use it in GitHub Desktop.
Save lwerdna/404575245eb65be0511c5cac3529d743 to your computer and use it in GitHub Desktop.
libopcodes command-line invocation
/*
## 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