1 /* 2 * Usage: raddr2line input-file address/offset 3 * 4 * This is a tool and is compiled using the host compiler, 5 * i.e. on Linux gcc and not mingw-gcc (cross-compiler). 6 * Therefore we can't include SDK headers and we have to 7 * duplicate some definitions here. 8 * Also note that the internal functions are "old C-style", 9 * returning an int, where a return of 0 means success and 10 * non-zero is failure. 11 */ 12 13 #include <stdio.h> 14 #include <string.h> 15 #include <stdlib.h> 16 17 #include "rsym.h" 18 19 /* Assume if an offset > ABS_TRESHOLD, then it must be absolute */ 20 #define ABS_TRESHOLD 0x00400000L 21 22 size_t fixup_offset ( size_t ImageBase, size_t offset ) 23 { 24 if (offset > ABS_TRESHOLD) 25 offset -= ImageBase; 26 27 return offset; 28 } 29 30 long 31 my_atoi ( const char* a ) 32 { 33 int i = 0; 34 const char* fmt = "%x"; 35 36 if ( *a == '0' ) 37 { 38 switch ( *++a ) 39 { 40 case 'x': 41 fmt = "%x"; 42 ++a; 43 break; 44 case 'd': 45 fmt = "%d"; 46 ++a; 47 break; 48 default: 49 fmt = "%o"; 50 break; 51 } 52 } 53 sscanf ( a, fmt, &i ); 54 return i; 55 } 56 57 PIMAGE_SECTION_HEADER 58 find_rossym_section ( PIMAGE_FILE_HEADER PEFileHeader, 59 PIMAGE_SECTION_HEADER PESectionHeaders ) 60 { 61 size_t i; 62 for ( i = 0; i < PEFileHeader->NumberOfSections; i++ ) 63 { 64 if ( 0 == strcmp ( (char*)PESectionHeaders[i].Name, ".rossym" ) ) 65 return &PESectionHeaders[i]; 66 } 67 return NULL; 68 } 69 70 int 71 find_and_print_offset ( 72 void* data, 73 size_t offset ) 74 { 75 PSYMBOLFILE_HEADER RosSymHeader = (PSYMBOLFILE_HEADER)data; 76 PROSSYM_ENTRY Entries = (PROSSYM_ENTRY)((char*)data + RosSymHeader->SymbolsOffset); 77 char* Strings = (char*)data + RosSymHeader->StringsOffset; 78 size_t symbols = RosSymHeader->SymbolsLength / sizeof(ROSSYM_ENTRY); 79 size_t i; 80 81 //if ( RosSymHeader->SymbolsOffset ) 82 83 for ( i = 0; i < symbols; i++ ) 84 { 85 if ( Entries[i].Address > offset ) 86 { 87 if ( !i-- ) 88 return 1; 89 else 90 { 91 PROSSYM_ENTRY e = &Entries[i]; 92 printf ( "%s:%u (%s)\n", 93 &Strings[e->FileOffset], 94 (unsigned int)e->SourceLine, 95 &Strings[e->FunctionOffset] ); 96 return 0; 97 } 98 } 99 } 100 return 1; 101 } 102 103 int 104 process_data ( const void* FileData, size_t offset ) 105 { 106 PIMAGE_DOS_HEADER PEDosHeader; 107 PIMAGE_FILE_HEADER PEFileHeader; 108 PIMAGE_OPTIONAL_HEADER PEOptHeader; 109 PIMAGE_SECTION_HEADER PESectionHeaders; 110 PIMAGE_SECTION_HEADER PERosSymSectionHeader; 111 size_t ImageBase; 112 int res; 113 114 /* Check if MZ header exists */ 115 PEDosHeader = (PIMAGE_DOS_HEADER)FileData; 116 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC || PEDosHeader->e_lfanew == 0L) 117 { 118 perror("Input file is not a PE image.\n"); 119 return 1; 120 } 121 122 /* Locate PE file header */ 123 /* sizeof(ULONG) = sizeof(MAGIC) */ 124 PEFileHeader = (PIMAGE_FILE_HEADER)((char *)FileData + PEDosHeader->e_lfanew + sizeof(ULONG)); 125 126 /* Locate optional header */ 127 PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1); 128 ImageBase = PEOptHeader->ImageBase; 129 130 /* Locate PE section headers */ 131 PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *) PEOptHeader + PEFileHeader->SizeOfOptionalHeader); 132 133 /* make sure offset is what we want */ 134 offset = fixup_offset ( ImageBase, offset ); 135 136 /* find rossym section */ 137 PERosSymSectionHeader = find_rossym_section ( 138 PEFileHeader, PESectionHeaders ); 139 if ( !PERosSymSectionHeader ) 140 { 141 fprintf ( stderr, "Couldn't find rossym section in executable\n" ); 142 return 1; 143 } 144 res = find_and_print_offset ( (char*)FileData + PERosSymSectionHeader->PointerToRawData, 145 offset ); 146 if ( res ) 147 printf ( "??:0\n" ); 148 return res; 149 } 150 151 int 152 process_file ( const char* file_name, size_t offset ) 153 { 154 void* FileData; 155 size_t FileSize; 156 int res = 1; 157 158 FileData = load_file ( file_name, &FileSize ); 159 if ( !FileData ) 160 { 161 fprintf ( stderr, "An error occured loading '%s'\n", file_name ); 162 } 163 else 164 { 165 res = process_data ( FileData, offset ); 166 free ( FileData ); 167 } 168 169 return res; 170 } 171 172 int main ( int argc, const char** argv ) 173 { 174 char* path; 175 size_t offset; 176 int res; 177 178 if ( argc != 3 ) 179 { 180 fprintf(stderr, "Usage: raddr2line <exefile> <offset>\n"); 181 exit(1); 182 } 183 184 path = convert_path ( argv[1] ); 185 offset = my_atoi ( argv[2] ); 186 187 res = process_file ( path, offset ); 188 189 free ( path ); 190 191 return res; 192 } 193