xref: /reactos/sdk/tools/rsym/raddr2line.c (revision c2c66aff)
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 
fixup_offset(size_t ImageBase,size_t offset)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
my_atoi(const char * a)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
find_rossym_section(PIMAGE_FILE_HEADER PEFileHeader,PIMAGE_SECTION_HEADER PESectionHeaders)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
find_and_print_offset(void * data,size_t offset)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
process_data(const void * FileData,size_t offset)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
process_file(const char * file_name,size_t offset)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 
main(int argc,const char ** argv)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