--- /dev/null
+/*BEGIN_LEGAL
+Intel Open Source License
+
+Copyright (c) 2002-2007 Intel Corporation
+All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer. Redistributions
+in binary form must reproduce the above copyright notice, this list of
+conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution. Neither the name of
+the Intel Corporation nor the names of its contributors may be used to
+endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+END_LEGAL */
+/// @file disas-elf.cpp
+/// @author Mark Charney <mark.charney@intel.com>
+
+#include "xed-disas-elf.H"
+
+#if defined(XED_ELF_READER)
+
+////////////////////////////////////////////////////////////////////////////
+#include <elf.h>
+
+extern "C" {
+#include "xed-interface.h"
+#include "xed-portability.h"
+#include "xed-examples-util.h"
+}
+
+#include <string.h>
+#include <stdlib.h>
+#include <iostream>
+#include <iomanip>
+#include <map>
+using namespace std;
+////////////////////////////////////////////////////////////////////////////
+
+
+char*
+lookup32(Elf32_Word stoffset,
+ void* start,
+ Elf32_Off offset)
+{
+ char* p = (char*)start + offset;
+ char* q = p + stoffset;
+ // int i;
+ //cout << "p = " << (unsigned int) p << endl;
+ //cout << "q = " << (unsigned int) q << endl;
+ //for(i=0;i<20;i++)
+ //{
+ // cout << q[i];
+ //}
+ //cout << endl;
+ return q;
+}
+
+char*
+lookup64(Elf64_Word stoffset,
+ void* start,
+ Elf64_Off offset)
+{
+ char* p = (char*)start + offset;
+ char* q = p + stoffset;
+ //int i;
+ //cout << "p = " << (unsigned int) p << endl;
+ //cout << "q = " << (unsigned int) q << endl;
+ //for( i=0;i<20;i++)
+ //{
+ // cout << q[i];
+ //}
+ //cout << endl;
+ return q;
+}
+
+#include <vector>
+void make_symbol_vector(map<xed_uint64_t,char*>* sym_map,
+ vector<xed_uint64_t>* sym_vec)
+{
+ map<xed_uint64_t,char*>::iterator i = sym_map->begin();
+ for( ; i != sym_map->end() ;i ++) {
+ sym_vec->push_back(i->first);
+ }
+ sort(sym_vec->begin(), sym_vec->end());
+}
+
+
+#include <algorithm>
+uint64_t find_symbol_address(vector<xed_uint64_t>* sym_vec, xed_uint64_t tgt)
+{
+ vector<xed_uint64_t>::iterator i = lower_bound(sym_vec->begin(), sym_vec->end(), tgt);
+ if (i == sym_vec->end())
+ return 0;
+ if (*i > tgt) {
+ // take previous value
+ if (i != sym_vec->begin())
+ return *(i-1);
+ }
+ if (*i == tgt) {
+ return *i;
+ }
+ return 0;
+
+}
+
+static vector<xed_uint64_t>* global_sym_vec=0;
+uint64_t find_symbol_address_global(xed_uint64_t tgt)
+{
+ return find_symbol_address(global_sym_vec, tgt);
+}
+
+static map<xed_uint64_t,char*>* global_sym_map;
+char* get_symbol(xed_uint64_t a) {
+ map<xed_uint64_t,char*>::iterator i = global_sym_map->find(a);
+ if (i != global_sym_map->end()) {
+ return i->second;
+ }
+ return 0;
+}
+
+
+int xed_disassembly_callback_function(
+ uint64_t address,
+ char* symbol_buffer,
+ uint32_t buffer_length,
+ uint64_t* offset,
+ void* caller_data)
+{
+ (void)caller_data; /* not used */
+ uint64_t symbol_address = find_symbol_address_global(address);
+ if (symbol_address) {
+ char* symbol = get_symbol(symbol_address);
+ if (symbol) {
+ if (xed_strlen(symbol) < buffer_length)
+ xed_strncpy(symbol_buffer, symbol, buffer_length);
+ else {
+ xed_strncpy(symbol_buffer, symbol, buffer_length-1);
+ symbol_buffer[buffer_length-1]=0;
+ }
+ *offset = address - symbol_address;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void xed_disas_elf_init() {
+ xed_register_disassembly_callback(xed_disassembly_callback_function);
+}
+
+
+
+void
+disas_test32(const xed_state_t* dstate,
+ void* start,
+ Elf32_Off offset,
+ Elf32_Word size,
+ int ninst,
+ Elf32_Addr runtime_vaddr,
+ bool decode_only,
+ map<xed_uint64_t,char*>& sym_map,
+ vector<xed_uint64_t>& sym_vec)
+{
+ unsigned char* s = (unsigned char*)start;
+ unsigned char* a = (unsigned char*)start + offset;
+ unsigned char* q = a + size; // end of region
+
+ // pass in a function to retreive valid symbol names
+ global_sym_map = & sym_map;
+ global_sym_vec = & sym_vec;
+ xed_disas_test(dstate, s,a,q, ninst, runtime_vaddr, decode_only,get_symbol);
+}
+
+void
+disas_test64(const xed_state_t* dstate,
+ void* start,
+ Elf64_Off offset,
+ Elf64_Word size,
+ int ninst,
+ Elf64_Addr runtime_vaddr,
+ bool decode_only,
+ map<xed_uint64_t,char*>& sym_map,
+ vector<xed_uint64_t>& sym_vec)
+{
+ unsigned char* s = (unsigned char*)start;
+ unsigned char* a = (unsigned char*)start + offset;
+ unsigned char* q = a + size; // end of region
+
+ // pass in a function to retreive valid symbol names
+ global_sym_map = & sym_map;
+ global_sym_vec = & sym_vec;
+ xed_disas_test(dstate, s,a,q, ninst, runtime_vaddr, decode_only,get_symbol);
+}
+
+
+void
+process_elf32(void* start,
+ unsigned int length,
+ const char* tgt_section,
+ const xed_state_t* dstate,
+ int ninst,
+ xed_bool_t decode_only,
+ map<xed_uint64_t,char*>& sym_map,
+ vector<xed_uint64_t>& sym_vec)
+{
+ Elf32_Ehdr* elf_hdr = (Elf32_Ehdr*) start;
+ if (elf_hdr->e_machine != EM_386) {
+ cerr << "Not an IA32 binary. Consider using the -64 switch" << endl;
+ exit(1);
+ }
+
+ Elf32_Off shoff = elf_hdr->e_shoff; // section hdr table offset
+ Elf32_Shdr* shp = (Elf32_Shdr*) ((char*)start + shoff);
+ int sect_strings = elf_hdr->e_shstrndx;
+ //cout << "String section " << sect_strings << endl;
+ int nsect = elf_hdr->e_shnum;
+ int i;
+ for(i=0;i<nsect;i++) {
+ char* name = lookup32(shp[i].sh_name, start, shp[sect_strings].sh_offset);
+ xed_bool_t text = false;
+ if (shp[i].sh_type == SHT_PROGBITS) {
+ if (tgt_section) {
+ if (strcmp(tgt_section, name)==0)
+ text = true;
+ }
+ else if (shp[i].sh_flags & SHF_EXECINSTR)
+ text = true;
+ }
+
+ if (text) {
+ printf("# SECTION " XED_FMT_D " ", i);
+ printf("%25s ", name);
+ printf("addr " XED_FMT_LX " ",static_cast<xed_uint64_t>(shp[i].sh_addr));
+ printf("offset " XED_FMT_LX " ",static_cast<xed_uint64_t>(shp[i].sh_offset));
+ printf("size " XED_FMT_LU " ", static_cast<xed_uint64_t>(shp[i].sh_size));
+ printf("type " XED_FMT_LU "\n", static_cast<xed_uint64_t>(shp[i].sh_type));
+
+ disas_test32(dstate,
+ start, shp[i].sh_offset, shp[i].sh_size,
+ ninst,
+ shp[i].sh_addr,
+ decode_only,
+ sym_map,
+ sym_vec);
+ }
+
+ }
+
+ (void) length;// pacify compiler
+}
+
+void
+process_elf64(void* start,
+ unsigned int length,
+ const char* tgt_section,
+ const xed_state_t* dstate,
+ int ninst,
+ xed_bool_t decode_only,
+ map<xed_uint64_t,char*>& sym_map,
+ vector<xed_uint64_t>& sym_vec)
+{
+ Elf64_Ehdr* elf_hdr = (Elf64_Ehdr*) start;
+ if (elf_hdr->e_machine != EM_X86_64) {
+ cerr << "Not an x86-64 binary. Consider not using the -64 switch." << endl;
+ exit(1);
+ }
+
+ Elf64_Off shoff = elf_hdr->e_shoff; // section hdr table offset
+ Elf64_Shdr* shp = (Elf64_Shdr*) ((char*)start + shoff);
+ Elf64_Half sect_strings = elf_hdr->e_shstrndx;
+ //cout << "String section " << sect_strings << endl;
+ Elf64_Half nsect = elf_hdr->e_shnum;
+ if (CLIENT_VERBOSE1)
+ printf("# sections %d\n" , nsect);
+ unsigned int i;
+ xed_bool_t text = false;
+ for( i=0;i<nsect;i++) {
+ char* name = lookup64(shp[i].sh_name, start, shp[sect_strings].sh_offset);
+
+ text = false;
+ if (shp[i].sh_type == SHT_PROGBITS) {
+ if (tgt_section) {
+ if (strcmp(tgt_section, name)==0)
+ text = true;
+ }
+ else if (shp[i].sh_flags & SHF_EXECINSTR)
+ text = true;
+ }
+
+ if (text) {
+ printf("# SECTION " XED_FMT_U " ", i);
+ printf("%25s ", name);
+ printf("addr " XED_FMT_LX " ",static_cast<xed_uint64_t>(shp[i].sh_addr));
+ printf("offset " XED_FMT_LX " ",static_cast<xed_uint64_t>(shp[i].sh_offset));
+ printf("size " XED_FMT_LU "\n", static_cast<xed_uint64_t>(shp[i].sh_size));
+ disas_test64(dstate,
+ start, shp[i].sh_offset, shp[i].sh_size,
+ ninst,
+ shp[i].sh_addr, decode_only, sym_map, sym_vec);
+
+ }
+ }
+ (void) length;// pacify compiler
+}
+
+
+void read_symbols64(void* start,
+ Elf64_Off offset,
+ Elf64_Word size,
+ Elf64_Off string_table_offset,
+ map<xed_uint64_t,char*>& sym_map) {
+ char* a = static_cast<char*>(start);
+ Elf64_Sym* p = reinterpret_cast<Elf64_Sym*>(a + offset);
+ Elf64_Sym* q = reinterpret_cast<Elf64_Sym*>(a + offset + size);
+ int i = 0;
+ while(p<q) {
+ char* name = lookup64(p->st_name, start, string_table_offset);
+/*
+ cout << "SYM " << setw(3) << i << " "
+ << hex << setw(16)
+ << p->st_value << dec
+ << " " << name << endl;
+*/
+ if (xed_strlen(name) > 0)
+ sym_map[static_cast<xed_uint64_t>(p->st_value)] = name;
+ p++;
+ i++;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+
+int check_binary_32b(void* start) {
+ Elf32_Ehdr* elf_hdr = (Elf32_Ehdr*) start;
+ if (elf_hdr->e_machine == EM_386)
+ return 1;
+ return 0;
+}
+
+int check_binary_64b(void* start) {
+ Elf64_Ehdr* elf_hdr = (Elf64_Ehdr*) start;
+ if (elf_hdr->e_machine == EM_X86_64)
+ return 1;
+ return 0;
+}
+/*-----------------------------------------------------------------*/
+
+
+void symbols_elf64(void* start, map<xed_uint64_t,char*>& sym_map) {
+ Elf64_Ehdr* elf_hdr = (Elf64_Ehdr*) start;
+ if (elf_hdr->e_machine != EM_X86_64) {
+ cerr << "Not an x86-64 binary. Consider not using the -64 switch." << endl;
+ exit(1);
+ }
+
+ Elf64_Off shoff = elf_hdr->e_shoff; // section hdr table offset
+ Elf64_Shdr* shp = (Elf64_Shdr*) ((char*)start + shoff);
+ Elf64_Half nsect = elf_hdr->e_shnum;
+ if (CLIENT_VERBOSE1)
+ printf("# sections %d\n" , nsect);
+ unsigned int i;
+ Elf64_Half sect_strings = elf_hdr->e_shstrndx;
+ Elf64_Off string_table_offset=0;
+ Elf64_Off dynamic_string_table_offset=0;
+ for( i=0;i<nsect;i++) {
+ if (shp[i].sh_type == SHT_STRTAB) {
+ char* name = lookup32(shp[i].sh_name, start, shp[sect_strings].sh_offset);
+ if (strcmp(name,".strtab")==0) {
+ cout << "# Found strtab: " << i
+ << " offset " <<shp[i].sh_offset
+ << " size " << shp[i].sh_size
+ << endl;
+ string_table_offset = shp[i].sh_offset;
+ }
+ if (strcmp(name,".dynstr")==0) {
+ cout << "# Found dynamic strtab: " << i
+ << " offset " <<shp[i].sh_offset
+ << " size " << shp[i].sh_size
+ << endl;
+ dynamic_string_table_offset = shp[i].sh_offset;
+ }
+ }
+ }
+
+ for( i=0;i<nsect;i++) {
+ if (shp[i].sh_type == SHT_SYMTAB) {
+ cout << "# Found symtab: " << i
+ << " offset " <<shp[i].sh_offset
+ << " size " << shp[i].sh_size
+ << endl;
+ read_symbols64(start,shp[i].sh_offset, shp[i].sh_size, string_table_offset,sym_map);
+ }
+ else if (shp[i].sh_type == SHT_DYNSYM) {
+ cout << "# Found dynamic symtab: " << i
+ << " offset " <<shp[i].sh_offset
+ << " size " << shp[i].sh_size
+ << endl;
+ read_symbols64(start,shp[i].sh_offset, shp[i].sh_size, dynamic_string_table_offset, sym_map);
+ }
+ }
+}
+
+
+
+void read_symbols32(void* start,
+ Elf32_Off offset,
+ Elf32_Word size,
+ Elf32_Off string_table_offset,
+ map<xed_uint64_t,char*>& sym_map) {
+ char* a = static_cast<char*>(start);
+ Elf32_Sym* p = reinterpret_cast<Elf32_Sym*>(a + offset);
+ Elf32_Sym* q = reinterpret_cast<Elf32_Sym*>(a + offset + size);
+ int i = 0;
+ while(p<q) {
+ char* name = lookup32(p->st_name, start, string_table_offset);
+/*
+ cout << "SYM " << setw(3) << i << " "
+ << hex << setw(16)
+ << p->st_value << dec
+ << " " << name << endl;
+*/
+ if (xed_strlen(name) > 0)
+ sym_map[static_cast<xed_uint64_t>(p->st_value)] = name;
+ p++;
+ i++;
+ }
+}
+
+
+void symbols_elf32(void* start, map<xed_uint64_t,char*>& sym_map) {
+ Elf32_Ehdr* elf_hdr = (Elf32_Ehdr*) start;
+ if (elf_hdr->e_machine != EM_386) {
+ cerr << "Not an IA32 binary. Consider using the -64 switch" << endl;
+ exit(1);
+ }
+
+ Elf32_Off shoff = elf_hdr->e_shoff; // section hdr table offset
+ Elf32_Shdr* shp = (Elf32_Shdr*) ((char*)start + shoff);
+ Elf32_Half nsect = elf_hdr->e_shnum;
+ if (CLIENT_VERBOSE1)
+ printf("# sections %d\n" , nsect);
+ unsigned int i;
+ Elf32_Off string_table_offset=0;
+ Elf32_Off dynamic_string_table_offset=0;
+ int sect_strings = elf_hdr->e_shstrndx;
+
+ for( i=0;i<nsect;i++) {
+
+ if (shp[i].sh_type == SHT_STRTAB) {
+ char* name = lookup32(shp[i].sh_name, start, shp[sect_strings].sh_offset);
+ if (strcmp(name,".strtab")==0) {
+ cout << "# Found strtab: " << i
+ << " offset " <<shp[i].sh_offset
+ << " size " << shp[i].sh_size
+ << endl;
+ string_table_offset = shp[i].sh_offset;
+ }
+ if (strcmp(name,".dynstr")==0) {
+ cout << "# Found dynamic strtab: " << i
+ << " offset " <<shp[i].sh_offset
+ << " size " << shp[i].sh_size
+ << endl;
+ dynamic_string_table_offset = shp[i].sh_offset;
+ }
+ }
+ }
+
+ for( i=0;i<nsect;i++) {
+
+ if (shp[i].sh_type == SHT_SYMTAB) {
+ cout << "# Found symtab: " << i
+ << " offset " <<shp[i].sh_offset
+ << " size " << shp[i].sh_size
+ << endl;
+ read_symbols32(start,shp[i].sh_offset, shp[i].sh_size, string_table_offset,sym_map);
+ }
+ else if (shp[i].sh_type == SHT_DYNSYM) {
+ cout << "# Found dynamic symtab: " << i
+ << " offset " <<shp[i].sh_offset
+ << " size " << shp[i].sh_size
+ << endl;
+ read_symbols32(start,shp[i].sh_offset, shp[i].sh_size, dynamic_string_table_offset, sym_map);
+ }
+ }
+}
+
+
+
+
+void
+xed_disas_elf(const char* input_file_name,
+ const xed_state_t* dstate,
+ int ninst,
+ xed_bool_t sixty_four_bit,
+ xed_bool_t decode_only,
+ const char* target_section)
+{
+
+ void* region = 0;
+ unsigned int len = 0;
+ xed_disas_elf_init();
+ xed_map_region(input_file_name, ®ion, &len);
+
+
+ map<xed_uint64_t,char*> sym_map;
+ vector<xed_uint64_t> sym_vec;
+
+ if (check_binary_64b(region)) {
+ xed_state_t local_dstate = *dstate;
+ if (sixty_four_bit == 0) {
+ /* modify the default dstate values because we were not expecting a
+ * 64b binary */
+ local_dstate.mmode = XED_MACHINE_MODE_LONG_64;
+ local_dstate.addr_width = XED_ADDRESS_WIDTH_64b;
+ }
+
+ symbols_elf64(region, sym_map);
+ make_symbol_vector(&sym_map, &sym_vec);
+ process_elf64(region, len, target_section, &local_dstate, ninst, decode_only, sym_map,sym_vec);
+ }
+ else if (check_binary_32b(region)) {
+ symbols_elf32(region, sym_map);
+ make_symbol_vector(&sym_map, &sym_vec);
+ process_elf32(region, len, target_section, dstate, ninst, decode_only,sym_map, sym_vec);
+ }
+ else {
+ cerr << "Not a recognized 32b or 64b ELF binary." << endl;
+ exit(1);
+ }
+ xed_print_decode_stats();
+
+}
+
+
+
+#endif
+////////////////////////////////////////////////////////////////////////////