RSYM: force all sym files to have 0-based function offsets.
[reactos.git] / reactos / tools / rsym.c
1 /*
2 * Usage: rsym input-file output-file
3 */
4 #include <stdio.h>
5 #include <string.h>
6 #include <stdlib.h>
7
8 #define IMAGE_DOS_MAGIC 0x5a4d
9 #define IMAGE_PE_MAGIC 0x00004550
10
11 #define IMAGE_SIZEOF_SHORT_NAME 8
12
13 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
14
15 typedef void* PVOID;
16 typedef unsigned char BYTE;
17 typedef unsigned short WORD;
18 typedef unsigned long DWORD;
19 typedef signed long LONG;
20 typedef unsigned long ULONG;
21
22 #pragma pack(push,2)
23 typedef struct _IMAGE_DOS_HEADER {
24 WORD e_magic;
25 WORD e_cblp;
26 WORD e_cp;
27 WORD e_crlc;
28 WORD e_cparhdr;
29 WORD e_minalloc;
30 WORD e_maxalloc;
31 WORD e_ss;
32 WORD e_sp;
33 WORD e_csum;
34 WORD e_ip;
35 WORD e_cs;
36 WORD e_lfarlc;
37 WORD e_ovno;
38 WORD e_res[4];
39 WORD e_oemid;
40 WORD e_oeminfo;
41 WORD e_res2[10];
42 LONG e_lfanew;
43 } IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;
44 #pragma pack(pop)
45 #pragma pack(push,4)
46 typedef struct _IMAGE_DATA_DIRECTORY {
47 DWORD VirtualAddress;
48 DWORD Size;
49 } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
50 typedef struct _IMAGE_OPTIONAL_HEADER {
51 WORD Magic;
52 BYTE MajorLinkerVersion;
53 BYTE MinorLinkerVersion;
54 DWORD SizeOfCode;
55 DWORD SizeOfInitializedData;
56 DWORD SizeOfUninitializedData;
57 DWORD AddressOfEntryPoint;
58 DWORD BaseOfCode;
59 DWORD BaseOfData;
60 DWORD ImageBase;
61 DWORD SectionAlignment;
62 DWORD FileAlignment;
63 WORD MajorOperatingSystemVersion;
64 WORD MinorOperatingSystemVersion;
65 WORD MajorImageVersion;
66 WORD MinorImageVersion;
67 WORD MajorSubsystemVersion;
68 WORD MinorSubsystemVersion;
69 DWORD Reserved1;
70 DWORD SizeOfImage;
71 DWORD SizeOfHeaders;
72 DWORD CheckSum;
73 WORD Subsystem;
74 WORD DllCharacteristics;
75 DWORD SizeOfStackReserve;
76 DWORD SizeOfStackCommit;
77 DWORD SizeOfHeapReserve;
78 DWORD SizeOfHeapCommit;
79 DWORD LoaderFlags;
80 DWORD NumberOfRvaAndSizes;
81 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
82 } IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER;
83 typedef struct _IMAGE_FILE_HEADER {
84 WORD Machine;
85 WORD NumberOfSections;
86 DWORD TimeDateStamp;
87 DWORD PointerToSymbolTable;
88 DWORD NumberOfSymbols;
89 WORD SizeOfOptionalHeader;
90 WORD Characteristics;
91 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
92 typedef struct _IMAGE_SECTION_HEADER {
93 BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
94 union {
95 DWORD PhysicalAddress;
96 DWORD VirtualSize;
97 } Misc;
98 DWORD VirtualAddress;
99 DWORD SizeOfRawData;
100 DWORD PointerToRawData;
101 DWORD PointerToRelocations;
102 DWORD PointerToLinenumbers;
103 WORD NumberOfRelocations;
104 WORD NumberOfLinenumbers;
105 DWORD Characteristics;
106 } IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;
107 #pragma pack(pop)
108
109 typedef struct _SYMBOLFILE_HEADER {
110 unsigned long StabsOffset;
111 unsigned long StabsLength;
112 unsigned long StabstrOffset;
113 unsigned long StabstrLength;
114 } SYMBOLFILE_HEADER, *PSYMBOLFILE_HEADER;
115
116 typedef struct _STAB_ENTRY {
117 unsigned long n_strx; /* index into string table of name */
118 unsigned char n_type; /* type of symbol */
119 unsigned char n_other; /* misc info (usually empty) */
120 unsigned short n_desc; /* description field */
121 unsigned long n_value; /* value of symbol */
122 } STAB_ENTRY, *PSTAB_ENTRY;
123
124 #define N_FUN 0x24
125 #define N_SLINE 0x44
126 #define N_SO 0x64
127
128 typedef struct
129 {
130 unsigned long OldOffset;
131 unsigned long NewOffset;
132 char* Name;
133 unsigned long Length;
134 } STR_ENTRY, *PSTR_ENTRY;
135
136 char* convert_path(char* origpath)
137 {
138 char* newpath;
139 int i;
140
141 newpath = strdup(origpath);
142
143 i = 0;
144 while (newpath[i] != 0)
145 {
146 #ifdef UNIX_PATHS
147 if (newpath[i] == '\\')
148 {
149 newpath[i] = '/';
150 }
151 #else
152 #ifdef DOS_PATHS
153 if (newpath[i] == '/')
154 {
155 newpath[i] = '\\';
156 }
157 #endif
158 #endif
159 i++;
160 }
161 return(newpath);
162 }
163
164 #define TRANSFER_SIZE (65536)
165
166 int main(int argc, char* argv[])
167 {
168 SYMBOLFILE_HEADER SymbolFileHeader;
169 IMAGE_DOS_HEADER PEDosHeader;
170 IMAGE_FILE_HEADER PEFileHeader;
171 PIMAGE_OPTIONAL_HEADER PEOptHeader;
172 PIMAGE_SECTION_HEADER PESectionHeaders;
173 ULONG ImageBase;
174 PVOID SymbolsBase;
175 ULONG SymbolsLength;
176 PVOID SymbolStringsBase;
177 ULONG SymbolStringsLength;
178 ULONG Idx;
179 char* path1;
180 char* path2;
181 FILE* in;
182 FILE* out;
183 int n_in;
184 int n_out;
185 PSTAB_ENTRY StabEntry;
186 ULONG Count;
187 ULONG i;
188 ULONG SymbolsCount;
189 PSTR_ENTRY StrEntry;
190 ULONG StrCount;
191 ULONG j;
192
193 if (argc != 3)
194 {
195 fprintf(stderr, "Too many arguments\n");
196 exit(1);
197 }
198
199 path1 = convert_path(argv[1]);
200 path2 = convert_path(argv[2]);
201
202 in = fopen(path1, "rb");
203 if (in == NULL)
204 {
205 perror("Cannot open input file");
206 exit(1);
207 }
208
209 out = fopen(path2, "wb");
210 if (out == NULL)
211 {
212 perror("Cannot open output file");
213 fclose(in);
214 exit(1);
215 }
216
217 /* Check if MZ header exists */
218 n_in = fread(&PEDosHeader, 1, sizeof(PEDosHeader), in);
219 if (PEDosHeader.e_magic != IMAGE_DOS_MAGIC && PEDosHeader.e_lfanew != 0L)
220 {
221 perror("Input file is not a PE image.\n");
222 }
223
224 /* Read PE file header */
225 /* sizeof(ULONG) = sizeof(MAGIC) */
226 fseek(in, PEDosHeader.e_lfanew + sizeof(ULONG), SEEK_SET);
227 n_in = fread(&PEFileHeader, 1, sizeof(PEFileHeader), in);
228
229 /* Read optional header */
230 PEOptHeader = malloc(PEFileHeader.SizeOfOptionalHeader);
231 fread ( PEOptHeader, 1, PEFileHeader.SizeOfOptionalHeader, in );
232 ImageBase = PEOptHeader->ImageBase;
233
234 /* Read PE section headers */
235 PESectionHeaders = malloc(PEFileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
236 fseek(in, PEDosHeader.e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER)
237 + sizeof(IMAGE_OPTIONAL_HEADER), SEEK_SET);
238 n_in = fread(PESectionHeaders, 1, PEFileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER), in);
239
240 /* Copy .stab and .stabstr sections if available */
241 SymbolsBase = NULL;
242 SymbolsLength = 0;
243 SymbolStringsBase = NULL;
244 SymbolStringsLength = 0;
245
246 for (Idx = 0; Idx < PEFileHeader.NumberOfSections; Idx++)
247 {
248 //printf("section: '%.08s'\n", PESectionHeaders[Idx].Name);
249 if ((strncmp(PESectionHeaders[Idx].Name, ".stab", 5) == 0)
250 && (PESectionHeaders[Idx].Name[5] == 0))
251 {
252 //printf(".stab section found. Size %d\n",
253 // PESectionHeaders[Idx].SizeOfRawData);
254
255 SymbolsLength = PESectionHeaders[Idx].SizeOfRawData;
256 SymbolsBase = malloc(SymbolsLength);
257
258 fseek(in, PESectionHeaders[Idx].PointerToRawData, SEEK_SET);
259 n_in = fread(SymbolsBase, 1, SymbolsLength, in);
260 }
261
262 if (strncmp(PESectionHeaders[Idx].Name, ".stabstr", 8) == 0)
263 {
264 //printf(".stabstr section found. Size %d\n",
265 // PESectionHeaders[Idx].SizeOfRawData);
266
267 SymbolStringsLength = PESectionHeaders[Idx].SizeOfRawData;
268 SymbolStringsBase = malloc(SymbolStringsLength);
269
270 fseek(in, PESectionHeaders[Idx].PointerToRawData, SEEK_SET);
271 n_in = fread(SymbolStringsBase, 1, SymbolStringsLength, in);
272 }
273 }
274
275 StabEntry = SymbolsBase;
276 SymbolsCount = SymbolsLength / sizeof(STAB_ENTRY);
277 Count = 0;
278
279 for (i = 0; i < SymbolsCount; i++)
280 {
281 if (StabEntry[i].n_type == N_FUN ||
282 StabEntry[i].n_type == N_SLINE ||
283 StabEntry[i].n_type == N_SO)
284 {
285 memmove(&StabEntry[Count], &StabEntry[i], sizeof(STAB_ENTRY));
286 if ( StabEntry[Count].n_value >= ImageBase )
287 StabEntry[Count].n_value -= ImageBase;
288 Count++;
289 }
290 }
291
292 StrEntry = malloc(sizeof(STR_ENTRY) * Count);
293 StrCount = 0;
294
295 for (i = 0; i < Count; i++)
296 {
297 for (j = 0; j < StrCount; j++)
298 {
299 if (StabEntry[i].n_strx == StrEntry[j].OldOffset)
300 {
301 StabEntry[i].n_strx = StrEntry[j].NewOffset;
302 break;
303 }
304 }
305 if (j >= StrCount)
306 {
307 StrEntry[StrCount].OldOffset = StabEntry[i].n_strx;
308 StrEntry[StrCount].Name = (char*)SymbolStringsBase + StrEntry[StrCount].OldOffset;
309 StrEntry[StrCount].Length = strlen(StrEntry[StrCount].Name) + 1;
310 if (StrCount == 0)
311 {
312 StrEntry[StrCount].NewOffset = 0;
313 }
314 else
315 {
316 StrEntry[StrCount].NewOffset = StrEntry[StrCount-1].NewOffset + StrEntry[StrCount-1].Length;
317 }
318 StabEntry[i].n_strx = StrEntry[StrCount].NewOffset;
319 StrCount++;
320 }
321 }
322
323 SymbolFileHeader.StabsOffset = sizeof(SYMBOLFILE_HEADER);
324 SymbolFileHeader.StabsLength = Count * sizeof(STAB_ENTRY);
325 SymbolFileHeader.StabstrOffset = SymbolFileHeader.StabsOffset + SymbolFileHeader.StabsLength;
326 SymbolFileHeader.StabstrLength = StrEntry[StrCount-1].NewOffset + StrEntry[StrCount-1].Length;
327
328 n_out = fwrite(&SymbolFileHeader, 1, sizeof(SYMBOLFILE_HEADER), out);
329 n_out = fwrite(SymbolsBase, 1, SymbolFileHeader.StabsLength, out);
330 for (i = 0; i < StrCount; i++)
331 {
332 fwrite(StrEntry[i].Name, 1, StrEntry[i].Length, out);
333 }
334
335 fclose(out);
336 exit(0);
337 }