--- /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 xed-disas-pecoff.cpp
+/// @author Mark Charney <mark.charney@intel.com>
+
+//// ONLY COMPILES IF -mno-cygwin is thrown on to GCC compilations
+
+#include "xed-disas-pecoff.H"
+
+#if defined(XED_PECOFF_FILE_READER)
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+
+
+// windows specific headers
+#include <windows.h>
+#include <winnt.h>
+
+// xed headers -- THESE MUST BE AFTER THE WINDOWS HEADERS
+
+
+extern "C" {
+#include "xed-interface.h"
+#include "xed-examples-util.h"
+#include "xed-portability.h" // This really must be after the windows.h include
+}
+
+#include "xed-disas-pecoff.h"
+#include "xed-examples-ostreams.h"
+using namespace std;
+
+// Pronto
+static std::string
+windows_error(const char* syscall,
+ const char* filename)
+{
+ std::ostringstream os;
+ os << "Mapped file:: " << syscall
+ << " for file " << filename << " failed: ";
+ switch (GetLastError())
+ {
+ case 2:
+ os << "File not found";
+ break;
+ case 3:
+ os << "Path not found";
+ break;
+ case 5:
+ os << "Access denied";
+ break;
+ case 15:
+ os << "Invalid drive";
+ break;
+ default:
+ os << "error code " << STATIC_CAST(xed_uint32_t,GetLastError());
+ break;
+ }
+
+ return os.str();
+}
+
+class pecoff_reader_t
+{
+ /// NT handle for the open file.
+ void* file_handle_;
+
+ /// NT handle for the memory mapping.
+ void* map_handle_;
+
+ void* base_;
+ xed_bool_t okay_;
+ xed_bool_t sixty_four_bit_;
+
+ const IMAGE_SECTION_HEADER* hdr;
+ const IMAGE_SECTION_HEADER* orig_hdr;
+ unsigned int nsections;
+ xed_uint64_t image_base;
+
+
+public:
+ xed_uint32_t section_index;
+
+ pecoff_reader_t()
+ {
+ init();
+ }
+ ~pecoff_reader_t()
+ {
+ close();
+ }
+
+ void* base() const { return base_; }
+ xed_bool_t okay() const { return okay_; }
+ xed_bool_t sixty_four_bit() const { return sixty_four_bit_; }
+
+ void
+ init()
+ {
+ file_handle_ = INVALID_HANDLE_VALUE;
+ map_handle_ = INVALID_HANDLE_VALUE;
+ okay_ = false;
+ sixty_four_bit_ = false;
+
+ hdr=0;
+ orig_hdr=0;
+ nsections=0;
+ image_base=0;
+ section_index=0;
+ }
+
+ void
+ close()
+ {
+ if (base_)
+ {
+ UnmapViewOfFile(base_);
+ }
+ if (map_handle_ != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(map_handle_);
+ }
+ if (file_handle_ != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(file_handle_);
+ }
+
+ init();
+ }
+
+
+ xed_bool_t
+ map_region(const char* input_file_name,
+ void*& vregion,
+ xed_uint32_t& len)
+ {
+ std::string error_msg;
+ okay_ = false;
+
+ file_handle_ = CreateFile(input_file_name,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_NO_BUFFERING + FILE_ATTRIBUTE_READONLY,
+ NULL);
+ if (file_handle_ == INVALID_HANDLE_VALUE) {
+ error_msg = windows_error("CreateFile", input_file_name);
+ xedex_derror(error_msg.c_str());
+ }
+
+ map_handle_ = CreateFileMapping(file_handle_,
+ NULL,
+ PAGE_READONLY,
+ 0,
+ 0,
+ NULL);
+
+ if (map_handle_ == INVALID_HANDLE_VALUE) {
+ error_msg = windows_error("CreateFileMapping", input_file_name);
+ xedex_derror(error_msg.c_str());
+ }
+
+ base_ = MapViewOfFile(map_handle_,
+ FILE_MAP_READ, 0, 0, 0);
+ if (base_ != NULL) {
+ okay_ = true;
+ vregion = base_;
+ len = 0; //FIXME
+ return true;
+ }
+ error_msg = windows_error("MapViewOfFile", input_file_name);
+ CloseHandle(map_handle_);
+ map_handle_ = INVALID_HANDLE_VALUE;
+
+ CloseHandle(file_handle_);
+ file_handle_ = INVALID_HANDLE_VALUE;
+ return false;
+ }
+
+
+ xed_bool_t read_header() {
+ if (! parse_nt_file_header(&nsections, &image_base, &hdr)) {
+ xedex_derror("Could not read nt file header");
+ return false;
+ }
+
+ orig_hdr=hdr;
+ return true;
+ }
+ void print_section_headers() {
+ const IMAGE_SECTION_HEADER* jhdr = orig_hdr;
+ for (unsigned int j = 0; j < nsections; j++, jhdr++) {
+ cout << "# SECNAME " << j << " "
+ << reinterpret_cast<const char*>(jhdr->Name)
+ << endl;
+ }
+ }
+
+ xed_bool_t
+ module_section_info(
+ const char* secname,
+ xed_uint8_t*& section_start,
+ xed_uint32_t& section_size,
+ xed_uint64_t& virtual_addr)
+ {
+ unsigned int i,ii;
+
+ if (secname == 0)
+ secname = ".text";
+
+ // Extract the name into a 0-padded 8 byte string.
+ char my_name[IMAGE_SIZEOF_SHORT_NAME];
+ memset(my_name,0,IMAGE_SIZEOF_SHORT_NAME);
+ for( i=0;i<IMAGE_SIZEOF_SHORT_NAME;i++) {
+ my_name[i] = secname[i];
+ if (secname[i] == 0)
+ break;
+ }
+
+ // There are section names that LOOK like .text$x but they really have
+ // a null string embedded in them. So when you strcmp, you hit the
+ // null.
+
+ // match the substring that starts with the given target_section_name
+ unsigned int match_len = static_cast<unsigned int>(strlen(secname));
+ if (match_len > IMAGE_SIZEOF_SHORT_NAME)
+ match_len = IMAGE_SIZEOF_SHORT_NAME;
+
+ for ( ii = section_index; ii < nsections; ii++, hdr++) {
+ if (strncmp(reinterpret_cast<const char*>(hdr->Name), my_name,
+ match_len) == 0) {
+ // Found it. Extract the info and return.
+ virtual_addr = hdr->VirtualAddress + image_base;
+ section_size = (hdr->Misc.VirtualSize > 0 ?
+ hdr->Misc.VirtualSize
+ : hdr->SizeOfRawData);
+ section_start = (xed_uint8_t*)ptr_add(base_, hdr->PointerToRawData);
+ section_index = ii+1;
+ hdr++;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+private:
+ static inline const void*
+ ptr_add(const void* ptr, unsigned int n) {
+ return static_cast<const char*>(ptr)+n;
+ }
+
+ xed_bool_t
+ is_valid_module() {
+ // Point to the DOS header and check it.
+ const IMAGE_DOS_HEADER* dh = static_cast<const IMAGE_DOS_HEADER*>(base_);
+ if (dh->e_magic != IMAGE_DOS_SIGNATURE)
+ return false;
+
+ // Point to the PE signature word and check it.
+ const DWORD* sig = static_cast<const DWORD*>(ptr_add(base_, dh->e_lfanew));
+
+ // This must be a valid PE file with a valid DOS header.
+ if (*sig != IMAGE_NT_SIGNATURE)
+ return false;
+
+ return true;
+ }
+
+
+ xed_bool_t
+ parse_nt_file_header(unsigned int* pnsections,
+ xed_uint64_t* pimage_base,
+ const IMAGE_SECTION_HEADER** phdr)
+ {
+ // Oh joy - the format of a .obj file on Windows is *different*
+ // from the format of a .exe file. Deal with that.
+ const IMAGE_FILE_HEADER* ifh;
+
+ // Check the header to see if this is a valid .exe file
+ if (is_valid_module())
+ {
+ // Point to the DOS header.
+ const IMAGE_DOS_HEADER* dh = static_cast<const IMAGE_DOS_HEADER*>(base_);
+
+ // Point to the COFF File Header (just after the signature)
+ ifh = static_cast<const IMAGE_FILE_HEADER*>(ptr_add(base_, dh->e_lfanew + 4));
+ }
+ else
+ {
+ // Maybe this is a .obj file, which starts with the image file header
+ ifh = static_cast<const IMAGE_FILE_HEADER*>(base_);
+ }
+
+#if !defined(IMAGE_FILE_MACHINE_AMD64)
+# define IMAGE_FILE_MACHINE_AMD64 0x8664
+#endif
+
+ if (ifh->Machine == IMAGE_FILE_MACHINE_I386) {
+ cout << "# IA32 format" << endl;
+ sixty_four_bit_ = false;
+ }
+ else if (ifh->Machine == IMAGE_FILE_MACHINE_AMD64) {
+ cout << "# Intel64 format" << endl;
+ sixty_four_bit_ = true;
+ }
+ else {
+ // We only support Windows formats on IA32 and Intel64
+ return false;
+ }
+
+ *pimage_base = 0;
+
+ // Very important to use the 32b header here because the
+ // unqualified IMAGE_OPTIONAL_HEADER gets the wrong version on
+ // win64!
+ const IMAGE_OPTIONAL_HEADER32* opthdr32
+ = static_cast<const IMAGE_OPTIONAL_HEADER32*>(ptr_add(ifh, sizeof(*ifh)));
+
+ // Cygwin's w32api winnt.h header doesn't distinguish 32 and 64b.
+#if !defined(IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+# define IMAGE_NT_OPTIONAL_HDR32_MAGIC IMAGE_NT_OPTIONAL_HDR_MAGIC
+#endif
+ // And it lacks the definition for 64b headers
+#if !defined(IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+# define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+#endif
+
+ if (ifh->SizeOfOptionalHeader > 0)
+ {
+ if (opthdr32->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+ {
+ *pimage_base = opthdr32->ImageBase;
+ //cerr << hex << "IMAGE BASE 32b: " << *pimage_base << dec << endl;
+ }
+ else if (opthdr32->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ {
+#if defined(_MSC_VER)
+# if _MSC_VER >= 1400
+ const IMAGE_OPTIONAL_HEADER64* opthdr64 =
+ static_cast<const IMAGE_OPTIONAL_HEADER64*>(ptr_add(ifh, sizeof(*ifh)));
+ *pimage_base = opthdr64->ImageBase;
+ //cerr << hex << "IMAGE BASE 64b: " << *pimage_base << dec << endl;
+# else
+ xedex_derror("No support for 64b optional headers because older MS compilers do not have the type yet");
+# endif
+#else
+ xedex_derror("No support for 64b optional headers because cygwin does nt have the type yet");
+ return false;
+#endif
+ }
+ else
+ {
+ // Optional header is not a form we recognize, so punt.
+ return false;
+ }
+ }
+
+ // Point to the first of the Section Headers
+ *phdr = static_cast<const IMAGE_SECTION_HEADER*>(ptr_add(opthdr32,
+ ifh->SizeOfOptionalHeader));
+ *pnsections = ifh->NumberOfSections;
+ return true;
+ }
+
+
+
+};
+
+////////////////////////////////////////////////////////////////////////////
+
+
+
+void
+process_pecoff(xed_uint8_t* start,
+ unsigned int length,
+ xed_decode_file_info_t& decode_info,
+ pecoff_reader_t& reader,
+ const char* target_section)
+{
+ xed_uint8_t* section_start = 0;
+ xed_uint32_t section_size = 0;
+ xed_uint64_t runtime_vaddr = 0;
+
+ xed_bool_t okay = true;
+ xed_bool_t found = false;
+ while(okay) {
+ okay = reader.module_section_info(target_section,
+ section_start,
+ section_size,
+ runtime_vaddr);
+ if (okay) {
+ printf ("# SECTION %d\n", reader.section_index-1);
+ found = true;
+ xed_disas_test(&decode_info.dstate,
+ REINTERPRET_CAST(unsigned char*,start),
+ REINTERPRET_CAST(unsigned char*,section_start),
+ REINTERPRET_CAST(unsigned char*,section_start + section_size),
+ decode_info.ninst,
+ runtime_vaddr,
+ decode_info.decode_only,0);
+ }
+ }
+ if (!found)
+ xedex_derror("text section not found");
+ (void) length;
+}
+
+void
+xed_disas_pecoff(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)
+{
+ xed_uint8_t* region = 0;
+ void* vregion = 0;
+ xed_uint32_t len = 0;
+ pecoff_reader_t image_reader;
+ xed_bool_t okay = image_reader.map_region(input_file_name, vregion, len);
+ if (!okay)
+ xedex_derror("image read failed");
+ if (CLIENT_VERBOSE1)
+ printf("Mapped image\n");
+ image_reader.read_header();
+ region = REINTERPRET_CAST(xed_uint8_t*,vregion);
+
+ xed_state_t local_dstate = *dstate;
+ if (image_reader.sixty_four_bit() && 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;
+ }
+
+ xed_decode_file_info_t decode_info;
+ xed_decode_file_info_init(&decode_info, &local_dstate, ninst, decode_only);
+ process_pecoff(region, len, decode_info, image_reader, target_section);
+ xed_print_decode_stats();
+}
+
+
+
+#endif
+//Local Variables:
+//pref: "xed-disas-pecoff.H"
+//End: