raddr2line utility
[reactos.git] / reactos / tools / raddr2line.c
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 size_t fixup_offset ( size_t ImageBase, size_t offset )
20 {
21 if ( offset >= ImageBase )
22 offset -= ImageBase;
23 return offset;
24 }
25
26 long
27 my_atoi ( const char* a )
28 {
29 int i = 0;
30 const char* fmt = "%x";
31
32 if ( *a == '0' )
33 {
34 switch ( *++a )
35 {
36 case 'x':
37 fmt = "%x";
38 ++a;
39 break;
40 case 'd':
41 fmt = "%d";
42 ++a;
43 break;
44 default:
45 fmt = "%o";
46 break;
47 }
48 }
49 sscanf ( a, fmt, &i );
50 return i;
51 }
52
53 PIMAGE_SECTION_HEADER
54 find_rossym_section ( PIMAGE_FILE_HEADER PEFileHeader,
55 PIMAGE_SECTION_HEADER PESectionHeaders )
56 {
57 size_t i;
58 for ( i = 0; i < PEFileHeader->NumberOfSections; i++ )
59 {
60 if ( 0 == strcmp ( PESectionHeaders[i].Name, ".rossym" ) )
61 return &PESectionHeaders[i];
62 }
63 return NULL;
64 }
65
66 int
67 find_and_print_offset (
68 void* data,
69 size_t offset )
70 {
71 PSYMBOLFILE_HEADER RosSymHeader = (PSYMBOLFILE_HEADER)data;
72 PROSSYM_ENTRY Entries = (PROSSYM_ENTRY)((char*)data + RosSymHeader->SymbolsOffset);
73 char* Strings = (char*)data + RosSymHeader->StringsOffset;
74 size_t symbols = RosSymHeader->SymbolsLength / sizeof(ROSSYM_ENTRY);
75 size_t i;
76
77 //if ( RosSymHeader->SymbolsOffset )
78
79 for ( i = 0; i < symbols; i++ )
80 {
81 if ( Entries[i].Address > offset )
82 {
83 if ( !i-- )
84 return 1;
85 else
86 {
87 PROSSYM_ENTRY e = &Entries[i];
88 printf ( "%s:%lu (%s)",
89 &Strings[e->FileOffset],
90 e->SourceLine,
91 &Strings[e->FunctionOffset] );
92 return 0;
93 }
94 }
95 }
96 return 1;
97 }
98
99 int
100 process_data ( const void* FileData, size_t FileSize, size_t offset )
101 {
102 PIMAGE_DOS_HEADER PEDosHeader;
103 PIMAGE_FILE_HEADER PEFileHeader;
104 PIMAGE_OPTIONAL_HEADER PEOptHeader;
105 PIMAGE_SECTION_HEADER PESectionHeaders;
106 PIMAGE_SECTION_HEADER PERosSymSectionHeader;
107 size_t ImageBase;
108 int res;
109
110 /* Check if MZ header exists */
111 PEDosHeader = (PIMAGE_DOS_HEADER)FileData;
112 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC || PEDosHeader->e_lfanew == 0L)
113 {
114 perror("Input file is not a PE image.\n");
115 return 1;
116 }
117
118 /* Locate PE file header */
119 /* sizeof(ULONG) = sizeof(MAGIC) */
120 PEFileHeader = (PIMAGE_FILE_HEADER)((char *)FileData + PEDosHeader->e_lfanew + sizeof(ULONG));
121
122 /* Locate optional header */
123 PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
124 ImageBase = PEOptHeader->ImageBase;
125
126 /* Locate PE section headers */
127 PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *) PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
128
129 /* make sure offset is what we want */
130 offset = fixup_offset ( ImageBase, offset );
131
132 /* find rossym section */
133 PERosSymSectionHeader = find_rossym_section (
134 PEFileHeader, PESectionHeaders );
135 if ( !PERosSymSectionHeader )
136 {
137 fprintf ( stderr, "Couldn't find rossym section in executable\n" );
138 return 1;
139 }
140 res = find_and_print_offset ( (char*)FileData + PERosSymSectionHeader->PointerToRawData,
141 offset );
142 if ( res )
143 printf ( "??:0\n" );
144 return res;
145 }
146
147 int
148 process_file ( const char* file_name, size_t offset )
149 {
150 void* FileData;
151 size_t FileSize;
152 int res = 1;
153
154 FileData = load_file ( file_name, &FileSize );
155 if ( !FileData )
156 {
157 fprintf ( stderr, "An error occured loading '%s'\n", file_name );
158 }
159 else
160 {
161 res = process_data ( FileData, FileSize, offset );
162 free ( FileData );
163 }
164
165 return res;
166 }
167
168 int main ( int argc, const char** argv )
169 {
170 char* path;
171 size_t offset;
172 int res;
173
174 if ( argc != 3 )
175 {
176 fprintf(stderr, "Usage: raddr2line <exefile> <offset>\n");
177 exit(1);
178 }
179
180 path = convert_path ( argv[1] );
181 offset = my_atoi ( argv[2] );
182
183 res = process_file ( path, offset );
184
185 free ( path );
186
187 return res;
188 }