<file_sep><!DOCTYPE html PUBLIC "-//IETF//DTD HTML//EN">
<!-- saved from url=(0051)https://www.toothycat.net/wiki/wiki.pl?Binutils/bfd -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1252"><title>ToothyWiki: Binutils/Bfd</title>
<script language="javascript" src="./ToothyWiki_ Binutils_Bfd_files/rot13.js"></script>
<link rel="icon" href="https://www.toothycat.net/favicon.ico"></head><body bgcolor="white">
<h1><a href="http://www.toothycat.net/"><img src="./ToothyWiki_ Binutils_Bfd_files/text_logo.jpg" alt="[Home]" border="0" align="right"></a><a href="https://www.toothycat.net/wiki/wiki.pl?search_bb=1&amp;search_ns=Binutils&amp;search=Bfd">Binutils/Bfd</a></h1>xxx.xxx.xxx.xxx | <a href="https://www.toothycat.net/wiki/wiki.pl?ToothyWiki">ToothyWiki</a> | <a href="https://www.toothycat.net/wiki/wiki.pl?Binutils">Binutils</a> | <a href="https://www.toothycat.net/wiki/wiki.pl?RecentChanges">RecentChanges</a> | <a href="https://www.toothycat.net/wiki/wiki.pl?action=login">Login</a> | <a href="https://www.toothycat.net/apoc/">Webcomic</a><br>
<hr><a name="libbfd"></a><a name="libbfd"></a><a name="uid-0"></a><h3>libbfd</h3>
<br>This library provides functions to read and write the contents of executable binaries and libraries.&nbsp; To use the library, simply include "bfd.h", and link your program against libbdf.so.&nbsp; <br><br>A binary file is represented by an instance of the "bfd" object.&nbsp; Each file is broken into sections represented by "struct bfd_section" objects.&nbsp; These can be retrieved by name.&nbsp; For example, ".text" and ".data" are the standard section names in ELF for the code and data segments.<br><br>Although it would be possible to access the linking information directly from the appropriate bfd_sections, libbfd abstracts this functionality to allow the API to work independently of the binary structure.&nbsp; To achieve this, bfd objects can be used to retrieve arrays of "struct bfd_symbol" that represent entries in the binary's linker tables.<br><br><a name="Primary_bfd_object_methods"></a><a name="Primary"></a><a name="uid-1"></a><h4>Primary bfd object methods</h4>
<br>Class representing a Binary File Descriptor<br><pre>&nbsp;  // Open and close binary files<br>&nbsp;  bfd&nbsp; &nbsp; &nbsp; &nbsp;  * bfd_openr( const char * filename, const char * target );<br>&nbsp;  bfd_boolean&nbsp;  bfd_close( bfd * );<br></pre>
<br><pre>&nbsp;  //&nbsp; Query file properties <br>&nbsp;  char&nbsp; &nbsp; &nbsp; &nbsp; * bfd_get_filename( bfd * );<br>&nbsp;  char&nbsp; &nbsp; &nbsp; &nbsp; * bfd_get_target( bfd * );<br>&nbsp;  bfd_flavour&nbsp;  bfd_get_flavour( bfd * );<br>&nbsp;  flagword&nbsp; &nbsp; &nbsp; bfd_get_flags(&nbsp; bfd * );<br></pre>
<br><pre>&nbsp;  // Address of the start of executable code when loaded into memory (.text section in standard ELF)<br>&nbsp;  bfd_vma&nbsp; &nbsp; &nbsp;  bfd_get_start_address( bfd * );<br></pre>
<br><pre>&nbsp;  // Enumerate or retrieve file sections (for example ".text", ".data")<br>&nbsp;  //<br>&nbsp;  //&nbsp;  Callback prototype is:<br>&nbsp;  //&nbsp;  void callback( bfd * bfdFile,<br>&nbsp;  //&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct bfd_section * section,<br>&nbsp;  //&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; void * user_data );<br>&nbsp;  //<br>&nbsp;  void bfd_map_over_sections( bfd *, &amp;callback, void * user_data );<br>&nbsp;  struct bfd_section * get_section_by_name( bfd *, const char * name );<br></pre>
<br><pre>&nbsp;  // Symbol access<br>&nbsp;  long bfd_get_symtab_upper_bound( bfd * );<br>&nbsp;  long bfd_canonicalize_symtab( bfd *, struct bfd_symbol ** symbols );<br></pre>
<br><pre>&nbsp;  long bfd_get_dynamic_symtab_upper_bound( bfd * );<br>&nbsp;  long bfd_canonicalize_dynamic_symtab( bfd *, struct bfd_symbol ** symbols );<br></pre>
<br><a name="Primary_struct_bfd_sections_properties"></a><a name="Primary"></a><a name="uid-2"></a><h4>Primary struct bfd_sections properties</h4>
<br>Class representing a section in an binary file<br><pre>&nbsp;  // Section name<br>&nbsp;  const char&nbsp; &nbsp; * name;<br></pre>
<br><pre>&nbsp;  //&nbsp; Address and size of section when loaded into memory<br>&nbsp;  bfd_vma&nbsp; &nbsp; &nbsp; &nbsp;  vma;<br>&nbsp;  bfd_size_type&nbsp;  size;<br></pre>
<br><a name="Primary_"></a><a name="Primary"></a><a name="uid-3"></a><h4>Primary "struct bfd_symbol" properties</h4>
<br>Class representing an entry in one of the binary's symbol table<br><pre>&nbsp;  //&nbsp; The symbol name, the section it resides in, and standard symbol information structure<br>&nbsp;  const char * name<br>&nbsp;  struct bfd_section * section<br>&nbsp;  void bfd_symbol_info( struct bfd_symbol *, symbol_info * info ); <br></pre>
<br><a name="Example"></a><a name="Example"></a><a name="uid-4"></a><h4>Example: Opening an existing binary file</h4>
<br>This code opens /bin/ls as an 64-bit x86 ELF binary.&nbsp; Note that it is necessary to call bfd_check_format() before using the bfd instance.<br><br><pre>&nbsp;  bfd_init();<br></pre>
<br><pre>&nbsp;  bfd * bfdFile = bfd_openr( "/bin/ls", "elf64-x86-64" );<br>&nbsp;  if ( bfdFile == NULL )<br>&nbsp;  {<br>&nbsp; &nbsp; &nbsp;  printf( "Error [%x]: %s\n", bfd_get_error(), bfd_errmsg(bfd_get_error()) );<br>&nbsp; &nbsp; &nbsp;  return;<br>&nbsp;  }<br></pre>
<br><pre>&nbsp;  if ( !bfd_check_format( bfdFile, bfd_object ))<br>&nbsp;  {<br>&nbsp; &nbsp; &nbsp;  printf( "Error [%x]: %s\n", bfd_get_error(), bfd_errmsg(bfd_get_error()) );<br>&nbsp; &nbsp; &nbsp;  return;<br>&nbsp;  }<br></pre>
<br><pre>&nbsp;  // Program goes here<br></pre>
<br><pre>&nbsp;  bfd_close( bfdFile );<br></pre>
<br><a name="Reading_symbol_tables"></a><a name="Reading"></a><a name="uid-5"></a><h4>Reading symbol tables</h4>
<br>Retrieving the symbols included in the bfd file is slightly more complicated (you need to pass in a buffer of appropriate size). The code below extracts the dynamic symbols from a bfd instance (static symbols are similar):<br><br><pre>&nbsp; &nbsp; struct bfd_symbol ** symbols;<br>&nbsp; &nbsp; long&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  symbolsSize;<br>&nbsp; &nbsp; long&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  symbolsCount;<br></pre>
<br><pre>&nbsp; &nbsp; long i;<br></pre>
<br><pre>&nbsp; &nbsp; // Calculate required buffer size<br>&nbsp; &nbsp; symbolsSize = bfd_get_dynamic_symtab_upper_bound( bfdFile );<br>&nbsp; &nbsp; if ( symbolsSize &lt; 0 )<br>&nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; printf( "Error [%x]: %s\n", bfd_get_error(), bfd_errmsg(bfd_get_error()) );<br>&nbsp; &nbsp; &nbsp; return;<br>&nbsp; &nbsp; }<br></pre>
<br><pre>&nbsp; &nbsp; // Allocate buffer<br>&nbsp; &nbsp; symbols = malloc( symbolsSize );<br>&nbsp; &nbsp; if ( symbols == NULL )<br>&nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; printf( "Could not allocate memory\n" );<br>&nbsp; &nbsp; &nbsp; return;<br>&nbsp; &nbsp; }<br></pre>
<br><pre>&nbsp; &nbsp; // Retrieve unpacked symbols<br>&nbsp; &nbsp; symbolsCount = bfd_canonicalize_dynamic_symtab( bfdFile, symbols );<br>&nbsp; &nbsp; if ( symbolsCount &lt; 0 )<br>&nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; printf( "Error [%x]: %s\n", bfd_get_error(), bfd_errmsg(bfd_get_error()) );<br>&nbsp; &nbsp; &nbsp; free( symbols );<br>&nbsp; &nbsp; &nbsp; return;<br>&nbsp; &nbsp; }<br></pre>
<br><pre>&nbsp; &nbsp; // List symbols<br>&nbsp; &nbsp; for ( i = 0; i &lt; symbolsCount; i++ )<br>&nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; printf( "Symbol [flags %x][value %x] %s\n", symbols[i]-&gt;flags, symbols[i]-&gt;value, symbols[i]-&gt;name );<br>&nbsp; &nbsp; } <br></pre>
<br><pre>&nbsp; &nbsp; free( symbols );<br></pre>
<br><a name="Modifying_and_linking_binary_files"></a><a name="Modifying"></a><a name="uid-6"></a><h4>Modifying and linking binary files</h4>
<br>In addition to examining existing files, libbfd also has functionality for creating and modifying them.&nbsp; The most advanced functionality is in the area of code disassemble/reassembly and linking.&nbsp; This can even support code compiled for different machine architectures.<br><hr>
<table width="100%" cellpadding="0" cellspacing="0" border="0"><tbody><tr><td width="*"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tbody><tr><td width="100%">xxx.xxx.xxx.xxx | <a href="https://www.toothycat.net/wiki/wiki.pl?ToothyWiki">ToothyWiki</a> | <a href="https://www.toothycat.net/wiki/wiki.pl?Binutils">Binutils</a> | <a href="https://www.toothycat.net/wiki/wiki.pl?RecentChanges">RecentChanges</a> | <a href="https://www.toothycat.net/wiki/wiki.pl?action=login">Login</a> | <a href="https://www.toothycat.net/apoc/">Webcomic</a><br>
This page is read-only | <a href="https://www.toothycat.net/wiki/wiki.pl?id=Binutils/Bfd&amp;action=history">View other revisions</a> | <a href="https://www.toothycat.net/cgi/log.pl?act=rrx&amp;n=/wiki/wiki.pl?Binutils/Bfd">Recently used referrers</a><br>Last edited January 12, 2009 11:10 pm (viewing revision 1, which is the newest) <a href="https://www.toothycat.net/wiki/wiki.pl?id=Binutils/Bfd&amp;action=browse&amp;diff=1">(diff)</a></td></tr></tbody></table><table width="100%" cellpadding="0" cellspacing="0" border="0"><tbody><tr><td width="70%" align="left"><form method="post" action="https://www.toothycat.net/wiki/wiki.pl" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="ipmatch" value="xxx.xxx.xxx.xxx">Search: <input type="text" name="search" size="20"> <label><input type="checkbox" name="search_ww" value="1" checked="checked">Whole words</label> <label><input type="checkbox" name="search_all" value="1" checked="checked">Must contain all</label> <label><input type="checkbox" name="search_title" value="1">Page title search</label><input type="hidden" name="dosearch" value="1"><div><input type="hidden" name=".cgifields" value="search_ww"><input type="hidden" name=".cgifields" value="search_all"><input type="hidden" name=".cgifields" value="search_title"></div>
</form></td><td width="30%" align="right"><form method="post" action="https://www.toothycat.net/wiki/wiki.pl" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="ipmatch" value="xxx.xxx.xxx.xxx"><input type="submit" name="dorot13" value="Rot13:" onclick="return rot13(rot13text1)"> <input type="text" name="rot13text1" size="20"><input type="hidden" name="rot13tag" value="1"><input type="hidden" name="action" value="browse"><input type="hidden" name="id" value="Binutils/Bfd"></form></td></tr></tbody></table></td></tr></tbody></table>

