21885b4e98546d4b9092a481c743c8ca2cb20604
[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
27 #define IMAGE_DOS_MAGIC 0x5a4d
28 #define IMAGE_PE_MAGIC 0x00004550
29
30 #define IMAGE_SIZEOF_SHORT_NAME 8
31
32 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
33
34 typedef unsigned char BYTE;
35 typedef unsigned short WORD;
36 typedef unsigned long DWORD;
37 typedef signed long LONG;
38 typedef unsigned long ULONG;
39 #if defined(_WIN64)
40 typedef unsigned __int64 ULONG_PTR;
41 #else
42 typedef unsigned long ULONG_PTR;
43 #endif
44
45 #pragma pack(push,2)
46 typedef struct _IMAGE_DOS_HEADER {
47 WORD e_magic;
48 WORD e_cblp;
49 WORD e_cp;
50 WORD e_crlc;
51 WORD e_cparhdr;
52 WORD e_minalloc;
53 WORD e_maxalloc;
54 WORD e_ss;
55 WORD e_sp;
56 WORD e_csum;
57 WORD e_ip;
58 WORD e_cs;
59 WORD e_lfarlc;
60 WORD e_ovno;
61 WORD e_res[4];
62 WORD e_oemid;
63 WORD e_oeminfo;
64 WORD e_res2[10];
65 LONG e_lfanew;
66 } IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;
67 #pragma pack(pop)
68
69 #define IMAGE_FILE_LINE_NUMS_STRIPPED 4
70 #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 8
71 #define IMAGE_FILE_DEBUG_STRIPPED 512
72
73 #pragma pack(push,4)
74 typedef struct _IMAGE_FILE_HEADER {
75 WORD Machine;
76 WORD NumberOfSections;
77 DWORD TimeDateStamp;
78 DWORD PointerToSymbolTable;
79 DWORD NumberOfSymbols;
80 WORD SizeOfOptionalHeader;
81 WORD Characteristics;
82 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
83
84 typedef struct _IMAGE_DATA_DIRECTORY {
85 DWORD VirtualAddress;
86 DWORD Size;
87 } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
88
89 #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
90
91 typedef struct _IMAGE_OPTIONAL_HEADER {
92 WORD Magic;
93 BYTE MajorLinkerVersion;
94 BYTE MinorLinkerVersion;
95 DWORD SizeOfCode;
96 DWORD SizeOfInitializedData;
97 DWORD SizeOfUninitializedData;
98 DWORD AddressOfEntryPoint;
99 DWORD BaseOfCode;
100 DWORD BaseOfData;
101 DWORD ImageBase;
102 DWORD SectionAlignment;
103 DWORD FileAlignment;
104 WORD MajorOperatingSystemVersion;
105 WORD MinorOperatingSystemVersion;
106 WORD MajorImageVersion;
107 WORD MinorImageVersion;
108 WORD MajorSubsystemVersion;
109 WORD MinorSubsystemVersion;
110 DWORD Reserved1;
111 DWORD SizeOfImage;
112 DWORD SizeOfHeaders;
113 DWORD CheckSum;
114 WORD Subsystem;
115 WORD DllCharacteristics;
116 DWORD SizeOfStackReserve;
117 DWORD SizeOfStackCommit;
118 DWORD SizeOfHeapReserve;
119 DWORD SizeOfHeapCommit;
120 DWORD LoaderFlags;
121 DWORD NumberOfRvaAndSizes;
122 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
123 } IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER;
124
125 #define IMAGE_SCN_TYPE_NOLOAD 0x00000002
126 #define IMAGE_SCN_LNK_REMOVE 0x00000800
127 #define IMAGE_SCN_MEM_READ 0x40000000
128 #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
129
130 typedef struct _IMAGE_SECTION_HEADER {
131 BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
132 union {
133 DWORD PhysicalAddress;
134 DWORD VirtualSize;
135 } Misc;
136 DWORD VirtualAddress;
137 DWORD SizeOfRawData;
138 DWORD PointerToRawData;
139 DWORD PointerToRelocations;
140 DWORD PointerToLinenumbers;
141 WORD NumberOfRelocations;
142 WORD NumberOfLinenumbers;
143 DWORD Characteristics;
144 } IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;
145
146 typedef struct _IMAGE_BASE_RELOCATION {
147 DWORD VirtualAddress;
148 DWORD SizeOfBlock;
149 } IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION;
150
151
152 typedef struct {
153 unsigned short f_magic; /* magic number */
154 unsigned short f_nscns; /* number of sections */
155 unsigned long f_timdat; /* time & date stamp */
156 unsigned long f_symptr; /* file pointer to symtab */
157 unsigned long f_nsyms; /* number of symtab entries */
158 unsigned short f_opthdr; /* sizeof(optional hdr) */
159 unsigned short f_flags; /* flags */
160 } FILHDR;
161
162 typedef struct {
163 char s_name[8]; /* section name */
164 unsigned long s_paddr; /* physical address, aliased s_nlib */
165 unsigned long s_vaddr; /* virtual address */
166 unsigned long s_size; /* section size */
167 unsigned long s_scnptr; /* file ptr to raw data for section */
168 unsigned long s_relptr; /* file ptr to relocation */
169 unsigned long s_lnnoptr; /* file ptr to line numbers */
170 unsigned short s_nreloc; /* number of relocation entries */
171 unsigned short s_nlnno; /* number of line number entries */
172 unsigned long s_flags; /* flags */
173 } SCNHDR;
174 #pragma pack(pop)
175
176 typedef struct _SYMBOLFILE_HEADER {
177 unsigned long SymbolsOffset;
178 unsigned long SymbolsLength;
179 unsigned long StringsOffset;
180 unsigned long StringsLength;
181 } SYMBOLFILE_HEADER, *PSYMBOLFILE_HEADER;
182
183 typedef struct _STAB_ENTRY {
184 unsigned long n_strx; /* index into string table of name */
185 unsigned char n_type; /* type of symbol */
186 unsigned char n_other; /* misc info (usually empty) */
187 unsigned short n_desc; /* description field */
188 unsigned long n_value; /* value of symbol */
189 } STAB_ENTRY, *PSTAB_ENTRY;
190
191 #define N_FUN 0x24
192 #define N_SLINE 0x44
193 #define N_SO 0x64
194
195 /* COFF symbol table */
196
197 #define E_SYMNMLEN 8 /* # characters in a symbol name */
198 #define E_FILNMLEN 14 /* # characters in a file name */
199 #define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
200
201 #define N_BTMASK (0xf)
202 #define N_TMASK (0x30)
203 #define N_BTSHFT (4)
204 #define N_TSHIFT (2)
205
206 /* derived types, in e_type */
207 #define DT_NON (0) /* no derived type */
208 #define DT_PTR (1) /* pointer */
209 #define DT_FCN (2) /* function */
210 #define DT_ARY (3) /* array */
211
212 #define BTYPE(x) ((x) & N_BTMASK)
213
214 #define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT))
215 #define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT))
216 #define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT))
217 #define ISTAG(x) ((x)==C_STRTAG||(x)==C_UNTAG||(x)==C_ENTAG)
218 #define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK))
219
220 #define C_EFCN 0xff /* physical end of function */
221 #define C_NULL 0
222 #define C_AUTO 1 /* automatic variable */
223 #define C_EXT 2 /* external symbol */
224 #define C_STAT 3 /* static */
225 #define C_REG 4 /* register variable */
226 #define C_EXTDEF 5 /* external definition */
227 #define C_LABEL 6 /* label */
228 #define C_ULABEL 7 /* undefined label */
229 #define C_MOS 8 /* member of structure */
230 #define C_ARG 9 /* function argument */
231 #define C_STRTAG 10 /* structure tag */
232 #define C_MOU 11 /* member of union */
233 #define C_UNTAG 12 /* union tag */
234 #define C_TPDEF 13 /* type definition */
235 #define C_USTATIC 14 /* undefined static */
236 #define C_ENTAG 15 /* enumeration tag */
237 #define C_MOE 16 /* member of enumeration */
238 #define C_REGPARM 17 /* register parameter */
239 #define C_FIELD 18 /* bit field */
240 #define C_AUTOARG 19 /* auto argument */
241 #define C_LASTENT 20 /* dummy entry (end of block) */
242 #define C_BLOCK 100 /* ".bb" or ".eb" */
243 #define C_FCN 101 /* ".bf" or ".ef" */
244 #define C_EOS 102 /* end of structure */
245 #define C_FILE 103 /* file name */
246 #define C_LINE 104 /* line # reformatted as symbol table entry */
247 #define C_ALIAS 105 /* duplicate tag */
248 #define C_HIDDEN 106 /* ext symbol in dmert public lib */
249
250 #pragma pack(push,1)
251 typedef struct _COFF_SYMENT
252 {
253 union
254 {
255 char e_name[E_SYMNMLEN];
256 struct
257 {
258 unsigned long e_zeroes;
259 unsigned long e_offset;
260 }
261 e;
262 }
263 e;
264 unsigned long e_value;
265 short e_scnum;
266 unsigned short e_type;
267 unsigned char e_sclass;
268 unsigned char e_numaux;
269 } COFF_SYMENT, *PCOFF_SYMENT;
270 #pragma pack(pop)
271
272 typedef struct _ROSSYM_ENTRY {
273 ULONG_PTR Address;
274 ULONG FunctionOffset;
275 ULONG FileOffset;
276 ULONG SourceLine;
277 } ROSSYM_ENTRY, *PROSSYM_ENTRY;
278
279 #define ROUND_UP(N, S) (((N) + (S) - 1) & ~((S) - 1))
280
281 char* convert_path(char* origpath)
282 {
283 char* newpath;
284 int i;
285
286 newpath = strdup(origpath);
287
288 i = 0;
289 while (newpath[i] != 0)
290 {
291 #ifdef UNIX_PATHS
292 if (newpath[i] == '\\')
293 {
294 newpath[i] = '/';
295 }
296 #else
297 #ifdef DOS_PATHS
298 if (newpath[i] == '/')
299 {
300 newpath[i] = '\\';
301 }
302 #endif
303 #endif
304 i++;
305 }
306 return(newpath);
307 }
308
309 static int
310 CompareSymEntry(const PROSSYM_ENTRY SymEntry1, const PROSSYM_ENTRY SymEntry2)
311 {
312 if (SymEntry1->Address < SymEntry2->Address)
313 {
314 return -1;
315 }
316
317 if (SymEntry2->Address < SymEntry1->Address)
318 {
319 return +1;
320 }
321
322 return 0;
323 }
324
325 static int
326 GetStabInfo(void *FileData, PIMAGE_FILE_HEADER PEFileHeader,
327 PIMAGE_SECTION_HEADER PESectionHeaders,
328 ULONG *StabSymbolsLength, void **StabSymbolsBase,
329 ULONG *StabStringsLength, void **StabStringsBase)
330 {
331 ULONG Idx;
332
333 /* Load .stab and .stabstr sections if available */
334 *StabSymbolsBase = NULL;
335 *StabSymbolsLength = 0;
336 *StabStringsBase = NULL;
337 *StabStringsLength = 0;
338
339 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
340 {
341 /* printf("section: '%.08s'\n", PESectionHeaders[Idx].Name); */
342 if ((strncmp((char*)PESectionHeaders[Idx].Name, ".stab", 5) == 0)
343 && (PESectionHeaders[Idx].Name[5] == 0))
344 {
345 /* printf(".stab section found. Size %d\n",
346 PESectionHeaders[Idx].SizeOfRawData); */
347
348 *StabSymbolsLength = PESectionHeaders[Idx].SizeOfRawData;
349 *StabSymbolsBase = (void *)((char *) FileData + PESectionHeaders[Idx].PointerToRawData);
350 }
351
352 if (strncmp((char*)PESectionHeaders[Idx].Name, ".stabstr", 8) == 0)
353 {
354 /* printf(".stabstr section found. Size %d\n",
355 PESectionHeaders[Idx].SizeOfRawData); */
356
357 *StabStringsLength = PESectionHeaders[Idx].SizeOfRawData;
358 *StabStringsBase = (void *)((char *) FileData + PESectionHeaders[Idx].PointerToRawData);
359 }
360 }
361
362 return 0;
363 }
364
365 static int
366 GetCoffInfo(void *FileData, PIMAGE_FILE_HEADER PEFileHeader,
367 PIMAGE_SECTION_HEADER PESectionHeaders,
368 ULONG *CoffSymbolsLength, void **CoffSymbolsBase,
369 ULONG *CoffStringsLength, void **CoffStringsBase)
370 {
371
372 if (0 == PEFileHeader->PointerToSymbolTable || 0 == PEFileHeader->NumberOfSymbols)
373 {
374 /* No COFF symbol table */
375 *CoffSymbolsLength = 0;
376 *CoffStringsLength = 0;
377 }
378 else
379 {
380 *CoffSymbolsLength = PEFileHeader->NumberOfSymbols * sizeof(COFF_SYMENT);
381 *CoffSymbolsBase = (void *)((char *) FileData + PEFileHeader->PointerToSymbolTable);
382 *CoffStringsLength = *((ULONG *) ((char *) *CoffSymbolsBase + *CoffSymbolsLength));
383 *CoffStringsBase = (void *)((char *) *CoffSymbolsBase + *CoffSymbolsLength);
384 }
385
386 return 0;
387 }
388
389 static ULONG
390 FindOrAddString(char *StringToFind, ULONG *StringsLength, void *StringsBase)
391 {
392 char *Search, *End;
393
394 Search = (char *) StringsBase;
395 End = Search + *StringsLength;
396
397 while (Search < End)
398 {
399 if (0 == strcmp(Search, StringToFind))
400 {
401 return Search - (char *) StringsBase;
402 }
403 Search += strlen(Search) + 1;
404 }
405
406 strcpy(Search, StringToFind);
407 *StringsLength += strlen(StringToFind) + 1;
408
409 return Search - (char *) StringsBase;
410 }
411
412 static int
413 ConvertStabs(ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase,
414 ULONG *StringsLength, void *StringsBase,
415 ULONG StabSymbolsLength, void *StabSymbolsBase,
416 ULONG StabStringsLength, void *StabStringsBase,
417 ULONG_PTR ImageBase, PIMAGE_FILE_HEADER PEFileHeader,
418 PIMAGE_SECTION_HEADER PESectionHeaders)
419 {
420 PSTAB_ENTRY StabEntry;
421 ULONG Count, i;
422 ULONG_PTR Address, LastFunctionAddress;
423 int First;
424 char *Name;
425 char FuncName[256];
426
427 StabEntry = StabSymbolsBase;
428 Count = StabSymbolsLength / sizeof(STAB_ENTRY);
429 *SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY));
430 if (NULL == *SymbolsBase)
431 {
432 fprintf(stderr, "Failed to allocate memory for converted .stab symbols\n");
433 return 1;
434 }
435 *SymbolsCount = 0;
436
437 LastFunctionAddress = 0;
438 First = 1;
439 for (i = 0; i < Count; i++)
440 {
441 switch (StabEntry[i].n_type)
442 {
443 case N_SO:
444 Name = (char *) StabStringsBase + StabEntry[i].n_strx;
445 if (StabStringsLength < StabEntry[i].n_strx
446 ||'\0' == *Name || '/' == Name[strlen(Name) - 1]
447 || '\\' == Name[strlen(Name) - 1]
448 || StabEntry[i].n_value < ImageBase)
449 {
450 continue;
451 }
452 Address = StabEntry[i].n_value - ImageBase;
453 if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
454 {
455 (*SymbolsCount)++;
456 }
457 (*SymbolsBase)[*SymbolsCount].Address = Address;
458 (*SymbolsBase)[*SymbolsCount].FileOffset = FindOrAddString((char *) StabStringsBase
459 + StabEntry[i].n_strx,
460 StringsLength,
461 StringsBase);
462 (*SymbolsBase)[*SymbolsCount].FunctionOffset = 0;
463 (*SymbolsBase)[*SymbolsCount].SourceLine = 0;
464 LastFunctionAddress = 0;
465 break;
466 case N_FUN:
467 if (0 == StabEntry[i].n_desc || StabEntry[i].n_value < ImageBase) /* line # 0 isn't valid */
468 {
469 continue;
470 }
471 Address = StabEntry[i].n_value - ImageBase;
472 if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
473 {
474 (*SymbolsCount)++;
475 (*SymbolsBase)[*SymbolsCount].FileOffset = (*SymbolsBase)[*SymbolsCount - 1].FileOffset;
476 }
477 (*SymbolsBase)[*SymbolsCount].Address = Address;
478 if (sizeof(FuncName) <= strlen((char *) StabStringsBase + StabEntry[i].n_strx))
479 {
480 free(*SymbolsBase);
481 fprintf(stderr, "Function name too long\n");
482 return 1;
483 }
484 strcpy(FuncName, (char *) StabStringsBase + StabEntry[i].n_strx);
485 Name = strchr(FuncName, ':');
486 if (NULL != Name)
487 {
488 *Name = '\0';
489 }
490 (*SymbolsBase)[*SymbolsCount].FunctionOffset = FindOrAddString(FuncName,
491 StringsLength,
492 StringsBase);
493 (*SymbolsBase)[*SymbolsCount].SourceLine = 0;
494 LastFunctionAddress = Address;
495 break;
496 case N_SLINE:
497 if (0 == LastFunctionAddress)
498 {
499 Address = StabEntry[i].n_value - ImageBase;
500 }
501 else
502 {
503 Address = LastFunctionAddress + StabEntry[i].n_value;
504 }
505 if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
506 {
507 (*SymbolsCount)++;
508 (*SymbolsBase)[*SymbolsCount].FileOffset = (*SymbolsBase)[*SymbolsCount - 1].FileOffset;
509 (*SymbolsBase)[*SymbolsCount].FunctionOffset = (*SymbolsBase)[*SymbolsCount - 1].FunctionOffset;
510 }
511 (*SymbolsBase)[*SymbolsCount].Address = Address;
512 (*SymbolsBase)[*SymbolsCount].SourceLine = StabEntry[i].n_desc;
513 break;
514 default:
515 continue;
516 }
517 First = 0;
518 }
519 (*SymbolsCount)++;
520
521 qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
522
523 return 0;
524 }
525
526 static int
527 ConvertCoffs(ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase,
528 ULONG *StringsLength, void *StringsBase,
529 ULONG CoffSymbolsLength, void *CoffSymbolsBase,
530 ULONG CoffStringsLength, void *CoffStringsBase,
531 ULONG_PTR ImageBase, PIMAGE_FILE_HEADER PEFileHeader,
532 PIMAGE_SECTION_HEADER PESectionHeaders)
533 {
534 ULONG Count, i;
535 PCOFF_SYMENT CoffEntry;
536 char FuncName[256];
537 char *p;
538
539 CoffEntry = (PCOFF_SYMENT) CoffSymbolsBase;
540 Count = CoffSymbolsLength / sizeof(COFF_SYMENT);
541 *SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY));
542 if (NULL == *SymbolsBase)
543 {
544 fprintf(stderr, "Unable to allocate memory for converted COFF symbols\n");
545 return 1;
546 }
547 *SymbolsCount = 0;
548
549 for (i = 0; i < Count; i++)
550 {
551 if (ISFCN(CoffEntry[i].e_type) || C_EXT == CoffEntry[i].e_sclass)
552 {
553 (*SymbolsBase)[*SymbolsCount].Address = CoffEntry[i].e_value;
554 if (0 < CoffEntry[i].e_scnum)
555 {
556 if (PEFileHeader->NumberOfSections < CoffEntry[i].e_scnum)
557 {
558 free(*SymbolsBase);
559 fprintf(stderr, "Invalid section number %d in COFF symbols (only %d sections present)\n",
560 CoffEntry[i].e_scnum, PEFileHeader->NumberOfSections);
561 return 1;
562 }
563 (*SymbolsBase)[*SymbolsCount].Address += PESectionHeaders[CoffEntry[i].e_scnum - 1].VirtualAddress;
564 }
565 (*SymbolsBase)[*SymbolsCount].FileOffset = 0;
566 if (0 == CoffEntry[i].e.e.e_zeroes)
567 {
568 if (sizeof(FuncName) <= strlen((char *) CoffStringsBase + CoffEntry[i].e.e.e_offset))
569 {
570 free(*SymbolsBase);
571 fprintf(stderr, "Function name too long\n");
572 return 1;
573 }
574 strcpy(FuncName, (char *) CoffStringsBase + CoffEntry[i].e.e.e_offset);
575 }
576 else
577 {
578 memcpy(FuncName, CoffEntry[i].e.e_name, E_SYMNMLEN);
579 FuncName[E_SYMNMLEN] = '\0';
580 }
581
582 /* Name demangling: stdcall */
583 p = strrchr(FuncName, '@');
584 if (NULL != p)
585 {
586 *p = '\0';
587 }
588 p = ('_' == FuncName[0] || '@' == FuncName[0] ? FuncName + 1 : FuncName);
589 (*SymbolsBase)[*SymbolsCount].FunctionOffset = FindOrAddString(p,
590 StringsLength,
591 StringsBase);
592 (*SymbolsBase)[*SymbolsCount].SourceLine = 0;
593 (*SymbolsCount)++;
594 }
595 i += CoffEntry[i].e_numaux;
596 }
597
598 qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
599
600 return 0;
601 }
602
603 static int
604 MergeStabsAndCoffs(ULONG *MergedSymbolCount, PROSSYM_ENTRY *MergedSymbols,
605 ULONG StabSymbolsCount, PROSSYM_ENTRY StabSymbols,
606 ULONG CoffSymbolsCount, PROSSYM_ENTRY CoffSymbols)
607 {
608 ULONG StabIndex, j;
609 ULONG CoffIndex;
610 ULONG_PTR StabFunctionStartAddress;
611 ULONG StabFunctionStringOffset, NewStabFunctionStringOffset;
612
613 *MergedSymbols = malloc(StabSymbolsCount * sizeof(ROSSYM_ENTRY));
614 if (NULL == *MergedSymbols)
615 {
616 fprintf(stderr, "Unable to allocate memory for merged symbols\n");
617 return 1;
618 }
619 *MergedSymbolCount = 0;
620
621 StabFunctionStartAddress = 0;
622 StabFunctionStringOffset = 0;
623 CoffIndex = 0;
624 for (StabIndex = 0; StabIndex < StabSymbolsCount; StabIndex++)
625 {
626 (*MergedSymbols)[*MergedSymbolCount] = StabSymbols[StabIndex];
627 for (j = StabIndex + 1;
628 j < StabSymbolsCount && StabSymbols[j].Address == StabSymbols[StabIndex].Address;
629 j++)
630 {
631 if (0 != StabSymbols[j].FileOffset && 0 == (*MergedSymbols)[*MergedSymbolCount].FileOffset)
632 {
633 (*MergedSymbols)[*MergedSymbolCount].FileOffset = StabSymbols[j].FileOffset;
634 }
635 if (0 != StabSymbols[j].FunctionOffset && 0 == (*MergedSymbols)[*MergedSymbolCount].FunctionOffset)
636 {
637 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = StabSymbols[j].FunctionOffset;
638 }
639 if (0 != StabSymbols[j].SourceLine && 0 == (*MergedSymbols)[*MergedSymbolCount].SourceLine)
640 {
641 (*MergedSymbols)[*MergedSymbolCount].SourceLine = StabSymbols[j].SourceLine;
642 }
643 }
644 StabIndex = j - 1;
645 while (CoffIndex < CoffSymbolsCount
646 && CoffSymbols[CoffIndex + 1].Address <= (*MergedSymbols)[*MergedSymbolCount].Address)
647 {
648 CoffIndex++;
649 }
650 NewStabFunctionStringOffset = (*MergedSymbols)[*MergedSymbolCount].FunctionOffset;
651 if (CoffSymbols[CoffIndex].Address < (*MergedSymbols)[*MergedSymbolCount].Address
652 && StabFunctionStartAddress < CoffSymbols[CoffIndex].Address
653 && 0 != CoffSymbols[CoffIndex].FunctionOffset)
654 {
655 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = CoffSymbols[CoffIndex].FunctionOffset;
656 }
657 if (StabFunctionStringOffset != NewStabFunctionStringOffset)
658 {
659 StabFunctionStartAddress = (*MergedSymbols)[*MergedSymbolCount].Address;
660 }
661 StabFunctionStringOffset = NewStabFunctionStringOffset;
662 (*MergedSymbolCount)++;
663 }
664
665 return 0;
666 }
667
668 static PIMAGE_SECTION_HEADER
669 FindSectionForRVA(DWORD RVA, unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
670 {
671 unsigned Section;
672
673 for (Section = 0; Section < NumberOfSections; Section++)
674 {
675 if (SectionHeaders[Section].VirtualAddress <= RVA &&
676 RVA < SectionHeaders[Section].VirtualAddress + SectionHeaders[Section].Misc.VirtualSize)
677 {
678 return SectionHeaders + Section;
679 }
680 }
681
682 return NULL;
683 }
684
685 static int
686 IncludeRelocationsForSection(PIMAGE_SECTION_HEADER SectionHeader)
687 {
688 static char *BlacklistedSections[] =
689 {
690 ".idata",
691 ".reloc"
692 };
693 char SectionName[IMAGE_SIZEOF_SHORT_NAME];
694 unsigned i;
695
696 if (0 != (SectionHeader->Characteristics & IMAGE_SCN_LNK_REMOVE))
697 {
698 return 0;
699 }
700
701 for (i = 0; i < sizeof(BlacklistedSections) / sizeof(BlacklistedSections[0]); i++)
702 {
703 strncpy(SectionName, BlacklistedSections[i], IMAGE_SIZEOF_SHORT_NAME);
704 if (0 == memcmp(SectionName, SectionHeader->Name, IMAGE_SIZEOF_SHORT_NAME))
705 {
706 return 0;
707 }
708 }
709
710 return 1;
711 }
712
713 static int
714 ProcessRelocations(ULONG *ProcessedRelocsLength, void **ProcessedRelocs,
715 void *RawData, PIMAGE_OPTIONAL_HEADER OptHeader,
716 unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
717 {
718 PIMAGE_SECTION_HEADER RelocSectionHeader, TargetSectionHeader;
719 PIMAGE_BASE_RELOCATION BaseReloc, End, AcceptedRelocs;
720 int Found;
721
722 if (OptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC
723 || 0 == OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
724 {
725 /* No relocation entries */
726 *ProcessedRelocsLength = 0;
727 *ProcessedRelocs = NULL;
728 return 0;
729 }
730
731 RelocSectionHeader = FindSectionForRVA(OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
732 NumberOfSections, SectionHeaders);
733 if (NULL == RelocSectionHeader)
734 {
735 fprintf(stderr, "Can't find section header for relocation data\n");
736 return 1;
737 }
738
739 *ProcessedRelocs = malloc(RelocSectionHeader->SizeOfRawData);
740 if (NULL == *ProcessedRelocs)
741 {
742 fprintf(stderr, "Failed to allocate %lu bytes for relocations\n", RelocSectionHeader->SizeOfRawData);
743 return 1;
744 }
745 *ProcessedRelocsLength = 0;
746
747 BaseReloc = (PIMAGE_BASE_RELOCATION) ((char *) RawData
748 + RelocSectionHeader->PointerToRawData
749 + (OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress -
750 RelocSectionHeader->VirtualAddress));
751 End = (PIMAGE_BASE_RELOCATION) ((char *) BaseReloc
752 + OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
753
754 while (BaseReloc < End && 0 < BaseReloc->SizeOfBlock)
755 {
756 TargetSectionHeader = FindSectionForRVA(BaseReloc->VirtualAddress, NumberOfSections,
757 SectionHeaders);
758 if (NULL != TargetSectionHeader && IncludeRelocationsForSection(TargetSectionHeader))
759 {
760 AcceptedRelocs = *ProcessedRelocs;
761 Found = 0;
762 while (AcceptedRelocs < (PIMAGE_BASE_RELOCATION) ((char *) *ProcessedRelocs +
763 *ProcessedRelocsLength)
764 && ! Found)
765 {
766 Found = BaseReloc->SizeOfBlock == AcceptedRelocs->SizeOfBlock
767 && 0 == memcmp(BaseReloc, AcceptedRelocs, AcceptedRelocs->SizeOfBlock);
768 AcceptedRelocs= (PIMAGE_BASE_RELOCATION) ((char *) AcceptedRelocs +
769 AcceptedRelocs->SizeOfBlock);
770 }
771 if (! Found)
772 {
773 memcpy((char *) *ProcessedRelocs + *ProcessedRelocsLength,
774 BaseReloc, BaseReloc->SizeOfBlock);
775 *ProcessedRelocsLength += BaseReloc->SizeOfBlock;
776 }
777 }
778 BaseReloc = (PIMAGE_BASE_RELOCATION)((char *) BaseReloc + BaseReloc->SizeOfBlock);
779 }
780
781 return 0;
782 }
783
784 static int
785 CreateOutputFile(FILE *OutFile, void *InData,
786 PIMAGE_DOS_HEADER InDosHeader, PIMAGE_FILE_HEADER InFileHeader,
787 PIMAGE_OPTIONAL_HEADER InOptHeader, PIMAGE_SECTION_HEADER InSectionHeaders,
788 ULONG RosSymLength, void *RosSymSection)
789 {
790 ULONG StartOfRawData;
791 unsigned Section;
792 void *OutHeader, *ProcessedRelocs, *PaddedRosSym, *Data;
793 PIMAGE_DOS_HEADER OutDosHeader;
794 PIMAGE_FILE_HEADER OutFileHeader;
795 PIMAGE_OPTIONAL_HEADER OutOptHeader;
796 PIMAGE_SECTION_HEADER OutSectionHeaders, CurrentSectionHeader;
797 DWORD CheckSum;
798 ULONG Length, i;
799 ULONG ProcessedRelocsLength;
800 ULONG RosSymOffset, RosSymFileLength;
801 int InRelocSectionIndex;
802 PIMAGE_SECTION_HEADER OutRelocSection;
803
804 StartOfRawData = 0;
805 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
806 {
807 if ((0 == StartOfRawData
808 || InSectionHeaders[Section].PointerToRawData < StartOfRawData)
809 && 0 != InSectionHeaders[Section].PointerToRawData
810 && 0 == (InSectionHeaders[Section].Characteristics & IMAGE_SCN_LNK_REMOVE))
811 {
812 StartOfRawData = InSectionHeaders[Section].PointerToRawData;
813 }
814 }
815 OutHeader = malloc(StartOfRawData);
816 if (NULL == OutHeader)
817 {
818 fprintf(stderr, "Failed to allocate %lu bytes for output file header\n", StartOfRawData);
819 return 1;
820 }
821 memset(OutHeader, '\0', StartOfRawData);
822
823 OutDosHeader = (PIMAGE_DOS_HEADER) OutHeader;
824 memcpy(OutDosHeader, InDosHeader, InDosHeader->e_lfanew + sizeof(ULONG));
825
826 OutFileHeader = (PIMAGE_FILE_HEADER)((char *) OutHeader + OutDosHeader->e_lfanew + sizeof(ULONG));
827 memcpy(OutFileHeader, InFileHeader, sizeof(IMAGE_FILE_HEADER));
828 OutFileHeader->PointerToSymbolTable = 0;
829 OutFileHeader->NumberOfSymbols = 0;
830 OutFileHeader->Characteristics &= ~(IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_LOCAL_SYMS_STRIPPED |
831 IMAGE_FILE_DEBUG_STRIPPED);
832
833 OutOptHeader = (PIMAGE_OPTIONAL_HEADER)(OutFileHeader + 1);
834 memcpy(OutOptHeader, InOptHeader, sizeof(IMAGE_OPTIONAL_HEADER));
835 OutOptHeader->CheckSum = 0;
836
837 OutSectionHeaders = (PIMAGE_SECTION_HEADER)((char *) OutOptHeader + OutFileHeader->SizeOfOptionalHeader);
838
839 if (ProcessRelocations(&ProcessedRelocsLength, &ProcessedRelocs, InData, InOptHeader,
840 InFileHeader->NumberOfSections, InSectionHeaders))
841 {
842 return 1;
843 }
844 if (InOptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC
845 || 0 == InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
846 {
847 InRelocSectionIndex = -1;
848 }
849 else
850 {
851 InRelocSectionIndex = FindSectionForRVA(InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
852 InFileHeader->NumberOfSections, InSectionHeaders) - InSectionHeaders;
853 }
854
855 OutFileHeader->NumberOfSections = 0;
856 CurrentSectionHeader = OutSectionHeaders;
857 OutOptHeader->SizeOfImage = 0;
858 RosSymOffset = 0;
859 OutRelocSection = NULL;
860 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
861 {
862 if (0 == (InSectionHeaders[Section].Characteristics & IMAGE_SCN_LNK_REMOVE))
863 {
864 *CurrentSectionHeader = InSectionHeaders[Section];
865 CurrentSectionHeader->PointerToLinenumbers = 0;
866 CurrentSectionHeader->NumberOfLinenumbers = 0;
867 if (OutOptHeader->SizeOfImage < CurrentSectionHeader->VirtualAddress +
868 CurrentSectionHeader->Misc.VirtualSize)
869 {
870 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress +
871 CurrentSectionHeader->Misc.VirtualSize,
872 OutOptHeader->SectionAlignment);
873 }
874 if (RosSymOffset < CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData)
875 {
876 RosSymOffset = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData;
877 }
878 if (Section == InRelocSectionIndex)
879 {
880 OutRelocSection = CurrentSectionHeader;
881 }
882 (OutFileHeader->NumberOfSections) ++;
883 CurrentSectionHeader++;
884 }
885 }
886
887 if (OutRelocSection == CurrentSectionHeader - 1)
888 {
889 OutOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = ProcessedRelocsLength;
890 if (OutOptHeader->SizeOfImage == OutRelocSection->VirtualAddress +
891 ROUND_UP(OutRelocSection->Misc.VirtualSize,
892 OutOptHeader->SectionAlignment))
893 {
894 OutOptHeader->SizeOfImage = OutRelocSection->VirtualAddress +
895 ROUND_UP(ProcessedRelocsLength,
896 OutOptHeader->SectionAlignment);
897 }
898 OutRelocSection->Misc.VirtualSize = ProcessedRelocsLength;
899 if (RosSymOffset == OutRelocSection->PointerToRawData
900 + OutRelocSection->SizeOfRawData)
901 {
902 RosSymOffset = OutRelocSection->PointerToRawData +
903 ROUND_UP(ProcessedRelocsLength, OutOptHeader->FileAlignment);
904 }
905 OutRelocSection->SizeOfRawData = ROUND_UP(ProcessedRelocsLength,
906 OutOptHeader->FileAlignment);
907 }
908
909 RosSymFileLength = ROUND_UP(RosSymLength, OutOptHeader->FileAlignment);
910 memcpy(CurrentSectionHeader->Name, ".rossym", 8); /* We're lucky: string is exactly 8 bytes long */
911 CurrentSectionHeader->Misc.VirtualSize = RosSymLength;
912 CurrentSectionHeader->VirtualAddress = OutOptHeader->SizeOfImage;
913 CurrentSectionHeader->SizeOfRawData = RosSymFileLength;
914 CurrentSectionHeader->PointerToRawData = RosSymOffset;
915 CurrentSectionHeader->PointerToRelocations = 0;
916 CurrentSectionHeader->PointerToLinenumbers = 0;
917 CurrentSectionHeader->NumberOfRelocations = 0;
918 CurrentSectionHeader->NumberOfLinenumbers = 0;
919 CurrentSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
920 | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_TYPE_NOLOAD;
921 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress +
922 CurrentSectionHeader->Misc.VirtualSize,
923 OutOptHeader->SectionAlignment);
924 (OutFileHeader->NumberOfSections)++;
925
926 PaddedRosSym = malloc(RosSymFileLength);
927 if (NULL == PaddedRosSym)
928 {
929 fprintf(stderr, "Failed to allocate %lu bytes for padded .rossym\n", RosSymFileLength);
930 return 1;
931 }
932 memcpy(PaddedRosSym, RosSymSection, RosSymLength);
933 memset((char *) PaddedRosSym + RosSymLength, '\0', RosSymFileLength - RosSymLength);
934
935 CheckSum = 0;
936 for (i = 0; i < StartOfRawData / 2; i++)
937 {
938 CheckSum += ((unsigned short*) OutHeader)[i];
939 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
940 }
941 Length = StartOfRawData;
942 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
943 {
944 if (OutRelocSection == OutSectionHeaders + Section)
945 {
946 Data = (void *) ProcessedRelocs;
947 }
948 else if (Section + 1 == OutFileHeader->NumberOfSections)
949 {
950 Data = (void *) PaddedRosSym;
951 }
952 else
953 {
954 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
955 }
956 for (i = 0; i < OutSectionHeaders[Section].SizeOfRawData / 2; i++)
957 {
958 CheckSum += ((unsigned short*) Data)[i];
959 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
960 }
961 Length += OutSectionHeaders[Section].SizeOfRawData;
962 }
963 CheckSum += Length;
964 OutOptHeader->CheckSum = CheckSum;
965
966 if (fwrite(OutHeader, 1, StartOfRawData, OutFile) != StartOfRawData)
967 {
968 perror("Error writing output header\n");
969 free(OutHeader);
970 return 1;
971 }
972
973 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
974 {
975 if (0 != OutSectionHeaders[Section].SizeOfRawData)
976 {
977 fseek(OutFile, OutSectionHeaders[Section].PointerToRawData, SEEK_SET);
978 if (OutRelocSection == OutSectionHeaders + Section)
979 {
980 Data = (void *) ProcessedRelocs;
981 }
982 else if (Section + 1 == OutFileHeader->NumberOfSections)
983 {
984 Data = (void *) PaddedRosSym;
985 }
986 else
987 {
988 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
989 }
990 if (fwrite(Data, 1, OutSectionHeaders[Section].SizeOfRawData, OutFile) !=
991 OutSectionHeaders[Section].SizeOfRawData)
992 {
993 perror("Error writing section data\n");
994 free(PaddedRosSym);
995 free(OutHeader);
996 return 1;
997 }
998 }
999 }
1000
1001 free(PaddedRosSym);
1002 free(OutHeader);
1003
1004 return 0;
1005 }
1006
1007 int main(int argc, char* argv[])
1008 {
1009 PSYMBOLFILE_HEADER SymbolFileHeader;
1010 PIMAGE_DOS_HEADER PEDosHeader;
1011 PIMAGE_FILE_HEADER PEFileHeader;
1012 PIMAGE_OPTIONAL_HEADER PEOptHeader;
1013 PIMAGE_SECTION_HEADER PESectionHeaders;
1014 ULONG ImageBase;
1015 void *StabBase;
1016 ULONG StabsLength;
1017 void *StabStringBase;
1018 ULONG StabStringsLength;
1019 void *CoffBase;
1020 ULONG CoffsLength;
1021 void *CoffStringBase;
1022 ULONG CoffStringsLength;
1023 char* path1;
1024 char* path2;
1025 FILE* in;
1026 FILE* out;
1027 int n_in;
1028 void *StringBase;
1029 ULONG StringsLength;
1030 ULONG StabSymbolsCount;
1031 PROSSYM_ENTRY StabSymbols;
1032 ULONG CoffSymbolsCount;
1033 PROSSYM_ENTRY CoffSymbols;
1034 ULONG MergedSymbolsCount;
1035 PROSSYM_ENTRY MergedSymbols;
1036 long FileSize;
1037 void *FileData;
1038 ULONG RosSymLength;
1039 void *RosSymSection;
1040
1041 if (3 != argc)
1042 {
1043 fprintf(stderr, "Usage: rsym <exefile> <symfile>\n");
1044 exit(1);
1045 }
1046
1047 path1 = convert_path(argv[1]);
1048 path2 = convert_path(argv[2]);
1049
1050 in = fopen(path1, "rb");
1051 if (in == NULL)
1052 {
1053 perror("Cannot open input file");
1054 exit(1);
1055 }
1056 fseek(in, 0L, SEEK_END);
1057 FileSize = ftell(in);
1058 fseek(in, 0L, SEEK_SET);
1059 FileData = malloc(FileSize);
1060 if (NULL == FileData)
1061 {
1062 fclose(in);
1063 fprintf(stderr, "Can't allocate %ld bytes to read input file\n", FileSize);
1064 exit(1);
1065 }
1066 n_in = fread(FileData, 1, FileSize, in);
1067 if (n_in != FileSize)
1068 {
1069 perror("Error reading from input file");
1070 free(FileData);
1071 fclose(in);
1072 exit(1);
1073 }
1074 fclose(in);
1075
1076 /* Check if MZ header exists */
1077 PEDosHeader = (PIMAGE_DOS_HEADER) FileData;
1078 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC || PEDosHeader->e_lfanew == 0L)
1079 {
1080 perror("Input file is not a PE image.\n");
1081 free(FileData);
1082 exit(1);
1083 }
1084
1085 /* Locate PE file header */
1086 /* sizeof(ULONG) = sizeof(MAGIC) */
1087 PEFileHeader = (PIMAGE_FILE_HEADER)((char *) FileData + PEDosHeader->e_lfanew + sizeof(ULONG));
1088
1089 /* Locate optional header */
1090 PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
1091 ImageBase = PEOptHeader->ImageBase;
1092
1093 /* Locate PE section headers */
1094 PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *) PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
1095
1096 if (GetStabInfo(FileData, PEFileHeader, PESectionHeaders, &StabsLength, &StabBase,
1097 &StabStringsLength, &StabStringBase))
1098 {
1099 free(FileData);
1100 exit(1);
1101 }
1102
1103 if (GetCoffInfo(FileData, PEFileHeader, PESectionHeaders, &CoffsLength, &CoffBase,
1104 &CoffStringsLength, &CoffStringBase))
1105 {
1106 free(FileData);
1107 exit(1);
1108 }
1109
1110 StringBase = malloc(1 + StabStringsLength + CoffStringsLength +
1111 (CoffsLength / sizeof(ROSSYM_ENTRY)) * (E_SYMNMLEN + 1));
1112 if (NULL == StringBase)
1113 {
1114 free(FileData);
1115 fprintf(stderr, "Failed to allocate memory for strings table\n");
1116 exit(1);
1117 }
1118 /* Make offset 0 into an empty string */
1119 *((char *) StringBase) = '\0';
1120 StringsLength = 1;
1121
1122 if (ConvertStabs(&StabSymbolsCount, &StabSymbols, &StringsLength, StringBase,
1123 StabsLength, StabBase, StabStringsLength, StabStringBase,
1124 ImageBase, PEFileHeader, PESectionHeaders))
1125 {
1126 free(StringBase);
1127 free(FileData);
1128 fprintf(stderr, "Failed to allocate memory for strings table\n");
1129 exit(1);
1130 }
1131
1132 if (ConvertCoffs(&CoffSymbolsCount, &CoffSymbols, &StringsLength, StringBase,
1133 CoffsLength, CoffBase, CoffStringsLength, CoffStringBase,
1134 ImageBase, PEFileHeader, PESectionHeaders))
1135 {
1136 free(StabSymbols);
1137 free(StringBase);
1138 free(FileData);
1139 exit(1);
1140 }
1141
1142 if (MergeStabsAndCoffs(&MergedSymbolsCount, &MergedSymbols,
1143 StabSymbolsCount, StabSymbols,
1144 CoffSymbolsCount, CoffSymbols))
1145 {
1146 free(CoffSymbols);
1147 free(StabSymbols);
1148 free(StringBase);
1149 free(FileData);
1150 exit(1);
1151 }
1152
1153 free(CoffSymbols);
1154 free(StabSymbols);
1155
1156 RosSymLength = sizeof(SYMBOLFILE_HEADER) + MergedSymbolsCount * sizeof(ROSSYM_ENTRY)
1157 + StringsLength;
1158 RosSymSection = malloc(RosSymLength);
1159 if (NULL == RosSymSection)
1160 {
1161 free(MergedSymbols);
1162 free(StringBase);
1163 free(FileData);
1164 fprintf(stderr, "Unable to allocate memory for .rossym section\n");
1165 exit(1);
1166 }
1167 memset(RosSymSection, '\0', RosSymLength);
1168
1169 SymbolFileHeader = (PSYMBOLFILE_HEADER) RosSymSection;
1170 SymbolFileHeader->SymbolsOffset = sizeof(SYMBOLFILE_HEADER);
1171 SymbolFileHeader->SymbolsLength = MergedSymbolsCount * sizeof(ROSSYM_ENTRY);
1172 SymbolFileHeader->StringsOffset = SymbolFileHeader->SymbolsOffset + SymbolFileHeader->SymbolsLength;
1173 SymbolFileHeader->StringsLength = StringsLength;
1174
1175 memcpy((char *) RosSymSection + SymbolFileHeader->SymbolsOffset, MergedSymbols,
1176 SymbolFileHeader->SymbolsLength);
1177 memcpy((char *) RosSymSection + SymbolFileHeader->StringsOffset, StringBase,
1178 SymbolFileHeader->StringsLength);
1179
1180 free(MergedSymbols);
1181 free(StringBase);
1182
1183 out = fopen(path2, "wb");
1184 if (out == NULL)
1185 {
1186 perror("Cannot open output file");
1187 free(RosSymSection);
1188 free(FileData);
1189 exit(1);
1190 }
1191
1192 if (CreateOutputFile(out, FileData, PEDosHeader, PEFileHeader, PEOptHeader,
1193 PESectionHeaders, RosSymLength, RosSymSection))
1194 {
1195 fclose(out);
1196 free(RosSymSection);
1197 free(FileData);
1198 exit(1);
1199 }
1200
1201 fclose(out);
1202 free(RosSymSection);
1203 free(FileData);
1204
1205 return 0;
1206 }
1207
1208 /* EOF */