added PCI interrupt link device
[reactos.git] / reactos / tools / rsym.c
1 /*
2 * Usage: rsym input-file output-file
3 *
4 * There are two sources of information: the .stab/.stabstr
5 * sections of the executable and the COFF symbol table. Most
6 * of the information is in the .stab/.stabstr sections.
7 * However, most of our asm files don't contain .stab directives,
8 * so routines implemented in assembler won't show up in the
9 * .stab section. They are present in the COFF symbol table.
10 * So, we mostly use the .stab/.stabstr sections, but we augment
11 * the info there with info from the COFF symbol table when
12 * possible.
13 *
14 * This is a tool and is compiled using the host compiler,
15 * i.e. on Linux gcc and not mingw-gcc (cross-compiler).
16 * Therefore we can't include SDK headers and we have to
17 * duplicate some definitions here.
18 * Also note that the internal functions are "old C-style",
19 * returning an int, where a return of 0 means success and
20 * non-zero is failure.
21 */
22
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <assert.h>
27
28 #include "rsym.h"
29
30 static int
31 CompareSymEntry(const PROSSYM_ENTRY SymEntry1, const PROSSYM_ENTRY SymEntry2)
32 {
33 if (SymEntry1->Address < SymEntry2->Address)
34 {
35 return -1;
36 }
37
38 if (SymEntry2->Address < SymEntry1->Address)
39 {
40 return +1;
41 }
42
43 return 0;
44 }
45
46 static int
47 GetStabInfo(void *FileData, PIMAGE_FILE_HEADER PEFileHeader,
48 PIMAGE_SECTION_HEADER PESectionHeaders,
49 ULONG *StabSymbolsLength, void **StabSymbolsBase,
50 ULONG *StabStringsLength, void **StabStringsBase)
51 {
52 ULONG Idx;
53
54 /* Load .stab and .stabstr sections if available */
55 *StabSymbolsBase = NULL;
56 *StabSymbolsLength = 0;
57 *StabStringsBase = NULL;
58 *StabStringsLength = 0;
59
60 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
61 {
62 /* printf("section: '%.08s'\n", PESectionHeaders[Idx].Name); */
63 if ((strncmp((char*)PESectionHeaders[Idx].Name, ".stab", 5) == 0)
64 && (PESectionHeaders[Idx].Name[5] == 0))
65 {
66 /* printf(".stab section found. Size %d\n",
67 PESectionHeaders[Idx].SizeOfRawData); */
68
69 *StabSymbolsLength = PESectionHeaders[Idx].SizeOfRawData;
70 *StabSymbolsBase = (void *)((char *) FileData + PESectionHeaders[Idx].PointerToRawData);
71 }
72
73 if (strncmp((char*)PESectionHeaders[Idx].Name, ".stabstr", 8) == 0)
74 {
75 /* printf(".stabstr section found. Size %d\n",
76 PESectionHeaders[Idx].SizeOfRawData); */
77
78 *StabStringsLength = PESectionHeaders[Idx].SizeOfRawData;
79 *StabStringsBase = (void *)((char *) FileData + PESectionHeaders[Idx].PointerToRawData);
80 }
81 }
82
83 return 0;
84 }
85
86 static int
87 GetCoffInfo(void *FileData, PIMAGE_FILE_HEADER PEFileHeader,
88 PIMAGE_SECTION_HEADER PESectionHeaders,
89 ULONG *CoffSymbolsLength, void **CoffSymbolsBase,
90 ULONG *CoffStringsLength, void **CoffStringsBase)
91 {
92
93 if (0 == PEFileHeader->PointerToSymbolTable || 0 == PEFileHeader->NumberOfSymbols)
94 {
95 /* No COFF symbol table */
96 *CoffSymbolsLength = 0;
97 *CoffStringsLength = 0;
98 }
99 else
100 {
101 *CoffSymbolsLength = PEFileHeader->NumberOfSymbols * sizeof(COFF_SYMENT);
102 *CoffSymbolsBase = (void *)((char *) FileData + PEFileHeader->PointerToSymbolTable);
103 *CoffStringsLength = *((ULONG *) ((char *) *CoffSymbolsBase + *CoffSymbolsLength));
104 *CoffStringsBase = (void *)((char *) *CoffSymbolsBase + *CoffSymbolsLength);
105 }
106
107 return 0;
108 }
109
110 static ULONG
111 FindOrAddString(char *StringToFind, ULONG *StringsLength, void *StringsBase)
112 {
113 char *Search, *End;
114
115 Search = (char *) StringsBase;
116 End = Search + *StringsLength;
117
118 while (Search < End)
119 {
120 if (0 == strcmp(Search, StringToFind))
121 {
122 return Search - (char *) StringsBase;
123 }
124 Search += strlen(Search) + 1;
125 }
126
127 strcpy(Search, StringToFind);
128 *StringsLength += strlen(StringToFind) + 1;
129
130 return Search - (char *) StringsBase;
131 }
132
133 static int
134 ConvertStabs(ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase,
135 ULONG *StringsLength, void *StringsBase,
136 ULONG StabSymbolsLength, void *StabSymbolsBase,
137 ULONG StabStringsLength, void *StabStringsBase,
138 ULONG_PTR ImageBase, PIMAGE_FILE_HEADER PEFileHeader,
139 PIMAGE_SECTION_HEADER PESectionHeaders)
140 {
141 PSTAB_ENTRY StabEntry;
142 ULONG Count, i;
143 ULONG_PTR Address, LastFunctionAddress;
144 int First;
145 char *Name;
146 char FuncName[256];
147
148 StabEntry = StabSymbolsBase;
149 Count = StabSymbolsLength / sizeof(STAB_ENTRY);
150 *SymbolsCount = 0;
151 if (Count == 0)
152 {
153 /* No symbol info */
154 *SymbolsBase = NULL;
155 return 0;
156 }
157
158 *SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY));
159 if (NULL == *SymbolsBase)
160 {
161 fprintf(stderr, "Failed to allocate memory for converted .stab symbols\n");
162 return 1;
163 }
164
165 LastFunctionAddress = 0;
166 First = 1;
167 for (i = 0; i < Count; i++)
168 {
169 switch (StabEntry[i].n_type)
170 {
171 case N_SO:
172 Name = (char *) StabStringsBase + StabEntry[i].n_strx;
173 if (StabStringsLength < StabEntry[i].n_strx
174 ||'\0' == *Name || '/' == Name[strlen(Name) - 1]
175 || '\\' == Name[strlen(Name) - 1]
176 || StabEntry[i].n_value < ImageBase)
177 {
178 continue;
179 }
180 Address = StabEntry[i].n_value - ImageBase;
181 if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
182 {
183 (*SymbolsCount)++;
184 }
185 (*SymbolsBase)[*SymbolsCount].Address = Address;
186 (*SymbolsBase)[*SymbolsCount].FileOffset = FindOrAddString((char *) StabStringsBase
187 + StabEntry[i].n_strx,
188 StringsLength,
189 StringsBase);
190 (*SymbolsBase)[*SymbolsCount].FunctionOffset = 0;
191 (*SymbolsBase)[*SymbolsCount].SourceLine = 0;
192 LastFunctionAddress = 0;
193 break;
194 case N_FUN:
195 if (0 == StabEntry[i].n_desc || StabEntry[i].n_value < ImageBase) /* line # 0 isn't valid */
196 {
197 continue;
198 }
199 Address = StabEntry[i].n_value - ImageBase;
200 if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
201 {
202 (*SymbolsCount)++;
203 (*SymbolsBase)[*SymbolsCount].FileOffset = (*SymbolsBase)[*SymbolsCount - 1].FileOffset;
204 }
205 (*SymbolsBase)[*SymbolsCount].Address = Address;
206 if (sizeof(FuncName) <= strlen((char *) StabStringsBase + StabEntry[i].n_strx))
207 {
208 free(*SymbolsBase);
209 fprintf(stderr, "Function name too long\n");
210 return 1;
211 }
212 strcpy(FuncName, (char *) StabStringsBase + StabEntry[i].n_strx);
213 Name = strchr(FuncName, ':');
214 if (NULL != Name)
215 {
216 *Name = '\0';
217 }
218 (*SymbolsBase)[*SymbolsCount].FunctionOffset = FindOrAddString(FuncName,
219 StringsLength,
220 StringsBase);
221 (*SymbolsBase)[*SymbolsCount].SourceLine = 0;
222 LastFunctionAddress = Address;
223 break;
224 case N_SLINE:
225 if (0 == LastFunctionAddress)
226 {
227 Address = StabEntry[i].n_value - ImageBase;
228 }
229 else
230 {
231 Address = LastFunctionAddress + StabEntry[i].n_value;
232 }
233 if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
234 {
235 (*SymbolsCount)++;
236 (*SymbolsBase)[*SymbolsCount].FileOffset = (*SymbolsBase)[*SymbolsCount - 1].FileOffset;
237 (*SymbolsBase)[*SymbolsCount].FunctionOffset = (*SymbolsBase)[*SymbolsCount - 1].FunctionOffset;
238 }
239 (*SymbolsBase)[*SymbolsCount].Address = Address;
240 (*SymbolsBase)[*SymbolsCount].SourceLine = StabEntry[i].n_desc;
241 break;
242 default:
243 continue;
244 }
245 First = 0;
246 }
247 (*SymbolsCount)++;
248
249 qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
250
251 return 0;
252 }
253
254 static int
255 ConvertCoffs(ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase,
256 ULONG *StringsLength, void *StringsBase,
257 ULONG CoffSymbolsLength, void *CoffSymbolsBase,
258 ULONG CoffStringsLength, void *CoffStringsBase,
259 ULONG_PTR ImageBase, PIMAGE_FILE_HEADER PEFileHeader,
260 PIMAGE_SECTION_HEADER PESectionHeaders)
261 {
262 ULONG Count, i;
263 PCOFF_SYMENT CoffEntry;
264 char FuncName[256];
265 char *p;
266
267 CoffEntry = (PCOFF_SYMENT) CoffSymbolsBase;
268 Count = CoffSymbolsLength / sizeof(COFF_SYMENT);
269 *SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY));
270 if (NULL == *SymbolsBase)
271 {
272 fprintf(stderr, "Unable to allocate memory for converted COFF symbols\n");
273 return 1;
274 }
275 *SymbolsCount = 0;
276
277 for (i = 0; i < Count; i++)
278 {
279 if (ISFCN(CoffEntry[i].e_type) || C_EXT == CoffEntry[i].e_sclass)
280 {
281 (*SymbolsBase)[*SymbolsCount].Address = CoffEntry[i].e_value;
282 if (0 < CoffEntry[i].e_scnum)
283 {
284 if (PEFileHeader->NumberOfSections < CoffEntry[i].e_scnum)
285 {
286 free(*SymbolsBase);
287 fprintf(stderr, "Invalid section number %d in COFF symbols (only %d sections present)\n",
288 CoffEntry[i].e_scnum, PEFileHeader->NumberOfSections);
289 return 1;
290 }
291 (*SymbolsBase)[*SymbolsCount].Address += PESectionHeaders[CoffEntry[i].e_scnum - 1].VirtualAddress;
292 }
293 (*SymbolsBase)[*SymbolsCount].FileOffset = 0;
294 if (0 == CoffEntry[i].e.e.e_zeroes)
295 {
296 if (sizeof(FuncName) <= strlen((char *) CoffStringsBase + CoffEntry[i].e.e.e_offset))
297 {
298 free(*SymbolsBase);
299 fprintf(stderr, "Function name too long\n");
300 return 1;
301 }
302 strcpy(FuncName, (char *) CoffStringsBase + CoffEntry[i].e.e.e_offset);
303 }
304 else
305 {
306 memcpy(FuncName, CoffEntry[i].e.e_name, E_SYMNMLEN);
307 FuncName[E_SYMNMLEN] = '\0';
308 }
309
310 /* Name demangling: stdcall */
311 p = strrchr(FuncName, '@');
312 if (NULL != p)
313 {
314 *p = '\0';
315 }
316 p = ('_' == FuncName[0] || '@' == FuncName[0] ? FuncName + 1 : FuncName);
317 (*SymbolsBase)[*SymbolsCount].FunctionOffset = FindOrAddString(p,
318 StringsLength,
319 StringsBase);
320 (*SymbolsBase)[*SymbolsCount].SourceLine = 0;
321 (*SymbolsCount)++;
322 }
323 i += CoffEntry[i].e_numaux;
324 }
325
326 qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
327
328 return 0;
329 }
330
331 static int
332 MergeStabsAndCoffs(ULONG *MergedSymbolCount, PROSSYM_ENTRY *MergedSymbols,
333 ULONG StabSymbolsCount, PROSSYM_ENTRY StabSymbols,
334 ULONG CoffSymbolsCount, PROSSYM_ENTRY CoffSymbols)
335 {
336 ULONG StabIndex, j;
337 ULONG CoffIndex;
338 ULONG_PTR StabFunctionStartAddress;
339 ULONG StabFunctionStringOffset, NewStabFunctionStringOffset;
340
341 *MergedSymbolCount = 0;
342 if (StabSymbolsCount == 0)
343 {
344 *MergedSymbols = NULL;
345 return 0;
346 }
347 *MergedSymbols = malloc(StabSymbolsCount * sizeof(ROSSYM_ENTRY));
348 if (NULL == *MergedSymbols)
349 {
350 fprintf(stderr, "Unable to allocate memory for merged symbols\n");
351 return 1;
352 }
353
354 StabFunctionStartAddress = 0;
355 StabFunctionStringOffset = 0;
356 CoffIndex = 0;
357 for (StabIndex = 0; StabIndex < StabSymbolsCount; StabIndex++)
358 {
359 (*MergedSymbols)[*MergedSymbolCount] = StabSymbols[StabIndex];
360 for (j = StabIndex + 1;
361 j < StabSymbolsCount && StabSymbols[j].Address == StabSymbols[StabIndex].Address;
362 j++)
363 {
364 if (0 != StabSymbols[j].FileOffset && 0 == (*MergedSymbols)[*MergedSymbolCount].FileOffset)
365 {
366 (*MergedSymbols)[*MergedSymbolCount].FileOffset = StabSymbols[j].FileOffset;
367 }
368 if (0 != StabSymbols[j].FunctionOffset && 0 == (*MergedSymbols)[*MergedSymbolCount].FunctionOffset)
369 {
370 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = StabSymbols[j].FunctionOffset;
371 }
372 if (0 != StabSymbols[j].SourceLine && 0 == (*MergedSymbols)[*MergedSymbolCount].SourceLine)
373 {
374 (*MergedSymbols)[*MergedSymbolCount].SourceLine = StabSymbols[j].SourceLine;
375 }
376 }
377 StabIndex = j - 1;
378 while (CoffIndex < CoffSymbolsCount
379 && CoffSymbols[CoffIndex + 1].Address <= (*MergedSymbols)[*MergedSymbolCount].Address)
380 {
381 CoffIndex++;
382 }
383 NewStabFunctionStringOffset = (*MergedSymbols)[*MergedSymbolCount].FunctionOffset;
384 if (CoffSymbolsCount > 0 &&
385 CoffSymbols[CoffIndex].Address < (*MergedSymbols)[*MergedSymbolCount].Address
386 && StabFunctionStartAddress < CoffSymbols[CoffIndex].Address
387 && 0 != CoffSymbols[CoffIndex].FunctionOffset)
388 {
389 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = CoffSymbols[CoffIndex].FunctionOffset;
390 }
391 if (StabFunctionStringOffset != NewStabFunctionStringOffset)
392 {
393 StabFunctionStartAddress = (*MergedSymbols)[*MergedSymbolCount].Address;
394 }
395 StabFunctionStringOffset = NewStabFunctionStringOffset;
396 (*MergedSymbolCount)++;
397 }
398
399 return 0;
400 }
401
402 static PIMAGE_SECTION_HEADER
403 FindSectionForRVA(DWORD RVA, unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
404 {
405 unsigned Section;
406
407 for (Section = 0; Section < NumberOfSections; Section++)
408 {
409 if (SectionHeaders[Section].VirtualAddress <= RVA &&
410 RVA < SectionHeaders[Section].VirtualAddress + SectionHeaders[Section].Misc.VirtualSize)
411 {
412 return SectionHeaders + Section;
413 }
414 }
415
416 return NULL;
417 }
418
419 static int
420 IncludeRelocationsForSection(PIMAGE_SECTION_HEADER SectionHeader)
421 {
422 static char *BlacklistedSections[] =
423 {
424 ".edata",
425 ".idata",
426 ".reloc"
427 };
428 char SectionName[IMAGE_SIZEOF_SHORT_NAME];
429 unsigned i;
430
431 if (0 != (SectionHeader->Characteristics & IMAGE_SCN_LNK_REMOVE))
432 {
433 return 0;
434 }
435
436 for (i = 0; i < sizeof(BlacklistedSections) / sizeof(BlacklistedSections[0]); i++)
437 {
438 strncpy(SectionName, BlacklistedSections[i], IMAGE_SIZEOF_SHORT_NAME);
439 if (0 == memcmp(SectionName, SectionHeader->Name, IMAGE_SIZEOF_SHORT_NAME))
440 {
441 return 0;
442 }
443 }
444
445 return 1;
446 }
447
448 static int
449 ProcessRelocations(ULONG *ProcessedRelocsLength, void **ProcessedRelocs,
450 void *RawData, PIMAGE_OPTIONAL_HEADER OptHeader,
451 unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
452 {
453 PIMAGE_SECTION_HEADER RelocSectionHeader, TargetSectionHeader;
454 PIMAGE_BASE_RELOCATION BaseReloc, End, AcceptedRelocs;
455 int Found;
456
457 if (OptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC
458 || 0 == OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
459 {
460 /* No relocation entries */
461 *ProcessedRelocsLength = 0;
462 *ProcessedRelocs = NULL;
463 return 0;
464 }
465
466 RelocSectionHeader = FindSectionForRVA(OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
467 NumberOfSections, SectionHeaders);
468 if (NULL == RelocSectionHeader)
469 {
470 fprintf(stderr, "Can't find section header for relocation data\n");
471 return 1;
472 }
473
474 *ProcessedRelocs = malloc(RelocSectionHeader->SizeOfRawData);
475 if (NULL == *ProcessedRelocs)
476 {
477 fprintf(stderr, "Failed to allocate %lu bytes for relocations\n", RelocSectionHeader->SizeOfRawData);
478 return 1;
479 }
480 *ProcessedRelocsLength = 0;
481
482 BaseReloc = (PIMAGE_BASE_RELOCATION) ((char *) RawData
483 + RelocSectionHeader->PointerToRawData
484 + (OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress -
485 RelocSectionHeader->VirtualAddress));
486 End = (PIMAGE_BASE_RELOCATION) ((char *) BaseReloc
487 + OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
488
489 while (BaseReloc < End && 0 < BaseReloc->SizeOfBlock)
490 {
491 TargetSectionHeader = FindSectionForRVA(BaseReloc->VirtualAddress, NumberOfSections,
492 SectionHeaders);
493 if (NULL != TargetSectionHeader && IncludeRelocationsForSection(TargetSectionHeader))
494 {
495 AcceptedRelocs = *ProcessedRelocs;
496 Found = 0;
497 while (AcceptedRelocs < (PIMAGE_BASE_RELOCATION) ((char *) *ProcessedRelocs +
498 *ProcessedRelocsLength)
499 && ! Found)
500 {
501 Found = BaseReloc->SizeOfBlock == AcceptedRelocs->SizeOfBlock
502 && 0 == memcmp(BaseReloc, AcceptedRelocs, AcceptedRelocs->SizeOfBlock);
503 AcceptedRelocs= (PIMAGE_BASE_RELOCATION) ((char *) AcceptedRelocs +
504 AcceptedRelocs->SizeOfBlock);
505 }
506 if (! Found)
507 {
508 memcpy((char *) *ProcessedRelocs + *ProcessedRelocsLength,
509 BaseReloc, BaseReloc->SizeOfBlock);
510 *ProcessedRelocsLength += BaseReloc->SizeOfBlock;
511 }
512 }
513 BaseReloc = (PIMAGE_BASE_RELOCATION)((char *) BaseReloc + BaseReloc->SizeOfBlock);
514 }
515
516 return 0;
517 }
518
519 static int
520 CreateOutputFile(FILE *OutFile, void *InData,
521 PIMAGE_DOS_HEADER InDosHeader, PIMAGE_FILE_HEADER InFileHeader,
522 PIMAGE_OPTIONAL_HEADER InOptHeader, PIMAGE_SECTION_HEADER InSectionHeaders,
523 ULONG RosSymLength, void *RosSymSection)
524 {
525 ULONG StartOfRawData;
526 unsigned Section;
527 void *OutHeader, *ProcessedRelocs, *PaddedRosSym, *Data;
528 PIMAGE_DOS_HEADER OutDosHeader;
529 PIMAGE_FILE_HEADER OutFileHeader;
530 PIMAGE_OPTIONAL_HEADER OutOptHeader;
531 PIMAGE_SECTION_HEADER OutSectionHeaders, CurrentSectionHeader;
532 DWORD CheckSum;
533 ULONG Length, i;
534 ULONG ProcessedRelocsLength;
535 ULONG RosSymOffset, RosSymFileLength;
536 int InRelocSectionIndex;
537 PIMAGE_SECTION_HEADER OutRelocSection;
538
539 StartOfRawData = 0;
540 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
541 {
542 if ((0 == StartOfRawData
543 || InSectionHeaders[Section].PointerToRawData < StartOfRawData)
544 && 0 != InSectionHeaders[Section].PointerToRawData
545 && 0 == (InSectionHeaders[Section].Characteristics & IMAGE_SCN_LNK_REMOVE))
546 {
547 StartOfRawData = InSectionHeaders[Section].PointerToRawData;
548 }
549 }
550 OutHeader = malloc(StartOfRawData);
551 if (NULL == OutHeader)
552 {
553 fprintf(stderr, "Failed to allocate %lu bytes for output file header\n", StartOfRawData);
554 return 1;
555 }
556 memset(OutHeader, '\0', StartOfRawData);
557
558 OutDosHeader = (PIMAGE_DOS_HEADER) OutHeader;
559 memcpy(OutDosHeader, InDosHeader, InDosHeader->e_lfanew + sizeof(ULONG));
560
561 OutFileHeader = (PIMAGE_FILE_HEADER)((char *) OutHeader + OutDosHeader->e_lfanew + sizeof(ULONG));
562 memcpy(OutFileHeader, InFileHeader, sizeof(IMAGE_FILE_HEADER));
563 OutFileHeader->PointerToSymbolTable = 0;
564 OutFileHeader->NumberOfSymbols = 0;
565 OutFileHeader->Characteristics &= ~(IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_LOCAL_SYMS_STRIPPED |
566 IMAGE_FILE_DEBUG_STRIPPED);
567
568 OutOptHeader = (PIMAGE_OPTIONAL_HEADER)(OutFileHeader + 1);
569 memcpy(OutOptHeader, InOptHeader, sizeof(IMAGE_OPTIONAL_HEADER));
570 OutOptHeader->CheckSum = 0;
571
572 OutSectionHeaders = (PIMAGE_SECTION_HEADER)((char *) OutOptHeader + OutFileHeader->SizeOfOptionalHeader);
573
574 if (ProcessRelocations(&ProcessedRelocsLength, &ProcessedRelocs, InData, InOptHeader,
575 InFileHeader->NumberOfSections, InSectionHeaders))
576 {
577 return 1;
578 }
579 if (InOptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC
580 || 0 == InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
581 {
582 InRelocSectionIndex = -1;
583 }
584 else
585 {
586 InRelocSectionIndex = FindSectionForRVA(InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
587 InFileHeader->NumberOfSections, InSectionHeaders) - InSectionHeaders;
588 }
589
590 OutFileHeader->NumberOfSections = 0;
591 CurrentSectionHeader = OutSectionHeaders;
592 OutOptHeader->SizeOfImage = 0;
593 RosSymOffset = 0;
594 OutRelocSection = NULL;
595 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
596 {
597 if (0 == (InSectionHeaders[Section].Characteristics & IMAGE_SCN_LNK_REMOVE))
598 {
599 *CurrentSectionHeader = InSectionHeaders[Section];
600 CurrentSectionHeader->PointerToLinenumbers = 0;
601 CurrentSectionHeader->NumberOfLinenumbers = 0;
602 if (OutOptHeader->SizeOfImage < CurrentSectionHeader->VirtualAddress +
603 CurrentSectionHeader->Misc.VirtualSize)
604 {
605 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress +
606 CurrentSectionHeader->Misc.VirtualSize,
607 OutOptHeader->SectionAlignment);
608 }
609 if (RosSymOffset < CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData)
610 {
611 RosSymOffset = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData;
612 }
613 if (Section == InRelocSectionIndex)
614 {
615 OutRelocSection = CurrentSectionHeader;
616 }
617 (OutFileHeader->NumberOfSections) ++;
618 CurrentSectionHeader++;
619 }
620 }
621
622 if (OutRelocSection == CurrentSectionHeader - 1)
623 {
624 OutOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = ProcessedRelocsLength;
625 if (OutOptHeader->SizeOfImage == OutRelocSection->VirtualAddress +
626 ROUND_UP(OutRelocSection->Misc.VirtualSize,
627 OutOptHeader->SectionAlignment))
628 {
629 OutOptHeader->SizeOfImage = OutRelocSection->VirtualAddress +
630 ROUND_UP(ProcessedRelocsLength,
631 OutOptHeader->SectionAlignment);
632 }
633 OutRelocSection->Misc.VirtualSize = ProcessedRelocsLength;
634 if (RosSymOffset == OutRelocSection->PointerToRawData
635 + OutRelocSection->SizeOfRawData)
636 {
637 RosSymOffset = OutRelocSection->PointerToRawData +
638 ROUND_UP(ProcessedRelocsLength, OutOptHeader->FileAlignment);
639 }
640 OutRelocSection->SizeOfRawData = ROUND_UP(ProcessedRelocsLength,
641 OutOptHeader->FileAlignment);
642 }
643
644 if (RosSymLength > 0)
645 {
646 RosSymFileLength = ROUND_UP(RosSymLength, OutOptHeader->FileAlignment);
647 memcpy(CurrentSectionHeader->Name, ".rossym", 8); /* We're lucky: string is exactly 8 bytes long */
648 CurrentSectionHeader->Misc.VirtualSize = RosSymLength;
649 CurrentSectionHeader->VirtualAddress = OutOptHeader->SizeOfImage;
650 CurrentSectionHeader->SizeOfRawData = RosSymFileLength;
651 CurrentSectionHeader->PointerToRawData = RosSymOffset;
652 CurrentSectionHeader->PointerToRelocations = 0;
653 CurrentSectionHeader->PointerToLinenumbers = 0;
654 CurrentSectionHeader->NumberOfRelocations = 0;
655 CurrentSectionHeader->NumberOfLinenumbers = 0;
656 CurrentSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
657 | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_TYPE_NOLOAD;
658 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress +
659 CurrentSectionHeader->Misc.VirtualSize,
660 OutOptHeader->SectionAlignment);
661 (OutFileHeader->NumberOfSections)++;
662
663 PaddedRosSym = malloc(RosSymFileLength);
664 if (NULL == PaddedRosSym)
665 {
666 fprintf(stderr, "Failed to allocate %lu bytes for padded .rossym\n", RosSymFileLength);
667 return 1;
668 }
669 memcpy(PaddedRosSym, RosSymSection, RosSymLength);
670 memset((char *) PaddedRosSym + RosSymLength, '\0', RosSymFileLength - RosSymLength);
671 }
672 else
673 {
674 PaddedRosSym = NULL;
675 }
676 CheckSum = 0;
677 for (i = 0; i < StartOfRawData / 2; i++)
678 {
679 CheckSum += ((unsigned short*) OutHeader)[i];
680 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
681 }
682 Length = StartOfRawData;
683 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
684 {
685 if (OutRelocSection == OutSectionHeaders + Section)
686 {
687 Data = (void *) ProcessedRelocs;
688 }
689 else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections)
690 {
691 Data = (void *) PaddedRosSym;
692 }
693 else
694 {
695 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
696 }
697 for (i = 0; i < OutSectionHeaders[Section].SizeOfRawData / 2; i++)
698 {
699 CheckSum += ((unsigned short*) Data)[i];
700 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
701 }
702 Length += OutSectionHeaders[Section].SizeOfRawData;
703 }
704 CheckSum += Length;
705 OutOptHeader->CheckSum = CheckSum;
706
707 if (fwrite(OutHeader, 1, StartOfRawData, OutFile) != StartOfRawData)
708 {
709 perror("Error writing output header\n");
710 free(OutHeader);
711 return 1;
712 }
713
714 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
715 {
716 if (0 != OutSectionHeaders[Section].SizeOfRawData)
717 {
718 fseek(OutFile, OutSectionHeaders[Section].PointerToRawData, SEEK_SET);
719 if (OutRelocSection == OutSectionHeaders + Section)
720 {
721 Data = (void *) ProcessedRelocs;
722 }
723 else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections)
724 {
725 Data = (void *) PaddedRosSym;
726 }
727 else
728 {
729 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
730 }
731 if (fwrite(Data, 1, OutSectionHeaders[Section].SizeOfRawData, OutFile) !=
732 OutSectionHeaders[Section].SizeOfRawData)
733 {
734 perror("Error writing section data\n");
735 free(PaddedRosSym);
736 free(OutHeader);
737 return 1;
738 }
739 }
740 }
741
742 if (PaddedRosSym)
743 {
744 free(PaddedRosSym);
745 }
746 free(OutHeader);
747
748 return 0;
749 }
750
751 int main(int argc, char* argv[])
752 {
753 PSYMBOLFILE_HEADER SymbolFileHeader;
754 PIMAGE_DOS_HEADER PEDosHeader;
755 PIMAGE_FILE_HEADER PEFileHeader;
756 PIMAGE_OPTIONAL_HEADER PEOptHeader;
757 PIMAGE_SECTION_HEADER PESectionHeaders;
758 ULONG ImageBase;
759 void *StabBase;
760 ULONG StabsLength;
761 void *StabStringBase;
762 ULONG StabStringsLength;
763 void *CoffBase = NULL;
764 ULONG CoffsLength;
765 void *CoffStringBase = NULL;
766 ULONG CoffStringsLength;
767 char* path1;
768 char* path2;
769 FILE* out;
770 void *StringBase;
771 ULONG StringsLength;
772 ULONG StabSymbolsCount;
773 PROSSYM_ENTRY StabSymbols;
774 ULONG CoffSymbolsCount;
775 PROSSYM_ENTRY CoffSymbols;
776 ULONG MergedSymbolsCount;
777 PROSSYM_ENTRY MergedSymbols;
778 size_t FileSize;
779 void *FileData;
780 ULONG RosSymLength;
781 void *RosSymSection;
782
783 if (3 != argc)
784 {
785 fprintf(stderr, "Usage: rsym <exefile> <symfile>\n");
786 exit(1);
787 }
788
789 path1 = convert_path(argv[1]);
790 path2 = convert_path(argv[2]);
791
792 FileData = load_file ( path1, &FileSize );
793 if ( !FileData )
794 {
795 fprintf ( stderr, "An error occured loading '%s'\n", path1 );
796 exit(1);
797 }
798
799 /* Check if MZ header exists */
800 PEDosHeader = (PIMAGE_DOS_HEADER) FileData;
801 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC || PEDosHeader->e_lfanew == 0L)
802 {
803 perror("Input file is not a PE image.\n");
804 free(FileData);
805 exit(1);
806 }
807
808 /* Locate PE file header */
809 /* sizeof(ULONG) = sizeof(MAGIC) */
810 PEFileHeader = (PIMAGE_FILE_HEADER)((char *) FileData + PEDosHeader->e_lfanew + sizeof(ULONG));
811
812 /* Locate optional header */
813 assert(sizeof(ULONG) == 4);
814 PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
815 ImageBase = PEOptHeader->ImageBase;
816
817 /* Locate PE section headers */
818 PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *) PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
819
820 if (GetStabInfo(FileData, PEFileHeader, PESectionHeaders, &StabsLength, &StabBase,
821 &StabStringsLength, &StabStringBase))
822 {
823 free(FileData);
824 exit(1);
825 }
826
827 if (GetCoffInfo(FileData, PEFileHeader, PESectionHeaders, &CoffsLength, &CoffBase,
828 &CoffStringsLength, &CoffStringBase))
829 {
830 free(FileData);
831 exit(1);
832 }
833
834 StringBase = malloc(1 + StabStringsLength + CoffStringsLength +
835 (CoffsLength / sizeof(ROSSYM_ENTRY)) * (E_SYMNMLEN + 1));
836 if (NULL == StringBase)
837 {
838 free(FileData);
839 fprintf(stderr, "Failed to allocate memory for strings table\n");
840 exit(1);
841 }
842 /* Make offset 0 into an empty string */
843 *((char *) StringBase) = '\0';
844 StringsLength = 1;
845
846 if (ConvertStabs(&StabSymbolsCount, &StabSymbols, &StringsLength, StringBase,
847 StabsLength, StabBase, StabStringsLength, StabStringBase,
848 ImageBase, PEFileHeader, PESectionHeaders))
849 {
850 free(StringBase);
851 free(FileData);
852 fprintf(stderr, "Failed to allocate memory for strings table\n");
853 exit(1);
854 }
855
856 if (ConvertCoffs(&CoffSymbolsCount, &CoffSymbols, &StringsLength, StringBase,
857 CoffsLength, CoffBase, CoffStringsLength, CoffStringBase,
858 ImageBase, PEFileHeader, PESectionHeaders))
859 {
860 if (StabSymbols)
861 {
862 free(StabSymbols);
863 }
864 free(StringBase);
865 free(FileData);
866 exit(1);
867 }
868
869 if (MergeStabsAndCoffs(&MergedSymbolsCount, &MergedSymbols,
870 StabSymbolsCount, StabSymbols,
871 CoffSymbolsCount, CoffSymbols))
872 {
873 if (CoffSymbols)
874 {
875 free(CoffSymbols);
876 }
877 if (StabSymbols)
878 {
879 free(StabSymbols);
880 }
881 free(StringBase);
882 free(FileData);
883 exit(1);
884 }
885
886 if (CoffSymbols)
887 {
888 free(CoffSymbols);
889 }
890 if (StabSymbols)
891 {
892 free(StabSymbols);
893 }
894 if (MergedSymbolsCount == 0)
895 {
896 RosSymLength = 0;
897 RosSymSection = NULL;
898 }
899 else
900 {
901 RosSymLength = sizeof(SYMBOLFILE_HEADER) + MergedSymbolsCount * sizeof(ROSSYM_ENTRY)
902 + StringsLength;
903 RosSymSection = malloc(RosSymLength);
904 if (NULL == RosSymSection)
905 {
906 free(MergedSymbols);
907 free(StringBase);
908 free(FileData);
909 fprintf(stderr, "Unable to allocate memory for .rossym section\n");
910 exit(1);
911 }
912 memset(RosSymSection, '\0', RosSymLength);
913
914 SymbolFileHeader = (PSYMBOLFILE_HEADER) RosSymSection;
915 SymbolFileHeader->SymbolsOffset = sizeof(SYMBOLFILE_HEADER);
916 SymbolFileHeader->SymbolsLength = MergedSymbolsCount * sizeof(ROSSYM_ENTRY);
917 SymbolFileHeader->StringsOffset = SymbolFileHeader->SymbolsOffset + SymbolFileHeader->SymbolsLength;
918 SymbolFileHeader->StringsLength = StringsLength;
919
920 memcpy((char *) RosSymSection + SymbolFileHeader->SymbolsOffset, MergedSymbols,
921 SymbolFileHeader->SymbolsLength);
922 memcpy((char *) RosSymSection + SymbolFileHeader->StringsOffset, StringBase,
923 SymbolFileHeader->StringsLength);
924
925 free(MergedSymbols);
926 }
927 free(StringBase);
928 out = fopen(path2, "wb");
929 if (out == NULL)
930 {
931 perror("Cannot open output file");
932 free(RosSymSection);
933 free(FileData);
934 exit(1);
935 }
936
937 if (CreateOutputFile(out, FileData, PEDosHeader, PEFileHeader, PEOptHeader,
938 PESectionHeaders, RosSymLength, RosSymSection))
939 {
940 fclose(out);
941 if (RosSymSection)
942 {
943 free(RosSymSection);
944 }
945 free(FileData);
946 exit(1);
947 }
948
949 fclose(out);
950 if (RosSymSection)
951 {
952 free(RosSymSection);
953 }
954 free(FileData);
955
956 return 0;
957 }
958
959 /* EOF */