</body></html>
<file_sep>// <NAME> <<EMAIL>>
// binutils - mach.rs

#![allow(dead_code)]
#![allow(non_upper_case_globals)]
#![allow(unknown_lints)]
#![allow(clippy::all)]

// Manually generate for binutils-2.29.1
pub const bfd_mach_m68000: u64 = 1;
pub const bfd_mach_m68008: u64 = 2;
pub const bfd_mach_m68010: u64 = 3;
pub const bfd_mach_m68020: u64 = 4;
pub const bfd_mach_m68030: u64 = 5;
pub const bfd_mach_m68040: u64 = 6;
pub const bfd_mach_m68060: u64 = 7;
pub const bfd_mach_cpu64: u64 = 8;
pub const bfd_mach_fido: u64 = 9;
pub const bfd_mach_mcf_isa_a_nodiv: u64 = 10;
pub const bfd_mach_mcf_isa_a: u64 = 11;
pub const bfd_mach_mcf_isa_a_mac: u64 = 12;
pub const bfd_mach_mcf_isa_a_emac: u64 = 13;
pub const bfd_mach_mcf_isa_aplus: u64 = 14;
pub const bfd_mach_mcf_isa_aplus_mac: u64 = 15;
pub const bfd_mach_mcf_isa_aplus_emac: u64 = 16;
pub const bfd_mach_mcf_isa_b_nousp: u64 = 17;
pub const bfd_mach_mcf_isa_b_nousp_mac: u64 = 18;
pub const bfd_mach_mcf_isa_b_nousp_emac: u64 = 19;
pub const bfd_mach_mcf_isa_b: u64 = 20;
pub const bfd_mach_mcf_isa_b_mac: u64 = 21;
pub const bfd_mach_mcf_isa_b_emac: u64 = 22;
pub const bfd_mach_mcf_isa_b_float: u64 = 23;
pub const bfd_mach_mcf_isa_b_float_mac: u64 = 24;
pub const bfd_mach_mcf_isa_b_float_emac: u64 = 25;
pub const bfd_mach_mcf_isa_c: u64 = 26;
pub const bfd_mach_mcf_isa_c_mac: u64 = 27;
pub const bfd_mach_mcf_isa_c_emac: u64 = 28;
pub const bfd_mach_mcf_isa_c_nodiv: u64 = 29;
pub const bfd_mach_mcf_isa_c_nodiv_mac: u64 = 30;
pub const bfd_mach_mcf_isa_c_nodiv_emac: u64 = 31;
pub const bfd_mach_i960_core: u64 = 1;
pub const bfd_mach_i960_ka_sa: u64 = 2;
pub const bfd_mach_i960_kb_sb: u64 = 3;
pub const bfd_mach_i960_mc: u64 = 4;
pub const bfd_mach_i960_xa: u64 = 5;
pub const bfd_mach_i960_ca: u64 = 6;
pub const bfd_mach_i960_jx: u64 = 7;
pub const bfd_mach_i960_hx: u64 = 8;
pub const bfd_mach_or1k: u64 = 1;
pub const bfd_mach_or1knd: u64 = 2;
pub const bfd_mach_sparc: u64 = 1;
pub const bfd_mach_sparc_sparclet: u64 = 2;
pub const bfd_mach_sparc_sparclite: u64 = 3;
pub const bfd_mach_sparc_v8plus: u64 = 4;
pub const bfd_mach_sparc_v8plusa: u64 = 5 /* with ultrasparc add'ns. */;
pub const bfd_mach_sparc_sparclite_le: u64 = 6;
pub const bfd_mach_sparc_v9: u64 = 7;
pub const bfd_mach_sparc_v9a: u64 = 8 /* with ultrasparc add'ns. */;
pub const bfd_mach_sparc_v8plusb: u64 = 9 /* with cheetah add'ns. */;
pub const bfd_mach_sparc_v9b: u64 = 10 /* with cheetah add'ns. */;
pub const bfd_mach_sparc_v8plusc: u64 = 11 /* with UA2005 and T1 add'ns. */;
pub const bfd_mach_sparc_v9c: u64 = 12 /* with UA2005 and T1 add'ns. */;
pub const bfd_mach_sparc_v8plusd: u64 = 13 /* with UA2007 and T3 add'ns. */;
pub const bfd_mach_sparc_v9d: u64 = 14 /* with UA2007 and T3 add'ns. */;
pub const bfd_mach_sparc_v8pluse: u64 = 15 /* with OSA2001 and T4 add'ns (no IMA). */;
pub const bfd_mach_sparc_v9e: u64 = 16 /* with OSA2001 and T4 add'ns (no IMA). */;
pub const bfd_mach_sparc_v8plusv: u64 = 17 /* with OSA2011 and T4 and IMA and FJMAU add'ns. */;
pub const bfd_mach_sparc_v9v: u64 = 18 /* with OSA2011 and T4 and IMA and FJMAU add'ns. */;
pub const bfd_mach_sparc_v8plusm: u64 = 19 /* with OSA2015 and M7 add'ns. */;
pub const bfd_mach_sparc_v9m: u64 = 20 /* with OSA2015 and M7 add'ns. */;
pub const bfd_mach_sparc_v8plusm8: u64 = 21 /* with OSA2017 and M8 add'ns. */;
pub const bfd_mach_sparc_v9m8: u64 = 22 /* with OSA2017 and M8 add'ns. */;
pub const bfd_mach_spu: u64 = 256;
pub const bfd_mach_mips3000: u64 = 3000;
pub const bfd_mach_mips3900: u64 = 3900;
pub const bfd_mach_mips4000: u64 = 4000;
pub const bfd_mach_mips4010: u64 = 4010;
pub const bfd_mach_mips4100: u64 = 4100;
pub const bfd_mach_mips4111: u64 = 4111;
pub const bfd_mach_mips4120: u64 = 4120;
pub const bfd_mach_mips4300: u64 = 4300;
pub const bfd_mach_mips4400: u64 = 4400;
pub const bfd_mach_mips4600: u64 = 4600;
pub const bfd_mach_mips4650: u64 = 4650;
pub const bfd_mach_mips5000: u64 = 5000;
pub const bfd_mach_mips5400: u64 = 5400;
pub const bfd_mach_mips5500: u64 = 5500;
pub const bfd_mach_mips5900: u64 = 5900;
pub const bfd_mach_mips6000: u64 = 6000;
pub const bfd_mach_mips7000: u64 = 7000;
pub const bfd_mach_mips8000: u64 = 8000;
pub const bfd_mach_mips9000: u64 = 9000;
pub const bfd_mach_mips10000: u64 = 10000;
pub const bfd_mach_mips12000: u64 = 12000;
pub const bfd_mach_mips14000: u64 = 14000;
pub const bfd_mach_mips16000: u64 = 16000;
pub const bfd_mach_mips16: u64 = 16;
pub const bfd_mach_mips5: u64 = 5;
pub const bfd_mach_mips_loongson_2e: u64 = 3001;
pub const bfd_mach_mips_loongson_2f: u64 = 3002;
pub const bfd_mach_mips_loongson_3a: u64 = 3003;
pub const bfd_mach_mips_sb1: u64 = 12310201 /* octal 'SB', 01 */;
pub const bfd_mach_mips_octeon: u64 = 6501;
pub const bfd_mach_mips_octeonp: u64 = 6601;
pub const bfd_mach_mips_octeon2: u64 = 6502;
pub const bfd_mach_mips_octeon3: u64 = 6503;
pub const bfd_mach_mips_xlr: u64 = 887682 /* decimal 'XLR' */;
pub const bfd_mach_mips_interaptiv_mr2: u64 = 736550 /* decimal 'IA2' */;
pub const bfd_mach_mipsisa32: u64 = 32;
pub const bfd_mach_mipsisa32r2: u64 = 33;
pub const bfd_mach_mipsisa32r3: u64 = 34;
pub const bfd_mach_mipsisa32r5: u64 = 36;
pub const bfd_mach_mipsisa32r6: u64 = 37;
pub const bfd_mach_mipsisa64: u64 = 64;
pub const bfd_mach_mipsisa64r2: u64 = 65;
pub const bfd_mach_mipsisa64r3: u64 = 66;
pub const bfd_mach_mipsisa64r5: u64 = 68;
pub const bfd_mach_mipsisa64r6: u64 = 69;
pub const bfd_mach_mips_micromips: u64 = 96;
pub const bfd_mach_i386_intel_syntax: u64 = (1 << 0);
pub const bfd_mach_i386_i8086: u64 = (1 << 1);
pub const bfd_mach_i386_i386: u64 = (1 << 2);
pub const bfd_mach_x86_64: u64 = (1 << 3);
pub const bfd_mach_x64_32: u64 = (1 << 4);
pub const bfd_mach_i386_i386_intel_syntax: u64 = (bfd_mach_i386_i386 | bfd_mach_i386_intel_syntax);
pub const bfd_mach_x86_64_intel_syntax: u64 = (bfd_mach_x86_64 | bfd_mach_i386_intel_syntax);
pub const bfd_mach_x64_32_intel_syntax: u64 = (bfd_mach_x64_32 | bfd_mach_i386_intel_syntax);
pub const bfd_mach_l1om: u64 = (1 << 5);
pub const bfd_mach_l1om_intel_syntax: u64 = (bfd_mach_l1om | bfd_mach_i386_intel_syntax);
pub const bfd_mach_k1om: u64 = (1 << 6);
pub const bfd_mach_k1om_intel_syntax: u64 = (bfd_mach_k1om | bfd_mach_i386_intel_syntax);
pub const bfd_mach_i386_nacl: u64 = (1 << 7);
pub const bfd_mach_i386_i386_nacl: u64 = (bfd_mach_i386_i386 | bfd_mach_i386_nacl);
pub const bfd_mach_x86_64_nacl: u64 = (bfd_mach_x86_64 | bfd_mach_i386_nacl);
pub const bfd_mach_x64_32_nacl: u64 = (bfd_mach_x64_32 | bfd_mach_i386_nacl);
pub const bfd_mach_iamcu: u64 = (1 << 8);
pub const bfd_mach_i386_iamcu: u64 = (bfd_mach_i386_i386 | bfd_mach_iamcu);
pub const bfd_mach_i386_iamcu_intel_syntax: u64 =
    (bfd_mach_i386_iamcu | bfd_mach_i386_intel_syntax);
pub const bfd_mach_h8300: u64 = 1;
pub const bfd_mach_h8300h: u64 = 2;
pub const bfd_mach_h8300s: u64 = 3;
pub const bfd_mach_h8300hn: u64 = 4;
pub const bfd_mach_h8300sn: u64 = 5;
pub const bfd_mach_h8300sx: u64 = 6;
pub const bfd_mach_h8300sxn: u64 = 7;
pub const bfd_mach_ppc: u64 = 32;
pub const bfd_mach_ppc64: u64 = 64;
pub const bfd_mach_ppc_403: u64 = 403;
pub const bfd_mach_ppc_403gc: u64 = 4030;
pub const bfd_mach_ppc_405: u64 = 405;
pub const bfd_mach_ppc_505: u64 = 505;
pub const bfd_mach_ppc_601: u64 = 601;
pub const bfd_mach_ppc_602: u64 = 602;
pub const bfd_mach_ppc_603: u64 = 603;
pub const bfd_mach_ppc_ec603e: u64 = 6031;
pub const bfd_mach_ppc_604: u64 = 604;
pub const bfd_mach_ppc_620: u64 = 620;
pub const bfd_mach_ppc_630: u64 = 630;
pub const bfd_mach_ppc_750: u64 = 750;
pub const bfd_mach_ppc_860: u64 = 860;
pub const bfd_mach_ppc_a35: u64 = 35;
pub const bfd_mach_ppc_rs64ii: u64 = 642;
pub const bfd_mach_ppc_rs64iii: u64 = 643;
pub const bfd_mach_ppc_7400: u64 = 7400;
pub const bfd_mach_ppc_e500: u64 = 500;
pub const bfd_mach_ppc_e500mc: u64 = 5001;
pub const bfd_mach_ppc_e500mc64: u64 = 5005;
pub const bfd_mach_ppc_e5500: u64 = 5006;
pub const bfd_mach_ppc_e6500: u64 = 5007;
pub const bfd_mach_ppc_titan: u64 = 83;
pub const bfd_mach_ppc_vle: u64 = 84;
pub const bfd_mach_rs6k: u64 = 6000;
pub const bfd_mach_rs6k_rs1: u64 = 6001;
pub const bfd_mach_rs6k_rsc: u64 = 6003;
pub const bfd_mach_rs6k_rs2: u64 = 6002;
pub const bfd_mach_hppa10: u64 = 10;
pub const bfd_mach_hppa11: u64 = 11;
pub const bfd_mach_hppa20: u64 = 20;
pub const bfd_mach_hppa20w: u64 = 25;
pub const bfd_mach_d10v: u64 = 1;
pub const bfd_mach_d10v_ts2: u64 = 2;
pub const bfd_mach_d10v_ts3: u64 = 3;
pub const bfd_mach_m6812_default: u64 = 0;
pub const bfd_mach_m6812: u64 = 1;
pub const bfd_mach_m6812s: u64 = 2;
pub const bfd_mach_z8001: u64 = 1;
pub const bfd_mach_z8002: u64 = 2;
pub const bfd_mach_sh: u64 = 1;
pub const bfd_mach_sh2: u64 = 0x20;
pub const bfd_mach_sh_dsp: u64 = 0x2d;
pub const bfd_mach_sh2a: u64 = 0x2a;
pub const bfd_mach_sh2a_nofpu: u64 = 0x2b;
pub const bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu: u64 = 0x2a1;
pub const bfd_mach_sh2a_nofpu_or_sh3_nommu: u64 = 0x2a2;
pub const bfd_mach_sh2a_or_sh4: u64 = 0x2a3;
pub const bfd_mach_sh2a_or_sh3e: u64 = 0x2a4;
pub const bfd_mach_sh2e: u64 = 0x2e;
pub const bfd_mach_sh3: u64 = 0x30;
pub const bfd_mach_sh3_nommu: u64 = 0x31;
pub const bfd_mach_sh3_dsp: u64 = 0x3d;
pub const bfd_mach_sh3e: u64 = 0x3e;
pub const bfd_mach_sh4: u64 = 0x40;
pub const bfd_mach_sh4_nofpu: u64 = 0x41;
pub const bfd_mach_sh4_nommu_nofpu: u64 = 0x42;
pub const bfd_mach_sh4a: u64 = 0x4a;
pub const bfd_mach_sh4a_nofpu: u64 = 0x4b;
pub const bfd_mach_sh4al_dsp: u64 = 0x4d;
pub const bfd_mach_sh5: u64 = 0x50;
pub const bfd_mach_alpha_ev4: u64 = 0x10;
pub const bfd_mach_alpha_ev5: u64 = 0x20;
pub const bfd_mach_alpha_ev6: u64 = 0x30;
pub const bfd_mach_arm_unknown: u64 = 0;
pub const bfd_mach_arm_2: u64 = 1;
pub const bfd_mach_arm_2a: u64 = 2;
pub const bfd_mach_arm_3: u64 = 3;
pub const bfd_mach_arm_3M: u64 = 4;
pub const bfd_mach_arm_4: u64 = 5;
pub const bfd_mach_arm_4T: u64 = 6;
pub const bfd_mach_arm_5: u64 = 7;
pub const bfd_mach_arm_5T: u64 = 8;
pub const bfd_mach_arm_5TE: u64 = 9;
pub const bfd_mach_arm_XScale: u64 = 10;
pub const bfd_mach_arm_ep9312: u64 = 11;
pub const bfd_mach_arm_iWMMXt: u64 = 12;
pub const bfd_mach_arm_iWMMXt2: u64 = 13;
pub const bfd_mach_n1: u64 = 1;
pub const bfd_mach_n1h: u64 = 2;
pub const bfd_mach_n1h_v2: u64 = 3;
pub const bfd_mach_n1h_v3: u64 = 4;
pub const bfd_mach_n1h_v3m: u64 = 5;
pub const bfd_mach_tic3x: u64 = 30;
pub const bfd_mach_tic4x: u64 = 40;
pub const bfd_mach_v850: u64 = 1;
pub const bfd_mach_v850e: u64 = 'E' as u64;
pub const bfd_mach_v850e1: u64 = '1' as u64;
pub const bfd_mach_v850e2: u64 = 0x4532;
pub const bfd_mach_v850e2v3: u64 = 0x45325633;
pub const bfd_mach_v850e3v5: u64 = 0x45335635 /* ('E'|'3'|'V'|'5') */;
pub const bfd_mach_arc_a4: u64 = 0;
pub const bfd_mach_arc_a5: u64 = 1;
pub const bfd_mach_arc_arc600: u64 = 2;
pub const bfd_mach_arc_arc601: u64 = 4;
pub const bfd_mach_arc_arc700: u64 = 3;
pub const bfd_mach_arc_arcv2: u64 = 5;
pub const bfd_mach_m16c: u64 = 0x75;
pub const bfd_mach_m32c: u64 = 0x78;
pub const bfd_mach_m32r: u64 = 1 /* For backwards compatibility. */;
pub const bfd_mach_m32rx: u64 = 'x' as u64;
pub const bfd_mach_m32r2: u64 = '2' as u64;
pub const bfd_mach_mn10300: u64 = 300;
pub const bfd_mach_am33: u64 = 330;
pub const bfd_mach_am33_2: u64 = 332;
pub const bfd_mach_fr30: u64 = 0x46523330;
pub const bfd_mach_frv: u64 = 1;
pub const bfd_mach_frvsimple: u64 = 2;
pub const bfd_mach_fr300: u64 = 300;
pub const bfd_mach_fr400: u64 = 400;
pub const bfd_mach_fr450: u64 = 450;
pub const bfd_mach_frvtomcat: u64 = 499 /* fr500 prototype */;
pub const bfd_mach_fr500: u64 = 500;
pub const bfd_mach_fr550: u64 = 550;
pub const bfd_mach_moxie: u64 = 1;
pub const bfd_mach_ft32: u64 = 1;
pub const bfd_mach_mep: u64 = 1;
pub const bfd_mach_mep_h1: u64 = 0x6831;
pub const bfd_mach_mep_c5: u64 = 0x6335;
pub const bfd_mach_metag: u64 = 1;
pub const bfd_mach_ia64_elf64: u64 = 64;
pub const bfd_mach_ia64_elf32: u64 = 32;
pub const bfd_mach_ip2022: u64 = 1;
pub const bfd_mach_ip2022ext: u64 = 2;
pub const bfd_mach_iq2000: u64 = 1;
pub const bfd_mach_iq10: u64 = 2;
pub const bfd_mach_epiphany16: u64 = 1;
pub const bfd_mach_epiphany32: u64 = 2;
pub const bfd_mach_ms1: u64 = 1;
pub const bfd_mach_mrisc2: u64 = 2;
pub const bfd_mach_ms2: u64 = 3;
pub const bfd_mach_avr1: u64 = 1;
pub const bfd_mach_avr2: u64 = 2;
pub const bfd_mach_avr25: u64 = 25;
pub const bfd_mach_avr3: u64 = 3;
pub const bfd_mach_avr31: u64 = 31;
pub const bfd_mach_avr35: u64 = 35;
pub const bfd_mach_avr4: u64 = 4;
pub const bfd_mach_avr5: u64 = 5;
pub const bfd_mach_avr51: u64 = 51;
pub const bfd_mach_avr6: u64 = 6;
pub const bfd_mach_avrtiny: u64 = 100;
pub const bfd_mach_avrxmega1: u64 = 101;
pub const bfd_mach_avrxmega2: u64 = 102;
pub const bfd_mach_avrxmega3: u64 = 103;
pub const bfd_mach_avrxmega4: u64 = 104;
pub const bfd_mach_avrxmega5: u64 = 105;
pub const bfd_mach_avrxmega6: u64 = 106;
pub const bfd_mach_avrxmega7: u64 = 107;
pub const bfd_mach_bfin: u64 = 1;
pub const bfd_mach_cr16: u64 = 1;
pub const bfd_mach_cr16c: u64 = 1;
pub const bfd_mach_crx: u64 = 1;
pub const bfd_mach_cris_v0_v10: u64 = 255;
pub const bfd_mach_cris_v32: u64 = 32;
pub const bfd_mach_cris_v10_v32: u64 = 1032;
pub const bfd_mach_riscv32: u64 = 132;
pub const bfd_mach_riscv64: u64 = 164;
pub const bfd_mach_rl78: u64 = 0x75;
pub const bfd_mach_rx: u64 = 0x75;
pub const bfd_mach_s390_31: u64 = 31;
pub const bfd_mach_s390_64: u64 = 64;
pub const bfd_mach_score3: u64 = 3;
pub const bfd_mach_score7: u64 = 7;
pub const bfd_mach_xstormy16: u64 = 1;
pub const bfd_mach_msp11: u64 = 11;
pub const bfd_mach_msp110: u64 = 110;
pub const bfd_mach_msp12: u64 = 12;
pub const bfd_mach_msp13: u64 = 13;
pub const bfd_mach_msp14: u64 = 14;
pub const bfd_mach_msp15: u64 = 15;
pub const bfd_mach_msp16: u64 = 16;
pub const bfd_mach_msp20: u64 = 20;
pub const bfd_mach_msp21: u64 = 21;
pub const bfd_mach_msp22: u64 = 22;
pub const bfd_mach_msp23: u64 = 23;
pub const bfd_mach_msp24: u64 = 24;
pub const bfd_mach_msp26: u64 = 26;
pub const bfd_mach_msp31: u64 = 31;
pub const bfd_mach_msp32: u64 = 32;
pub const bfd_mach_msp33: u64 = 33;
pub const bfd_mach_msp41: u64 = 41;
pub const bfd_mach_msp42: u64 = 42;
pub const bfd_mach_msp43: u64 = 43;
pub const bfd_mach_msp44: u64 = 44;
pub const bfd_mach_msp430x: u64 = 45;
pub const bfd_mach_msp46: u64 = 46;
pub const bfd_mach_msp47: u64 = 47;
pub const bfd_mach_msp54: u64 = 54;
pub const bfd_mach_xc16x: u64 = 1;
pub const bfd_mach_xc16xl: u64 = 2;
pub const bfd_mach_xc16xs: u64 = 3;
pub const bfd_mach_xgate: u64 = 1;
pub const bfd_mach_xtensa: u64 = 1;
pub const bfd_mach_z80strict: u64 = 1 /* No undocumented opcodes. */;
pub const bfd_mach_z80: u64 = 3 /* With ixl, ixh, iyl, and iyh. */;
pub const bfd_mach_z80full: u64 = 7 /* All undocumented instructions. */;
pub const bfd_mach_r800: u64 = 11 /* R800: successor with multiplication. */;
pub const bfd_mach_lm32: u64 = 1;
pub const bfd_mach_tilepro: u64 = 1;
pub const bfd_mach_tilegx: u64 = 1;
pub const bfd_mach_tilegx32: u64 = 2;
pub const bfd_mach_aarch64: u64 = 0;
pub const bfd_mach_aarch64_ilp32: u64 = 32;
pub const bfd_mach_nios2: u64 = 0;
pub const bfd_mach_nios2r1: u64 = 1;
pub const bfd_mach_nios2r2: u64 = 2;
pub const bfd_mach_visium: u64 = 1;
pub const bfd_mach_wasm32: u64 = 1;
pub const bfd_mach_pru: u64 = 0;
<file_sep>// <NAME> <<EMAIL>>
// binutils - build.rs

use std::env;
use std::ffi;
use std::fs::File;
use std::io::Read;
use std::path;
use std::process;

extern crate cc;

extern crate sha2;
use sha2::{Digest, Sha256};

fn execute_command(command: &str, arguments: Vec<&str>) {
    // Execute a command, and panic on any error

    let status = process::Command::new(command).args(arguments).status();
    match status {
        Ok(exit) => match exit.success() {
            true => (),
            false => panic!(
                "\n\n  \
                 Error '{}' exited with code {}\n\n",
                command,
                exit.code().unwrap()
            ),
        },
        Err(e) => panic!(
            "\n\n  \
             Error with '{}': {}\n\n",
            command, e
        ),
    };
}

fn change_dir(directory: &str) {
    // Go to another directory, and panic on error

    if !env::set_current_dir(directory).is_ok() {
        panic!(
            "\n\n  \
             Can't change dir to {}' !\n\n",
            directory
        );
    }
}

fn hash_file(filename: &str, hash_value: &str) -> bool {
    // Compute a SHA256 and return true if correct
    let mut f = File::open(filename).expect("file not found");
    let mut hasher = Sha256::new();

    loop {
        let mut buffer = [0; 256];

        let len = match f.read(&mut buffer[..]) {
            Err(_) => return false,
            Ok(len) => len,
        };
        if len == 0 {
            break;
        }

        hasher.input(&buffer[0..len]);
    }

    return format!("{:x}", hasher.result()) == hash_value;
}

fn build_binutils(version: &str, sha256sum: &str, output_directory: &str, targets: &str) {
    // Build binutils from source

    let binutils_name = format!("binutils-{}", version);
    let filename = format!("{}.tar.gz", binutils_name);
    let directory_filename = format!("{}/{}", output_directory, filename);

    // Check if binutils is already built
    if path::Path::new(&format!("{}/built/", output_directory)).exists() {
        return;
    }

    // Check if the tarball exists, or download it
    if !path::Path::new(&filename).exists() {
        execute_command(
            "curl",
            vec![
                format!("https://ftp.gnu.org/gnu/binutils/{}", filename).as_str(),
                "--output",
                &directory_filename,
            ],
        );
    }

    // Verify the SHA256 hash
    if !hash_file(&directory_filename, sha256sum) {
        panic!(
            "\n\n  \
             Incorrect hash value for {} !\n\n",
            filename
        );
    }

    // Check if the tarball exists after calling curl
    if !path::Path::new(&directory_filename).exists() {
        panic!(
            "\n\n  \
             Can't download {} to {} using curl!\n\n",
            filename, directory_filename
        );
    }

    // Call tar
    change_dir(output_directory);
    if !path::Path::new(&binutils_name).exists() {
        execute_command("tar", vec!["xzf", &filename]);
    }

    // Calls commands to build binutils
    if path::Path::new(&binutils_name).exists() {
        change_dir(&binutils_name);
        let prefix_arg = format!("--prefix={}/built/", output_directory);
        execute_command(
            "./configure",
            vec![&prefix_arg, &format!("--enable-targets={}", targets)],
        );
        execute_command("make", vec!["-j8"]);
        execute_command("make", vec!["install"]);

        // Copy useful files
        execute_command(
            "cp",
            vec![
                "opcodes/config.h",
                &format!("{}/built/include/", output_directory),
            ],
        );
        execute_command(
            "cp",
            vec![
                "libiberty/libiberty.a",
                &format!("{}/built/lib/", output_directory),
            ],
        );
    }
}

fn main() {
    let version = "2.29.1";
    let sha256 = "0d9d2bbf71e17903f26a676e7fba7c200e581c84b8f2f43e72d875d0e638771c";

    // Retrieve targets to build
    let targets_var = match env::var_os("TARGETS") {
        Some(dir) => dir,
        None => ffi::OsString::from("all"),
    };
    let targets = targets_var
        .as_os_str()
        .to_str()
        .expect("Invalid TARGETS content!");

    // Get the current working directory
    let current_dir = env::current_dir().unwrap();

    // Where binutils will be built
    let out_directory = format!("{}/target", current_dir.to_str().unwrap());

    // Build binutils
    build_binutils(version, sha256, &out_directory, targets);

    // Build our C helpers
    change_dir(current_dir.to_str().unwrap());
    cc::Build::new()
        .file("src/helpers.c")
        .include(format!("{}/built/include/", out_directory))
        .compile("helpers");

    // Locally compiled binutils libraries path
    println!(
        "cargo:rustc-link-search=native={}",
        format!("{}/built/lib/", out_directory)
    );
    println!("cargo:rustc-link-lib=static=bfd");
    println!("cargo:rustc-link-lib=static=opcodes");
    println!("cargo:rustc-link-lib=static=iberty");

    // Link to zlib
    println!("cargo:rustc-link-search=native=/usr/lib/"); // Arch Linux
    println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/"); // Debian based
    println!("cargo:rustc-link-lib=static=z");
}
<file_sep>// <NAME> <<EMAIL>>
// C based binutils and custom helpers

#include <config.h>

#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <bfd.h>
#include <dis-asm.h>

void buffer_to_rust(char *buffer);


// Silly macro that helps removing the unused warnings
#define UNUSED_VARIABLE(id) id=id


/*** Generic helpers ***/

#define BUFFER_SIZE 64
char buffer_asm[BUFFER_SIZE];
void copy_buffer(void* useless, const char* format, ...) {
    /* Construct the final opcode into buffer_asm */
    UNUSED_VARIABLE(useless);

    va_list ap;

    va_start(ap, format);
    vsnprintf(buffer_asm, BUFFER_SIZE, format, ap);
    va_end(ap);
    buffer_to_rust(buffer_asm);
}

void show_buffer(struct disassemble_info *info) {
    printf("len=%d - vma=%lu\n", info->buffer_length, info->buffer_vma);
    printf("%p\n", info->buffer);
    printf("%x\n", info->buffer[0]);
    printf("%x\n", info->buffer[1]);
    printf("%x\n", info->buffer[2]);
    printf("%x\n", info->buffer[3]);
}


/*** disassemble_info structure helpers ***/

disassemble_info* new_disassemble_info() {
    /* Return a new structure */
    struct disassemble_info *info = malloc (sizeof(struct disassemble_info));
    return info;
}

bfd_boolean configure_disassemble_info(struct disassemble_info *info, asection *section, bfd *bfdFile) {
    /* Construct and configure the disassembler_info class using stdout */
  
    init_disassemble_info (info, stdout, (fprintf_ftype) copy_buffer);
    info->arch = bfd_get_arch (bfdFile);
    info->mach = bfd_get_mach (bfdFile);
    info->section = section;

    info->buffer_vma = section->vma;
    info->buffer_length = section->size;

    return bfd_malloc_and_get_section (bfdFile, section, &info->buffer);
}

void configure_disassemble_info_buffer(struct disassemble_info *info, enum bfd_architecture arch, unsigned long mach) {
    /* A variant of configure_disassemble_info() for buffers */
  
    init_disassemble_info (info, stdout, (fprintf_ftype) copy_buffer);
    info->arch = arch;
    info->mach = mach;
    info->read_memory_func = buffer_read_memory;
}

typedef void (*print_address_func) (bfd_vma addr, struct disassemble_info *dinfo);
void set_print_address_func(struct disassemble_info *info, print_address_func print_function) {
    info->print_address_func = print_function;
}

asection* set_buffer(struct disassemble_info *info, bfd_byte* buffer, unsigned int length, bfd_vma vma) {
    /* Configure the buffet that will be disassembled */
    info->buffer = buffer;
    info->buffer_length = length;
    info->buffer_vma = vma;

    asection *section = (asection*) malloc(sizeof(asection));
    if (section) {
        info->section = section;
        info->section->vma = vma;
    }

    return (asection*) section;
}

asection* get_disassemble_info_section(struct disassemble_info *info) {
  return info->section;
}

unsigned long get_disassemble_info_section_vma(struct disassemble_info *info) {
  return info->section->vma;
}

void free_disassemble_info(struct disassemble_info *info, bool free_section) {
  /* Free the structure and allocated variable */
  if (info) {
    if (free_section && info->section)
      free(info->section);
    free(info);
  }
}


/*** bfd structure helpers ***/

unsigned long get_start_address(bfd *bfdFile) {
    return bfdFile->start_address;
}

unsigned int macro_bfd_big_endian(bfd *bfdFile) {
    return bfd_big_endian(bfdFile);
}


/*** bfd_arch_info structure helpers ***/

enum bfd_architecture get_arch(struct bfd_arch_info *arch_info) {
  return arch_info->arch;
}

unsigned long get_mach(struct bfd_arch_info *arch_info) {
  return arch_info->mach;
}


/*** section structure helpers ***/

unsigned long get_section_size(asection *section) {
    return section->size;
}
<file_sep>extern crate binutils;
use binutils::opcodes::DisassembleInfo;
use binutils::utils::disassemble_buffer;

#[test]
fn compact_loop() {
    // Prepare the disassembler
    let mut info = disassemble_buffer("i386", &[0xc3, 0x90, 0x66, 0x90], 0x2800)
        .unwrap_or(DisassembleInfo::empty());

    // Iterate over the instructions
    loop {
        match info
            .disassemble()
            .ok_or(2807)
            .map(|i| Some(i.unwrap()))
            .unwrap_or(None)
        {
            Some(instruction) => println!("{}", instruction),
            None => break,
        }
    }
}
<file_sep>// <NAME> <<EMAIL>>
// binutils - instruction.rs

use std::fmt;

use bfd::Bfd;
use helpers;
use opcodes::DisassembleInfo;
use Error;

#[allow(dead_code)]
pub struct Instruction<'a> {
    pub length: u64,
    pub offset: u64,
    pub opcode: String,
    info: Option<&'a mut DisassembleInfo>,
    pub error: Option<Error>,
}

impl<'a> fmt::Display for Instruction<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:X} {}", self.offset, self.opcode)
    }
}

pub(crate) fn get_opcode() -> Result<String, Error> {
    unsafe {
        let ret = match helpers::CURRENT_OPCODE {
            None => Err(Error::DisassembleInfoError("Empty opcode!".to_string())),
            Some(ref opcode) => Ok(opcode.clone()),
        };
        helpers::CURRENT_OPCODE = None;
        ret
    }
}

pub fn get_instruction<'a>(offset: u64, length: u64) -> Result<Instruction<'a>, Error> {
    Ok(Instruction {
        offset,
        length,
        opcode: get_opcode()?,
        info: None,
        error: None,
    })
}

impl<'a> Instruction<'a> {
    pub fn empty_with_error(error: Option<Error>) -> Instruction<'a> {
        Instruction {
            offset: 0,
            length: 0,
            opcode: String::new(),
            info: None,
            error,
        }
    }
    pub fn from_buffer(
        info: &'a mut DisassembleInfo,
        bfd: Bfd,
        buffer: &[u8],
        offset: u64,
    ) -> Instruction<'a> {
        match info.init_buffer(buffer, bfd, offset) {
            Ok(_) => (),
            Err(e) => return Instruction::empty_with_error(Some(e)),
        };

        Instruction {
            offset: 0,
            length: 0,
            opcode: String::new(),
            info: Some(info),
            error: None,
        }
    }
}

impl<'a> Iterator for Instruction<'a> {
    type Item = Instruction<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        // Temporarily remove info from the structure
        let info = match self.info.take() {
            Some(i) => i,
            None => {
                return Some(Instruction::empty_with_error(Some(
                    Error::DisassembleInfoError("empty".to_string()),
                )))
            }
        };

        let i = info.disassemble();
        match i {
            Some(r) => match r {
                Ok(i) => {
                    self.info = Some(info);
                    Some(i)
                }
                Err(_) => None,
            },
            None => None,
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_no_init() {
        use instruction;

        assert!(instruction::get_opcode().is_err());
        assert!(instruction::get_instruction(0, 0).is_err());
    }

    #[test]
    fn test_iterator() {
        use bfd;
        use instruction;
        use opcodes;

        let mut bfd = bfd::Bfd::empty();
        let _ = bfd.set_arch_mach("i386:x86-64");

        let mut info = opcodes::DisassembleInfo::new().unwrap();

        let buffer = vec![0x90];
        let mut instruction = instruction::Instruction::from_buffer(&mut info, bfd, &buffer, 0);
        match instruction.next() {
            Some(i) => assert_eq!(i.opcode, "nop"),
            None => assert!(false),
        };
    }
}
<file_sep>[package]
name = "binutils"
version = "0.1.1"
build = "build.rs"
authors = ["<NAME> <<EMAIL>>"]
license = "MIT"
readme = "README.md"
repository = "https://github.com/guedou/binutils-rs/"
description = "A Rust library that ease interacting with the binutils disassembly engine"
keywords = ["ffi", "binutils", "disassemble", "reverse"]
categories = ["api-bindings", "external-ffi-bindings"]
exclude = ["resources/*"]

[dependencies]
libc = "0.2.40"

[build-dependencies]
cc = "1.0"
sha2 = "0.7.1"
<file_sep># Copyright (C) 2018 <NAME> <<EMAIL>>

BINUTILS_BUILT_DIR=../../built/

CFLAG_INCLUDES=-I$(BINUTILS_BUILT_DIR)/include/
CFLAGS=-ggdb2
LDFLAGS=-L$(BINUTILS_BUILT_DIR)/lib/ -lbfd -lopcodes -Wl,-rpath,$(BINUTILS_BUILT_DIR)/lib/
TARGETS=test_binary test_buffer_mep test_buffer_x86_64

all: $(TARGETS)

.IGNORE: clean
clean:
	@rm $(TARGETS)

%: src/%.c
	gcc -o $@ $^ $(CFLAG_INCLUDES) -ldl -lz $(CFLAGS) $(LDFLAGS)
<file_sep># Playing with libfd and libopcodes

This directory contains examples that show howto call `binutils` bfd and
opcodes libraries from C:
1. [test_binary](examples/src/test_binary.c): this is the example from
   https://www.toothycat.net/wiki/wiki.pl?Binutils/libopcodes that was adapt to
   work with binutils 2.29.1
2. [test_buffer_x86_64](examples/src/test_buffer_x86_64.c): this example shows
   howto disassemble a buffer containing x86 instructions
3. [test_buffer_mep](examples/src/test_buffer_mep.c): similar to the second
   example with a more exotic architecture and binutils builtins

For convenience, the [libbfd](http://htmlpreview.github.com/?https://github.com/guedou/binutils-rs/blob/master/resources/docs/ToothyWiki_%20Binutils_Bfd.html) and
[libopcodes](http://htmlpreview.github.com/?https://github.com/guedou/binutils-rs/blob/master/resources/docs/ToothyWiki_%20Binutils_Libopcodes.html) documentation from
toothycat.net is archived in this repository.


## Building examples

The examples assume that binutils 2.29.1 is built at the root of this
repostitory. They can be compiled by typing `make` in the `src/` directory.

Here is how binutils dynamic libraries can be installed:
```
curl https://ftp.gnu.org/gnu/binutils/binutils-2.29.1.tar.gz -O
tar xzvf binutils-2.29.1.tar.gz
cd binutils-2.29.1/
./configure --prefix=../built --enable-shared --enable-targets=all
make -j8
```

Note: by default binutils does not produce shared libraries. When enabling all
targets, the resulting `objdump` binary is 61MB!
<file_sep>// <NAME> <<EMAIL>>
// binutils libopcodes bindings - opcodes.rs

use libc::{c_uint, c_ulong, uintptr_t};
use std;

use super::Error;
use bfd::{Bfd, BfdRaw};
use helpers;
use instruction::{get_instruction, Instruction};
use section::Section;
use utils;

extern "C" {
    pub(crate) fn disassembler(
        arc: c_uint,
        big_endian: bool,
        mach: c_ulong,
        bfd: *const BfdRaw,
    ) -> extern "C" fn(pc: c_ulong, info: *const DisassembleInfoRaw) -> c_ulong;

    fn disassemble_init_for_target(dinfo: *const DisassembleInfoRaw);
}

pub type DisassemblerFunction = dyn Fn(c_ulong, &DisassembleInfo) -> c_ulong;

pub(crate) enum DisassembleInfoRaw {}

pub struct DisassembleInfo {
    info: *const DisassembleInfoRaw,
    free_section: bool,
    disassembler: Option<Box<DisassemblerFunction>>,
    pc: u64,
}

impl DisassembleInfo {
    pub fn empty() -> DisassembleInfo {
        DisassembleInfo {
            info: std::ptr::null(),
            free_section: false,
            disassembler: None,
            pc: 0,
        }
    }

    pub fn new() -> Result<DisassembleInfo, Error> {
        let new_info = unsafe { helpers::new_disassemble_info() };
        if new_info.is_null() {
            return Err(Error::DisassembleInfoError(String::from(
                "Error while getting disassemble_info!",
            )));
        }

        Ok(DisassembleInfo {
            info: new_info,
            free_section: false,
            disassembler: None,
            pc: 0,
        })
    }

    pub(crate) fn raw(&self) -> *const DisassembleInfoRaw {
        self.info
    }

    pub fn configure(&self, section: Section, bfd: Bfd) -> Result<(), Error> {
        utils::check_null_pointer(self.info, "info pointer is null!")?;
        utils::check_null_pointer(self.raw(), "section pointer is null!")?;
        utils::check_null_pointer(bfd.raw(), "bfd pointer is null!")?;

        if !unsafe { helpers::configure_disassemble_info(self.info, section.raw(), bfd.raw()) } {
            return Err(Error::DisassembleInfoError(
                "Error while calling configure_disassemble_info() !".to_string(),
            ));
        }

        Ok(())
    }

    pub fn init_buffer(&mut self, buffer: &[u8], bfd: Bfd, offset: u64) -> Result<(), Error> {
        let disassemble_fn = match bfd.raw_disassembler(bfd.arch_mach.0, false, bfd.arch_mach.1) {
            Ok(f) => f,
            Err(e) => return Err(e),
        };

        self.configure_buffer(bfd.arch_mach.0, bfd.arch_mach.1, buffer, offset)?;
        self.configure_disassembler(disassemble_fn)?;
        self.init()?;

        Ok(())
    }

    pub fn configure_buffer(
        &mut self,
        arch: c_uint,
        mach: c_ulong,
        buffer: &[u8],
        offset: u64,
    ) -> Result<(), Error> {
        utils::check_null_pointer(self.info, "info pointer is null!")?;

        unsafe {
            let ptr = buffer.as_ptr();
            utils::check_null_pointer(ptr, "buffer pointer is null!")?;

            let len = buffer.len();
            if len == 0 {
                return Err(Error::DisassembleInfoError(
                    "buffer length is 0!".to_string(),
                ));
            };

            helpers::configure_disassemble_info_buffer(self.info, arch, mach);

            if helpers::set_buffer(self.info, ptr, len as u32, offset).is_null() {
                return Err(Error::DisassembleInfoError(
                    "set_buffer() malloc error!".to_string(),
                ));
            }
            self.free_section = true;
        }
        Ok(())
    }

    pub fn init(&self) -> Result<(), Error> {
        utils::check_null_pointer(self.info, "info pointer is null!")?;

        unsafe { disassemble_init_for_target(self.info) };
        Ok(())
    }

    pub fn set_print_address_func(
        &self,
        print_function: extern "C" fn(c_ulong, *const uintptr_t),
    ) -> Result<(), Error> {
        utils::check_null_pointer(self.info, "info pointer is null!")?;
        unsafe { helpers::set_print_address_func(self.info, print_function) }

        Ok(())
    }

    pub fn configure_disassembler(
        &mut self,
        disassembler: Box<DisassemblerFunction>,
    ) -> Result<(), Error> {
        if self.info.is_null() {
            self.pc = 0;
            self.disassembler = None;
            return Err(Error::DisassembleInfoError(
                "info pointer is null!".to_string(),
            ));
        }

        let section_raw = unsafe { helpers::get_disassemble_info_section(self.info) };
        utils::check_null_pointer(section_raw, "section pointer is null!")?;

        self.pc = unsafe { helpers::get_disassemble_info_section_vma(self.info) };
        self.disassembler = Some(disassembler);

        Ok(())
    }

    pub fn disassemble<'a>(&mut self) -> Option<Result<Instruction<'a>, Error>> {
        let f = match self.disassembler {
            Some(ref f) => f,
            None => {
                return Some(Err(Error::CommonError(
                    "disassembler not configured!".to_string(),
                )))
            }
        };

        let count = f(self.pc, self);
        if count == 4_294_967_295 {
            return None;
        }

        let instruction = get_instruction(self.pc, count);
        self.pc += count;
        Some(instruction)
    }
}

impl Drop for DisassembleInfo {
    fn drop(&mut self) {
        if !self.info.is_null() {
            unsafe {
                helpers::free_disassemble_info(self.info, self.free_section);
            }
            self.info = std::ptr::null();
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_di_empty() {
        use bfd;
        use opcodes;
        use std;

        let mut di = opcodes::DisassembleInfo::empty();
        assert_eq!(di.info, std::ptr::null());

        let mut bfd = bfd::Bfd::empty();
        match di.init_buffer(&[0x90], bfd, 0) {
            Ok(_) => assert!(false),
            Err(_) => assert!(true),
        };

        let _ = bfd.set_arch_mach("i386:x86-64");
        let _ = di.configure_buffer(bfd.arch_mach.0, bfd.arch_mach.1, &[0x90], 1);

        let disassemble_fn = bfd
            .raw_disassembler(bfd.arch_mach.0, false, bfd.arch_mach.1)
            .unwrap();
        let _ = di.configure_disassembler(disassemble_fn);
    }

    #[test]
    fn test_configure_null() {
        // Make sure that configure() test null pointers
        use bfd;
        use opcodes;
        use section;
        use std;

        let mut di = opcodes::DisassembleInfo::new().unwrap();
        assert_ne!(di.info, std::ptr::null());

        let section = section::Section::null();
        match di.configure(section, bfd::Bfd::empty()) {
            Ok(_) => assert!(false),
            Err(_) => assert!(true),
        }

        let section = section::Section::from_raw(0x2807 as *const section::SectionRaw);
        match di.configure(section.unwrap(), bfd::Bfd::empty()) {
            Ok(_) => assert!(false),
            Err(_) => assert!(true),
        }

        let mut bfd = bfd::Bfd::empty();
        let _ = bfd.set_arch_mach("i386:x86-64");
        let _ = di.configure_buffer(bfd.arch_mach.0, bfd.arch_mach.1, &[], 0);
    }

    #[test]
    fn test_configure_disassembler() {
        use bfd;
        use opcodes;
        use std;

        let mut di = opcodes::DisassembleInfo::new().unwrap();
        assert_ne!(di.info, std::ptr::null());

        let mut bfd = bfd::Bfd::empty();
        let _ = bfd.set_arch_mach("i386:x86-64");

        let disassemble_fn = bfd
            .raw_disassembler(bfd.arch_mach.0, false, bfd.arch_mach.1)
            .unwrap();
        let _ = di.configure_disassembler(disassemble_fn);
    }
}
<file_sep>// <NAME> <<EMAIL>>

#include <config.h>

#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <bfd.h>
#include <dis-asm.h>

bfd_byte buffer[] = { 0xc3, 0x90, 0x66, 0x90 };
int buffer_len = 4;
int buffer_ptr = 0;

int copy_buffer(bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
  struct disassemble_info *dinfo) {
  // Copy our buffer to binutils
  
  if (length > buffer_len)
    return 1;

  memcpy (myaddr, &buffer[buffer_ptr], length);
  buffer_ptr += length;

  return 0;
}

int main(int argc, char** argv) {
  disassembler_ftype      disassemble;
  struct disassemble_info info;
  unsigned long           count, pc;

  /* Construct a specific disassembler */
  enum bfd_architecture arch = bfd_arch_i386;
  bfd_boolean big_endian = FALSE;
  unsigned long mach = bfd_mach_x86_64;
  disassemble = disassembler (arch, big_endian, mach, NULL);
  if( disassemble == NULL) {
    printf ("Error creating disassembler\n");
    return EXIT_FAILURE;
  }

  /* Construct and configure the disassembler_info structure */
  init_disassemble_info (&info, stdout, (fprintf_ftype) fprintf);
  info.arch = arch;
  info.mach = mach;
  info.read_memory_func = copy_buffer;

  disassemble_init_for_target (&info);

  /* Disassemble instruction from the buffer */
  pc = 0;
  for (int i=0; i < 3; i++) {
    printf ("Address: 0x%lx\n", pc);
    count = disassemble (pc, &info);
    pc += count;
    printf ("\nType: 0x%x\n", info.insn_type);
    printf ("====\n");
  }

  return EXIT_SUCCESS;
}
<file_sep>// <NAME> <<EMAIL>>
// binutils libbfd bindings - bfd.rs

use libc::{c_char, c_uint, c_ulong, uintptr_t};

use std;
use std::ffi::{CStr, CString};

use helpers::{get_arch, get_mach, get_start_address, macro_bfd_big_endian, CURRENT_OPCODE};
use opcodes::{disassembler, DisassembleInfo, DisassemblerFunction};
use section::{Section, SectionRaw};
use utils;
use Error;

extern "C" {
    fn bfd_init();

    pub fn bfd_get_error() -> c_uint;

    pub fn bfd_errmsg(error_tag: c_uint) -> *const c_char;

    fn bfd_openr(filename: *const c_char, target: *const c_char) -> *const BfdRaw;

    fn bfd_check_format(bfd: *const BfdRaw, bfd_format: BfdFormat) -> bool;

    fn bfd_get_section_by_name(bfd: *const BfdRaw, name: *const c_char) -> *const SectionRaw;

    fn bfd_arch_list() -> *const uintptr_t;

    fn bfd_scan_arch(string: *const c_char) -> *const c_uint;

    fn bfd_get_arch(bfd: *const BfdRaw) -> c_uint;

    fn bfd_get_mach(bfd: *const BfdRaw) -> c_ulong;
}

// Rust bfd types
// Note: - trick from https://doc.rust-lang.org/nomicon/ffi.html
//       - it allows to use the Rust type checker
pub(crate) enum BfdRaw {}

#[derive(Clone, Copy)]
pub struct Bfd {
    bfd: *const BfdRaw,
    pub arch_mach: (u32, u64),
}

impl Bfd {
    pub(crate) fn raw(&self) -> *const BfdRaw {
        self.bfd
    }

    pub fn empty() -> Bfd {
        unsafe { bfd_init() };
        Bfd {
            bfd: std::ptr::null(),
            arch_mach: (0, 0),
        }
    }

    pub fn openr(filename: &str, target: &str) -> Result<Bfd, Error> {
        unsafe { bfd_init() };

        let filename_cstring = CString::new(filename)?;
        let target_cstring = CString::new(target)?;

        let bfd = unsafe { bfd_openr(filename_cstring.as_ptr(), target_cstring.as_ptr()) };
        if bfd.is_null() {
            return Err(bfd_convert_error());
        };

        Ok(Bfd {
            bfd,
            arch_mach: (0, 0),
        })
    }

    pub fn check_format(&self, format: BfdFormat) -> Result<(), Error> {
        utils::check_null_pointer(self.bfd, "bfd pointer is null!")?;

        if !unsafe { bfd_check_format(self.bfd, format) } {
            return Err(bfd_convert_error());
        };

        Ok(())
    }

    pub fn get_section_by_name(&self, section_name: &str) -> Result<Section, Error> {
        utils::check_null_pointer(self.bfd, "bfd pointer is null!")?;

        let section_name_cstring = CString::new(section_name)?;

        let section = unsafe { bfd_get_section_by_name(self.bfd, section_name_cstring.as_ptr()) };
        if section.is_null() {
            return Err(Error::SectionError(section_name.to_string()));
        };

        Ok(Section::from_raw(section)?)
    }

    pub fn disassembler(&self) -> Result<Box<DisassemblerFunction>, Error> {
        utils::check_null_pointer(self.bfd, "bfd pointer is null!")?;

        let arch = unsafe { bfd_get_arch(self.bfd) };
        let big_endian = match self.is_big_endian() {
            Ok(be) => be,
            Err(e) => return Err(e),
        };
        let mach = unsafe { bfd_get_mach(self.bfd) };
        self.raw_disassembler(arch, big_endian, mach)
    }

    pub fn raw_disassembler(
        &self,
        arch: c_uint,
        big_endian: bool,
        mach: c_ulong,
    ) -> Result<Box<DisassemblerFunction>, Error> {
        let disassemble = unsafe { disassembler(arch, big_endian, mach, self.bfd) };
        if (disassemble as *const c_uint).is_null() {
            return Err(Error::BfdError(
                0,
                String::from("Error creating disassembler!"),
            ));
        };

        let disassemble_closure = move |p: c_ulong, di: &DisassembleInfo| -> c_ulong {
            // Reset the buffer pointer
            unsafe {
                CURRENT_OPCODE = None;
            }
            disassemble(p, di.raw())
        };

        Ok(Box::new(disassemble_closure))
    }

    pub fn get_start_address(&self) -> Result<c_ulong, Error> {
        utils::check_null_pointer(self.bfd, "bfd pointer is null!")?;

        Ok(unsafe { get_start_address(self.bfd) })
    }

    pub fn is_big_endian(&self) -> Result<bool, Error> {
        utils::check_null_pointer(self.bfd, "bfd pointer is null!")?;

        Ok(unsafe { macro_bfd_big_endian(self.bfd) })
    }
    pub fn set_arch_mach(&mut self, arch: &str) -> Result<(u32, u64), Error> {
        let arch_cstring = CString::new(arch)?;
        let arch_info = unsafe { bfd_scan_arch(arch_cstring.as_ptr()) };
        if arch_info.is_null() {
            return Err(Error::BfdError(0, "architecture not found!".to_string()));
        };
        self.arch_mach = unsafe { (get_arch(arch_info), get_mach(arch_info)) };
        Ok(self.arch_mach)
    }
}

pub fn arch_list() -> Vec<String> {
    let mut ret_vec = Vec::new();
    let mut index = 0;
    let mut stop = false;

    let list = unsafe { bfd_arch_list() };
    if list.is_null() {
        return ret_vec;
    }

    loop {
        let slice = unsafe { std::slice::from_raw_parts(list.offset(index), 32) };
        for item in slice.iter().take(32) {
            if *item == 0 {
                stop = true;
                break;
            }
            let arch = unsafe { CStr::from_ptr(*item as *const i8).to_str() };
            match arch {
                Ok(s) => ret_vec.push(s.to_string()),
                Err(_) => ret_vec.push("arch_list() - from_ptr() error !".to_string()),
            }
        }
        if stop {
            break;
        } else {
            index += 32;
        }
    }

    unsafe { libc::free(list as *mut libc::c_void); }

    ret_vec
}

fn bfd_convert_error() -> Error {
    let error = unsafe { bfd_get_error() };
    let msg_char = unsafe { bfd_errmsg(error) };
    let msg_str = match unsafe { CStr::from_ptr(msg_char).to_str() } {
        Ok(s) => s,
        Err(e) => return Error::Utf8Error(e),
    };
    Error::BfdError(error, msg_str.to_string())
}

#[allow(non_camel_case_types)] // use the same enum names as libbfd
#[allow(dead_code)] // don't warn that some variants are not used
#[repr(C)]
pub enum BfdFormat {
    bfd_unknown = 0,
    bfd_object,
    bfd_archive,
    bfd_core,
    bfd_type_end,
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_bfd_empty() {
        use bfd;
        use std;

        let bfd = bfd::Bfd::empty();
        assert_eq!(bfd.bfd, std::ptr::null());
        assert_eq!(bfd.arch_mach, (0, 0));

        match bfd.get_start_address() {
            Ok(_) => assert!(false),
            Err(_) => assert!(true),
        };
        match bfd.is_big_endian() {
            Ok(_) => assert!(false),
            Err(_) => assert!(true),
        };
    }

    #[test]
    fn test_bfd_openr() {
        use bfd;
        use std;
        use Error;

        let raw_binary_name = b"bin\0name".to_vec();
        let binary_name = unsafe { std::str::from_utf8_unchecked(&raw_binary_name) };
        match bfd::Bfd::openr(binary_name, "elf64-x86-64") {
            Ok(_) => assert!(false),
            Err(Error::NulError(_)) => assert!(true),
            Err(_) => assert!(false),
        };

        match bfd::Bfd::openr("/bin/ls", "elf64-x86-64") {
            Ok(_) => assert!(true),
            Err(_) => assert!(false),
        };

        match bfd::Bfd::openr("", "") {
            Ok(_) => assert!(false),
            Err(Error::BfdError(_, _)) => assert!(true),
            Err(_) => assert!(false),
        };
    }

    #[test]
    fn test_bfd_get_section_bad() {
        use bfd;
        use std;
        use Error;

        let bfd = bfd::Bfd::openr("/bin/ls", "elf64-x86-64").unwrap();
        let raw_section_name = b".\0text".to_vec();
        let section_name = unsafe { std::str::from_utf8_unchecked(&raw_section_name) };
        match bfd.get_section_by_name(section_name) {
            Ok(_) => assert!(false),
            Err(Error::NulError(_)) => assert!(true),
            Err(_) => assert!(false),
        }

        match bfd.get_section_by_name("unknown") {
            Ok(_) => assert!(false),
            Err(Error::SectionError(_)) => assert!(true),
            Err(_) => assert!(false),
        }
    }

    #[test]
    fn test_bfd_get_section_good() {
        use bfd;

        let bfd = bfd::Bfd::openr("/bin/ls", "elf64-x86-64").unwrap();
        bfd.check_format(bfd::BfdFormat::bfd_object).unwrap();
        match bfd.get_section_by_name(".text") {
            Ok(section) => {
                assert!(!section.raw().is_null());
                assert!(section.get_size().unwrap() > 0);
            }
            Err(_) => assert!(false),
        };

        assert!(bfd.get_start_address().is_ok());
        assert!(!bfd.is_big_endian().unwrap_or(true));
    }

    #[test]
    fn test_bfd_arch_list() {
        use bfd;

        assert_eq!(bfd::arch_list()[0..2].len(), 2);
    }

    #[test]
    fn test_bfd_disassemble() {
        use bfd;
        use opcodes;

        let bfd = bfd::Bfd::openr("/bin/ls", "elf64-x86-64").unwrap();
        bfd.check_format(bfd::BfdFormat::bfd_object).unwrap();
        let section = bfd.get_section_by_name(".text").unwrap();

        let info = match opcodes::DisassembleInfo::new() {
            Ok(i) => i,
            Err(_) => {
                assert!(false);
                return;
            }
        };

        match info.configure(section, bfd) {
            Ok(_) => assert!(true),
            Err(_) => assert!(false),
        };
    }
}
<file_sep>// <NAME> <<EMAIL>>

#include <config.h>

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include <bfd.h>
#include <dis-asm.h>

bfd_byte buffer[] = { 0x53, 0x53,
	              0x08, 0xd8, 0x01, 0x00,
	              0x53, 0x53,
		      0x30, 0xeb, 0x5b, 0x00
                    }; 
unsigned int buffer_len = 12;


int main (int argc, char ** argv) {
  bfd                     *bfdFile;
  asection                *section;
  disassembler_ftype      disassemble;
  struct disassemble_info info;
  unsigned long           count, pc;

  /* Open /dev/null as a binary target with libbfd */
  bfdFile = bfd_openr ("/dev/null", "binary");
  if (bfdFile == NULL) {
    printf ("Error [%x]: %s\n", bfd_get_error (),
                                bfd_errmsg (bfd_get_error ()));
    return EXIT_FAILURE;
  }

  /* Check the file format */
  if (!bfd_check_format (bfdFile, bfd_object)) {
    printf ("Error [%x]: %s\n", bfd_get_error (),
                                bfd_errmsg (bfd_get_error ()));
    return EXIT_FAILURE;
  }

  /* Retrieve the ELF .data code section */
  section = bfd_get_section_by_name (bfdFile, ".data");
  if (section == NULL) {
    printf ("Error accessing .text section\n");
    return EXIT_FAILURE;
  }

  /* Configure a MeP disassembler */
  enum bfd_architecture arch = bfd_arch_mep;
  bfd_boolean big_endian = BFD_ENDIAN_BIG;
  unsigned long mach = bfd_mach_mep;
  bfd_default_set_arch_mach(bfdFile, arch, mach);
  disassemble = disassembler (bfd_get_arch (bfdFile), bfd_big_endian (bfdFile),
                              bfd_get_mach (bfdFile), bfdFile);
  if( disassemble == NULL) {
    printf ("Error creating disassembler\n" );
    return EXIT_FAILURE;
  }

  /* Construct and configure the disassembler_info structure */
  init_disassemble_info (&info, stdout, (fprintf_ftype) fprintf);
  info.arch = bfd_get_arch (bfdFile);
  info.mach = bfd_get_mach (bfdFile);
  info.section = section;

  /* Configure buffer information */
  section->vma = 0xC00000; // memory offset
  info.read_memory_func = buffer_read_memory; // builtin
  info.buffer_length = buffer_len;
  info.buffer = (bfd_byte*) &buffer;
  info.buffer_vma = section->vma;

  /* Initialize the disassembler_info structure */
  disassemble_init_for_target (&info);

  /* Diassemble instructions */
  pc = section->vma;
  for (int i=0; i < 4; i++) {
    printf ("Address: 0x%lx\n  ", pc);
    count = disassemble (pc, &info);
    pc += count;
    printf ("\n====\n");
    fflush (stdout);
  }

  return EXIT_SUCCESS;
}
<file_sep># binutils-rs

A Rust library that ease interacting with the
[binutils](https://www.gnu.org/software/binutils/) disassembly engine with a
high-level API. Its main goal is to simplify disassembling raw buffers into
instructions.

[![crates.io badge](https://img.shields.io/crates/v/binutils.svg)](https://crates.io/crates/binutils/)
[![doc.rs badge](https://docs.rs/binutils/badge.svg)](https://docs.rs/crate/binutils/)

## Usage

You need to add the following lines to your `Cargo.toml`:
```toml
[dependencies]
binutils = "0.1.1"
```

and make sure that your are using it in your code:
```rust
extern crate binutils;
```

> **Note:**
By default, all architectures supported by binutils will be built by cargo. The
resulting library will be over 60MB. When size is an issue, the `TARGETS`
environment variable can be set to only build specific architectures (i.e.
`TARGETS=arm-linux,mep`) as defined in `bfd/config.bfd`.
>

## Examples

Here is how to disassemble a buffer containing x86 instructions while being
gentle with errors:
```rust
extern crate binutils;
use binutils::utils::disassemble_buffer;
use binutils::opcodes::DisassembleInfo;

// Prepare the disassembler
let mut info = disassemble_buffer("i386", &[0xc3, 0x90, 0x66, 0x90], 0x2800)
    .unwrap_or(DisassembleInfo::empty());

// Iterate over the instructions
loop {
    match info.disassemble()
        .ok_or(2807)
        .map(|i| Some(i.unwrap()))
        .unwrap_or(None)
    {
        Some(instruction) => println!("{}", instruction),
        None => break,
    }
}
```

Other examples are located in the [examples/](examples) directory, and be used
with `cargo run --example`.

## Resources

Examples in C and archived documentations are available in the
[resources/](resources/) directory.

## Roadmap

- [ ] add Travis support: test and rustfmt
- [ ] code coverage with tarpaulin
- [ ] write more tests
- [ ] investigate stripping libraries
- [ ] convert check_null_pointer() to a macro to add file and line numbers to the Error
- [ ] fuzz the disassembler
- [ ] generate mach.rs with build.rs
- [ ] generate documentation from comments
- [ ] use the error_chain crate
- [ ] investigate info->stop_vma
- [ ] rewrite copy_buffer in Rust
<file_sep>// <NAME> <<EMAIL>>
// binutils - utils.rs

use bfd::{arch_list, Bfd};
use helpers;
use opcodes::DisassembleInfo;
use Error;

pub fn disassemble_buffer(
    arch_name: &str,
    buffer: &[u8],
    offset: u64,
) -> Result<DisassembleInfo, Error> {
    // Create a bfd structure
    let mut bfd = Bfd::empty();

    // Check if the architecture is supported
    if !arch_list().iter().any(|arch| arch == arch_name) {
        let error = Error::CommonError(format!("Unsupported architecture ({})!", arch_name));
        return Err(error);
    }

    // Set bfd_arch and bfd_mach from the architecture name
    let _ = bfd.set_arch_mach(arch_name);

    // Create a disassemble_info structure
    let mut info = DisassembleInfo::new()?;

    // Configure the disassemble_info structure
    info.init_buffer(buffer, bfd, offset)?;

    Ok(info)
}

pub(crate) fn check_null_pointer<T>(pointer: *const T, message: &str) -> Result<(), Error> {
    if pointer.is_null() {
        Err(Error::NullPointerError(message.to_string()))
    } else {
        Ok(())
    }
}

pub fn opcode_buffer_append(string: &str) {
    unsafe {
        let tmp = match helpers::CURRENT_OPCODE {
            Some(ref o) => o,
            None => "",
        };
        helpers::CURRENT_OPCODE = Some(format!("{}{}", tmp, string));
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_opcode_buffer_append() {
        use helpers;
        use utils;

        unsafe {
            helpers::CURRENT_OPCODE = None;
            utils::opcode_buffer_append("te");
            assert_eq!(helpers::CURRENT_OPCODE, Some("te".to_string()));
            utils::opcode_buffer_append("st!");
            assert_eq!(helpers::CURRENT_OPCODE, Some("test!".to_string()));
            helpers::CURRENT_OPCODE = None;
        }
    }
}
<file_sep>// <NAME> <<EMAIL>>
// binutils bindings to helpers.c - helpers.rs

#![doc(hidden)]

use std::ffi::CStr;

use libc::{c_char, c_uchar, c_uint, c_ulong, uintptr_t};

use bfd::BfdRaw;
use opcodes::DisassembleInfoRaw;
use section::SectionRaw;

extern "C" {
    // libbfd helpers
    pub(crate) fn macro_bfd_big_endian(bfd: *const BfdRaw) -> bool;

    pub(crate) fn get_start_address(bfd: *const BfdRaw) -> c_ulong;

    pub(crate) fn get_arch(arch_info: *const c_uint) -> u32;

    pub(crate) fn get_mach(arch_info: *const c_uint) -> u64;

    // libopcodes helpers
    pub(crate) fn new_disassemble_info() -> *const DisassembleInfoRaw;

    pub(crate) fn configure_disassemble_info(
        info: *const DisassembleInfoRaw,
        section: *const SectionRaw,
        bfd: *const BfdRaw,
    ) -> bool;

    pub(crate) fn configure_disassemble_info_buffer(
        info: *const DisassembleInfoRaw,
        arch: c_uint,
        mach: c_ulong,
    );

    pub(crate) fn set_print_address_func(
        info: *const DisassembleInfoRaw,
        print_function: extern "C" fn(c_ulong, *const uintptr_t),
    );

    pub(crate) fn set_buffer(
        info: *const DisassembleInfoRaw,
        buffer: *const c_uchar,
        length: c_uint,
        vma: c_ulong,
    ) -> *const SectionRaw;

    pub(crate) fn free_disassemble_info(info: *const DisassembleInfoRaw, free_section: bool);

    pub(crate) fn get_disassemble_info_section(
        info: *const DisassembleInfoRaw,
    ) -> *const DisassembleInfoRaw;

    pub(crate) fn get_disassemble_info_section_vma(info: *const DisassembleInfoRaw) -> c_ulong;

    // Custom helpers
    #[allow(dead_code)]
    pub(crate) fn show_buffer(info: *const DisassembleInfoRaw);
}

pub(crate) static mut CURRENT_OPCODE: Option<String> = None;

/// # Safety
///
/// This function is used to copy the disassembly buffer to a static variable
#[no_mangle]
pub unsafe extern "C" fn buffer_to_rust(buffer: *const c_char) {
    let buffer_cstr = CStr::from_ptr(buffer);
    let current_string = match CURRENT_OPCODE {
        Some(ref o) => o,
        None => "",
    };
    let new_string = match buffer_cstr.to_str() {
        Ok(s) => s.to_string(),
        Err(e) => format!("buffer_to_rust() - {}", e),
    };
    CURRENT_OPCODE = Some(format!("{}{}", current_string, new_string));
}
<file_sep>// <NAME> <<EMAIL>>

#include <config.h>

#include <stdlib.h>
#include <string.h>

#include <bfd.h>
#include <dis-asm.h>

void override_print_address(bfd_vma addr, struct disassemble_info *info)
{
  // This function change how addresses are displayed
  printf ("0x%x", addr);
}

int main(int argc, char **argv)
{
  bfd                     *bfdFile;
  asection                *section;
  disassembler_ftype      disassemble;
  struct disassemble_info info;
  unsigned long           count, pc;

  /* Open an ELF binary with libbfd */
  bfd_init ();
  bfdFile = bfd_openr ("/bin/ls", "elf64-x86-64");
  if (bfdFile == NULL) {
    printf ("Error [%x]: %s\n", bfd_get_error (),
                                bfd_errmsg (bfd_get_error ()));
    return EXIT_FAILURE;
  }
  if (!bfd_check_format( bfdFile, bfd_object)) {
    printf ("Error [%x]: %s\n", bfd_get_error (),
                                bfd_errmsg (bfd_get_error ()));
    return EXIT_FAILURE;
  }

  /* Retrieve the ELF .text code section */
  section = bfd_get_section_by_name (bfdFile, ".text");
  if (section == NULL) {
    printf ("Error accessing .text section\n");
    return EXIT_FAILURE;
  }

  /* Get a disassemble function pointer */
  disassemble = disassembler (bfd_get_arch (bfdFile), bfd_big_endian (bfdFile),
                              bfd_get_mach (bfdFile), bfdFile);
  if (disassemble == NULL) {
    printf ("Error creating disassembler\n");
    return EXIT_FAILURE;
  }

  /* Construct and configure the disassembler_info class */ 
  init_disassemble_info (&info, stdout, (fprintf_ftype) fprintf);
  info.print_address_func = override_print_address;
  info.arch          = bfd_get_arch (bfdFile);
  info.mach          = bfd_get_mach (bfdFile);
  info.buffer_vma    = section->vma;
  info.buffer_length = section->size;
  info.section       = section;
  bfd_malloc_and_get_section (bfdFile, section, &info.buffer);
  disassemble_init_for_target (&info);

  /* Start diassembling */
  pc = bfd_get_start_address (bfdFile);
  do {
    printf ("0x%x  ", pc);
    count = disassemble (pc, &info);
    pc += count;
    printf ("\n");
  } while (count > 0 && pc <= section->size);

  return EXIT_SUCCESS;
}
<file_sep>// <NAME> <<EMAIL>>
// binutils - section.rs

use libc::c_ulong;

use std::ptr;

use utils;
use Error;

extern "C" {
    fn get_section_size(section: *const SectionRaw) -> c_ulong;
}

pub enum SectionRaw {}

#[derive(Clone, Copy)]
pub struct Section {
    pub section: *const SectionRaw,
}

impl Section {
    #[allow(dead_code)]
    pub(crate) fn null() -> Section {
        Section {
            section: ptr::null(),
        }
    }

    pub(crate) fn raw(self) -> *const SectionRaw {
        self.section
    }

    pub fn from_raw(section_raw: *const SectionRaw) -> Result<Section, Error> {
        utils::check_null_pointer(section_raw, "raw section pointer is null!")?;

        Ok(Section {
            section: section_raw,
        })
    }

    pub fn get_size(self) -> Result<c_ulong, Error> {
        utils::check_null_pointer(self.section, "section pointer is null!")?;

        Ok(unsafe { get_section_size(self.section) })
    }
}
<file_sep>// <NAME> <<EMAIL>>
// binutils - test_binary.rs

extern crate libc;
use libc::{c_ulong, uintptr_t};

extern crate binutils;
use binutils::bfd;
use binutils::instruction;
use binutils::opcodes::DisassembleInfo;
use binutils::utils;

extern "C" fn change_address(addr: c_ulong, _info: *const uintptr_t) {
    // Example of C callback that modifies an address used by an instruction

    // Format the address and copy it to the buffer
    utils::opcode_buffer_append(&format!("0x{:x}", addr));
}

fn test_ls(max_instructions: Option<u8>) {
    println!("From an ELF");

    let bfd = match bfd::Bfd::openr("/bin/ls", "elf64-x86-64") {
        Ok(b) => b,
        Err(e) => {
            println!("Error with openr() - {}", e);
            return;
        }
    };

    match bfd.check_format(bfd::BfdFormat::bfd_object) {
        Ok(_) => (),
        Err(e) => {
            println!("Error with check_format() - {}", e);
            return;
        }
    };

    // Retrieve the .text code section
    let section = match bfd.get_section_by_name(".text") {
        Ok(s) => s,
        Err(e) => {
            println!("Error with get_section_by_name() - {}", e);
            return;
        }
    };

    // Construct disassembler_ftype class
    let disassemble = match bfd.disassembler() {
        Ok(d) => d,
        Err(e) => {
            println!("Error with disassembler() - {}", e);
            return;
        }
    };

    // Create a disassemble_info structure
    let info = match DisassembleInfo::new() {
        Ok(i) => i,
        Err(e) => {
            println!("{}", e);
            return;
        }
    };

    // Configure the disassemble_info structure
    match info.configure(section, bfd) {
        Ok(_) => (),
        Err(e) => {
            println!("Error configure() - {}", e);
            return;
        }
    };
    match info.set_print_address_func(change_address) {
        Ok(_) => (),
        Err(e) => {
            println!("Error set_print_address_func() - {}", e);
            return;
        }
    };
    match info.init() {
        Ok(_) => (),
        Err(e) => {
            println!("Error init() - {}", e);
            return;
        }
    };

    // Disassemble the binary
    let mut pc = match bfd.get_start_address() {
        Ok(a) => a,
        Err(e) => {
            println!("Error with get_start_address() - {}", e);
            return;
        }
    };
    let section_size = match section.get_size() {
        Ok(a) => a,
        Err(e) => {
            println!("Error with get_size() - {}", e);
            return;
        }
    };
    let mut counter = 0;
    loop {
        let length = disassemble(pc, &info);
        let instruction = match instruction::get_instruction(pc, length) {
            Ok(i) => i,
            Err(e) => {
                println!("{}", e);
                return;
            }
        };

        println!("{}", instruction);

        pc += length;
        counter += 1;

        if !(length > 0 && pc <= section_size) {
            break;
        }

        if !max_instructions.is_none() && max_instructions.unwrap() <= counter {
            break;
        }
    }
}

fn main() {
    test_ls(Some(12));
}
<file_sep>// <NAME> <<EMAIL>>
// binutils - test_buffer.rs

extern crate binutils;
use binutils::bfd;
use binutils::instruction;
use binutils::instruction::Instruction;
use binutils::opcodes::DisassembleInfo;
use binutils::utils;

fn test_buffer_full(arch_name: &str, buffer: Vec<u8>, offset: u64) {
    println!("---");
    println!("From a buffer (full API) - {}", arch_name);

    let mut bfd = bfd::Bfd::empty();

    if !bfd::arch_list().iter().any(|arch| arch == arch_name) {
        println!("Unsuported architecture ({})!", arch_name);
        return;
    }

    // Retrieve bfd_arch and bfd_mach from the architecture name
    let bfd_arch_mach = match bfd.set_arch_mach(arch_name) {
        Ok(arch_mach) => arch_mach,
        Err(e) => {
            println!("Error with set_arch_mach() - {}", e);
            return;
        }
    };

    // Construct disassembler_ftype class
    let disassemble = match bfd.raw_disassembler(bfd_arch_mach.0, false, bfd_arch_mach.1) {
        Ok(d) => d,
        Err(e) => {
            println!("Error with raw_disassembler() - {}", e);
            return;
        }
    };

    // Create a disassemble_info structure
    let mut info = match DisassembleInfo::new() {
        Ok(i) => i,
        Err(e) => {
            println!("{}", e);
            return;
        }
    };

    // Configure the disassemble_info structure
    match info.configure_buffer(bfd_arch_mach.0, bfd_arch_mach.1, &buffer, offset) {
        Ok(_) => (),
        Err(e) => {
            println!("configure_buffer() - {}", e);
            return;
        }
    };
    match info.init() {
        Ok(_) => (),
        Err(e) => {
            println!("Error init() - {}", e);
            return;
        }
    };

    // Disassemble the buffer
    let mut pc = offset;
    for _i in 0..3 {
        let length = disassemble(pc, &info);
        let instruction = match instruction::get_instruction(pc, length) {
            Ok(i) => i,
            Err(e) => {
                println!("{}", e);
                return;
            }
        };
        println!("{}", instruction);
        pc += length;
    }
}

fn test_buffer_compact(arch_name: &str, buffer: Vec<u8>, offset: u64) {
    println!("---");
    println!("From a buffer (compact API) - {}", arch_name);

    let mut bfd = bfd::Bfd::empty();

    if !bfd::arch_list().iter().any(|arch| arch == arch_name) {
        println!("Unsuported architecture ({})!", arch_name);
        return;
    }

    // Set bfd_arch and bfd_mach from the architecture name
    let _ = bfd.set_arch_mach(arch_name);

    // Create a disassemble_info structure
    let mut info = match DisassembleInfo::new() {
        Ok(i) => i,
        Err(e) => {
            println!("{}", e);
            return;
        }
    };

    // Configure the disassemble_info structure
    match info.init_buffer(&buffer, bfd, offset) {
        Ok(_) => (),
        Err(e) => {
            println!("init_buffer() - {}", e);
            return;
        }
    };

    // Disassemble the buffer
    loop {
        let instruction = match info.disassemble() {
            None => break,
            Some(i) => match i {
                Ok(i) => i,
                Err(e) => {
                    println!("disassemble() - {}", e);
                    break;
                }
            },
        };
        println!("{}", instruction);
    }
}

fn test_buffer_utils(arch_name: &str, buffer: Vec<u8>, offset: u64) {
    println!("---");
    println!("From a buffer (binutils::utils) - {}", arch_name);

    let mut info = match utils::disassemble_buffer(arch_name, &buffer, offset) {
        Ok(i) => i,
        Err(e) => {
            println!("{}", e);
            return;
        }
    };

    // Disassemble the buffer
    loop {
        let instruction = match info.disassemble() {
            None => break,
            Some(i) => match i {
                Ok(i) => i,
                Err(e) => {
                    println!("disassemble() - {}", e);
                    break;
                }
            },
        };
        println!("{}", instruction);
    }
}

fn test_buffer_iter(arch_name: &str, buffer: Vec<u8>, offset: u64) {
    println!("---");
    println!("From a buffer (iter) - {}", arch_name);

    let mut bfd = bfd::Bfd::empty();

    if !bfd::arch_list().iter().any(|arch| arch == arch_name) {
        println!("Unsuported architecture ({})!", arch_name);
        return;
    }

    // Set bfd_arch and bfd_mach from the architecture name
    let _ = bfd.set_arch_mach(arch_name);

    // Create a disassemble_info structure
    let mut info = match DisassembleInfo::new() {
        Ok(i) => i,
        Err(e) => {
            println!("{}", e);
            return;
        }
    };

    // Disassemble the buffer using an iterator
    for instruction in Instruction::from_buffer(&mut info, bfd, &buffer, offset) {
        println!("{}", instruction);
    }
}

fn main() {
    test_buffer_full("i386:x86-64", vec![0xc3, 0x90, 0x66, 0x90], 0xA00);

    test_buffer_compact(
        "mep",
        vec![
            0x53, 0x53, 0x08, 0xd8, 0x01, 0x00, 0x53, 0x53, 0x30, 0xeb, 0x5b, 0x00,
        ],
        0xC00000,
    );

    test_buffer_utils(
        "mep",
        vec![
            0x53, 0x53, 0x08, 0xd8, 0x01, 0x00, 0x53, 0x53, 0x30, 0xeb, 0x5b, 0x00,
        ],
        0xC00000,
    );

    test_buffer_iter(
        "mep",
        vec![
            0x53, 0x53, 0x08, 0xd8, 0x01, 0x00, 0x53, 0x53, 0x30, 0xeb, 0x5b, 0x00,
        ],
        0xC00000,
    );
}
<file_sep>// <NAME> <<EMAIL>>
// binutils - lib.rs

pub mod bfd;
pub mod helpers;
pub mod instruction;
pub mod mach;
pub mod opcodes;
pub mod section;
pub mod utils;

extern crate libc;

use std::fmt;

// Specific errors
#[derive(Debug)]
pub enum Error {
    BfdError(u32, String),
    DisassembleInfoError(String),
    SectionError(String),
    CommonError(String),
    NulError(String),
    Utf8Error(std::str::Utf8Error),
    NullPointerError(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::BfdError(tag, ref msg) => write!(f, "{} ({})", msg, tag),
            Error::DisassembleInfoError(ref msg) => write!(f, "{}", msg),
            Error::SectionError(ref section) => write!(f, "Can't find '{}' section!", section),
            Error::CommonError(ref msg) => write!(f, "{}", msg),
            Error::NulError(ref error) => write!(f, "{}", error),
            Error::Utf8Error(ref error) => write!(f, "{}", error),
            Error::NullPointerError(ref error) => write!(f, "{}", error),
        }
    }
}

// Needed to use the ? operator on Cstring::new()
impl From<std::ffi::NulError> for Error {
    fn from(error: std::ffi::NulError) -> Self {
        Error::NulError(format!("{}", error))
    }
}

// Needed to use the ? operator on Cstring::from_bytes_with_nul()
impl From<std::ffi::FromBytesWithNulError> for Error {
    fn from(error: std::ffi::FromBytesWithNulError) -> Self {
        Error::NulError(format!("{}", error))
    }
}

// Needed to use the ? operator on Cstr.to_str()
impl From<std::str::Utf8Error> for Error {
    fn from(error: std::str::Utf8Error) -> Self {
        Error::Utf8Error(error)
    }
}
