1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "rsym.h"
6 #include "rsym64.h"
7 #include "dwarf2.h"
8
9 char DoPrint = 0;
10 ULONG g_ehframep;
11
12 #define DPRINT if(DoPrint) printf
13
14 struct {char *name; char regnt;} regs[] =
15 { {"rax", REG_RAX}, {"rdx", REG_RDX}, {"rcx", REG_RCX}, {"rbx", REG_RBX},
16 {"rsi", REG_RSI}, {"rdi", REG_RDI}, {"rbp", REG_RBP}, {"rsp", REG_RSP},
17 {"r8", REG_R8}, {"r9", REG_R9}, {"r10", REG_R10}, {"r11", REG_R11},
18 {"r12", REG_R12}, {"r13", REG_R13}, {"r14", REG_R14}, {"r15", REG_R15},
19 {"xmm0", REG_XMM0}, {"xmm1", REG_XMM1}, {"xmm2", REG_XMM2}, {"xmm3", REG_XMM3},
20 {"xmm4", REG_XMM4}, {"xmm5", REG_XMM5}, {"xmm6", REG_XMM6}, {"xmm7", REG_XMM7},
21 {"xmm8", REG_XMM8}, {"xmm9", REG_XMM9}, {"xmm10",REG_XMM10},{"xmm11",REG_XMM11},
22 {"xmm12",REG_XMM12},{"xmm13",REG_XMM13},{"xmm14",REG_XMM14},{"xmm15",REG_XMM15},
23 // "st0", "st1", "st2", "st3",
24 // "st4", "st5", "st6", "st7",
25 // "mm0", "mm1", "mm2", "mm3",
26 // "mm4", "mm5", "mm6", "mm7"
27 };
28
29 /** Functions for DWARF2 ******************************************************/
30
31 unsigned long
DwDecodeUleb128(unsigned long * pResult,char * pc)32 DwDecodeUleb128(unsigned long *pResult, char *pc)
33 {
34 unsigned long ulResult = 0;
35 unsigned long ulShift = 0;
36 unsigned char current;
37 unsigned long ulSize = 0;
38
39 do
40 {
41 current = pc[ulSize];
42 ulSize++;
43 ulResult |= (current & 0x7f) << ulShift;
44 ulShift += 7;
45 }
46 while (current & 0x80);
47
48 *pResult = ulResult;
49 return ulSize;
50 }
51
52 unsigned long
DwDecodeSleb128(long * pResult,char * pc)53 DwDecodeSleb128(long *pResult, char *pc)
54 {
55 long lResult = 0;
56 unsigned long ulShift = 0;
57 unsigned char current;
58 unsigned long ulSize = 0;
59
60 do
61 {
62 current = pc[ulSize];
63 ulSize++;
64 lResult |= (current & 0x7f) << ulShift;
65 ulShift += 7;
66 }
67 while (current & 0x80);
68
69 if (current & 0x40)
70 lResult |= - (1 << (ulShift));
71
72 *pResult = lResult;
73
74 return ulSize;
75 }
76
77 unsigned long
DwDecodeCie(PDW2CIE Cie,char * pc)78 DwDecodeCie(PDW2CIE Cie, char *pc)
79 {
80 Cie->Length = *(ULONG*)pc;
81 Cie->Next = pc + 4 + Cie->Length;
82 Cie->CieId = *(ULONG*)(pc + 4);
83 Cie->Version = pc[8];
84 Cie->AugString = pc + 9;
85 Cie->AugStringLength = strlen(Cie->AugString);
86 pc = Cie->AugString + Cie->AugStringLength + 1;
87 pc += DwDecodeUleb128(&Cie->CodeAlign, pc);
88 pc += DwDecodeSleb128(&Cie->DataAlign, pc);
89 pc += DwDecodeUleb128(&Cie->ReturnAddressRegister, pc);
90 pc += DwDecodeUleb128(&Cie->AugLength, pc);
91 Cie->AugData = pc;
92 pc += Cie->AugLength;
93 Cie->Instructions = pc;
94
95 return Cie->Length + 4;
96 }
97
98 unsigned long
DwDecodeFde(PDW2FDE Fde,char * pc)99 DwDecodeFde(PDW2FDE Fde, char *pc)
100 {
101 Fde->Length = *(ULONG*)pc;
102 Fde->Next = pc + 4 + Fde->Length;
103 Fde->CiePointer = pc + 4 - *(ULONG*)(pc + 4);
104 Fde->PcBegin = *(ULONG*)(pc + 8);
105 Fde->PcRange = *(ULONG*)(pc + 12);
106 pc += 16;
107 pc += DwDecodeUleb128(&Fde->AugLength, pc);
108 Fde->AugData = pc;
109 Fde->Instructions = Fde->AugData + Fde->AugLength;
110
111 return Fde->Length + 4;
112 }
113
114 unsigned long
DwExecIntruction(PDW2CFSTATE State,char * pc)115 DwExecIntruction(PDW2CFSTATE State, char *pc)
116 {
117 unsigned char Code;
118 unsigned long Length;
119 unsigned long PrevFramePtr = State->FramePtr;
120
121 State->Scope = 0;
122 State->IsUwop = 0;
123 State->Code = Code = *pc;
124 Length = 1;
125 if ((Code & 0xc0) == DW_CFA_advance_loc)
126 {
127 State->Code = DW_CFA_advance_loc;
128 State->Location += Code & 0x3f;
129 }
130 else if ((Code & 0xc0) == DW_CFA_offset)
131 {
132 State->Code = DW_CFA_offset;
133 State->Reg = Code & 0x3f;
134 Length += DwDecodeUleb128((unsigned long*)&State->Offset, pc + 1);
135 State->Offset *= 8; // fixme data alignment
136 State->IsUwop = 1;
137 }
138 else if ((Code & 0xc0) == DW_CFA_restore)
139 {
140 State->Code = DW_CFA_restore;
141 State->Reg = Code & 0x3f;
142 }
143 else switch (Code)
144 {
145 case DW_CFA_nop:
146 break;
147 case DW_CFA_set_loc:
148 Length = 9; // address
149 State->Location = *(DWORD*)(pc + 1);
150 break;
151 case DW_CFA_advance_loc1:
152 Length = 2;
153 State->Location += pc[1];
154 break;
155 case DW_CFA_advance_loc2:
156 Length = 3;
157 // printf("Found a DW_CFA_advance_loc2 : 0x%lx ->", *(WORD*)(pc + 1));
158 State->Location += *(WORD*)(pc + 1);
159 // printf(" 0x%lx\n", State->Location);
160 break;
161 case DW_CFA_advance_loc4:
162 Length = 5;
163 // printf("Found a DW_CFA_advance_loc4 : 0x%lx ->", *(DWORD*)(pc + 1));
164 State->Location += *(DWORD*)(pc + 1);
165 // printf(" 0x%lx\n", State->Location);
166 break;
167 case DW_CFA_offset_extended:
168 Length += DwDecodeUleb128(&State->Reg, pc + Length);
169 Length += DwDecodeUleb128((unsigned long*)&State->Offset, pc + Length);
170 State->IsUwop = 1;
171 break;
172 case DW_CFA_offset_extended_sf:
173 Length += DwDecodeUleb128(&State->Reg, pc + Length);
174 Length += DwDecodeSleb128(&State->Offset, pc + Length);
175 State->IsUwop = 1;
176 break;
177 case DW_CFA_restore_extended:
178 Length += DwDecodeUleb128(&State->Reg, pc + Length);
179 break;
180 case DW_CFA_undefined:
181 Length += DwDecodeUleb128(&State->Reg, pc + Length);
182 break;
183 case DW_CFA_same_value:
184 Length += DwDecodeUleb128(&State->Reg, pc + Length);
185 break;
186 case DW_CFA_register:
187 Length += DwDecodeUleb128(&State->Reg, pc + Length);
188 Length += DwDecodeUleb128(&State->Reg2, pc + Length);
189 break;
190 case DW_CFA_remember_state:
191 break;
192 case DW_CFA_restore_state:
193 break;
194 case DW_CFA_def_cfa:
195 Length += DwDecodeUleb128(&State->Reg, pc + Length);
196 Length += DwDecodeUleb128((unsigned long*)&State->FramePtr, pc + Length);
197 State->IsUwop = 1;
198 break;
199 case DW_CFA_def_cfa_register:
200 Length += DwDecodeUleb128(&State->Reg, pc + Length);
201 break;
202 case DW_CFA_def_cfa_offset:
203 Length += DwDecodeUleb128((unsigned long*)&State->FramePtr, pc + Length);
204 State->IsUwop = 1;
205 break;
206 case DW_CFA_def_cfa_sf:
207 Length += DwDecodeUleb128(&State->Reg, pc + Length);
208 Length += DwDecodeSleb128(&State->FramePtr, pc + Length);
209 State->FramePtr *= 8; // data alignment
210 State->IsUwop = 1;
211 break;
212 case DW_CFA_GNU_args_size:
213 {
214 unsigned long argsize;
215 printf("Warning, DW_CFA_GNU_args_size is unimplemented\n");
216 Length += DwDecodeUleb128(&argsize, pc + Length);
217 break;
218 }
219 /* PSEH */
220 case 0x21:
221 {
222 unsigned long SehType;
223
224 // printf("found 0x21 at %lx\n", State->Location);
225 Length += DwDecodeUleb128(&SehType, pc + Length);
226 switch (SehType)
227 {
228 case 1: /* Begin Try */
229 State->TryLevel++;
230 if (State->TryLevel >= 20)
231 {
232 printf("WTF? Trylevel of 20 exceeded...\n");
233 exit(1);
234 }
235 State->SehBlock[State->TryLevel-1].BeginTry = State->Location;
236 // printf("Found begintry at 0x%lx\n", State->Location);
237 State->Scope = 1;
238 break;
239
240 case 2: /* End Try */
241 State->SehBlock[State->TryLevel-1].EndTry = State->Location;
242 State->Scope = 2;
243 break;
244
245 case 3: /* Jump target */
246 State->SehBlock[State->TryLevel-1].Target = State->Location;
247 State->Scope = 3;
248 break;
249
250 case 4: /* SEH End */
251 if (State->TryLevel == 20)
252 {
253 printf("Ooops, end of SEH with trylevel at 0!\n");
254 exit(1);
255 }
256 State->SehBlock[State->TryLevel-1].End = State->Location;
257 State->TryLevel--;
258 State->cScopes++;
259 State->Scope = 0;
260 break;
261
262 case 5: /* Constant filter */
263 {
264 unsigned long value;
265 Length += DwDecodeUleb128(&value, pc + Length);
266 State->SehBlock[State->TryLevel-1].Handler = value;
267 // printf("Found a constant filter at 0x%lx\n", State->Location);
268 break;
269 }
270
271 /* These work differently. We are in a new function.
272 * We have to parse a lea opcode to find the address of
273 * the jump target. This is the reference to find the
274 * appropriate C_SCOPE_TABLE. */
275 case 6: /* Filter func */
276 // printf("Found a filter func at 0x%lx\n", State->Location);
277 break;
278
279 case 7: /* Finally func */
280 {
281 // printf("Found a finally func at 0x%lx\n", State->Location);
282 break;
283 }
284
285 default:
286 printf("Found unknow PSEH code 0x%lx\n", SehType);
287 exit(1);
288 }
289 break;
290 }
291 default:
292 fprintf(stderr, "unknown instruction 0x%x at 0x%p\n", Code, pc);
293 exit(1);
294 }
295
296 State->FramePtrDiff = State->FramePtr - PrevFramePtr;
297 DPRINT("@%p: code=%x, Loc=%lx, offset=%lx, reg=0x%lx:%s\n",
298 (void*)((ULONG)pc - g_ehframep), Code, State->Location, State->Offset, State->Reg, regs[State->Reg].name);
299 return Length;
300 }
301
302 /** Windows unwind data functions *********************************************/
303
304 ULONG
StoreUnwindCodes(PUNWIND_INFO Info,PDW2CFSTATE State,ULONG FunctionStart)305 StoreUnwindCodes(PUNWIND_INFO Info, PDW2CFSTATE State, ULONG FunctionStart)
306 {
307 ULONG cCodes = 0;
308 ULONG AllocSize;
309 UNWIND_CODE Code[3];
310 int i;
311
312 Code[0].CodeOffset = State->Location - FunctionStart;
313
314 switch (State->Code)
315 {
316 case DW_CFA_offset:
317 case DW_CFA_offset_extended:
318 // save register at offset
319 Code[0].OpInfo = regs[State->Reg].regnt;
320 if (State->Offset <= 0x7FFF8)
321 {
322 Code[0].UnwindOp = UWOP_SAVE_NONVOL;
323 Code[1].FrameOffset = State->Offset / 8;
324 cCodes = 2;
325 }
326 else
327 {
328 Code[0].UnwindOp = UWOP_SAVE_NONVOL_FAR;
329 Code[1].FrameOffset = (State->Offset / 8);
330 Code[2].FrameOffset = (State->Offset / 8) >> 16;
331 cCodes = 3;
332 }
333 break;
334
335 case DW_CFA_def_cfa:
336 //case DW_CFA_def_cfa_register:
337 case DW_CFA_def_cfa_offset:
338 case DW_CFA_def_cfa_sf:
339 AllocSize = State->FramePtrDiff;
340 if (AllocSize <= 128)
341 {
342 Code[0].UnwindOp = UWOP_ALLOC_SMALL;
343 Code[0].OpInfo = (AllocSize / 8) - 1;
344 cCodes = 1;
345 }
346 else if (AllocSize <= 0x7FFF8)
347 {
348 Code[0].UnwindOp = UWOP_ALLOC_LARGE;
349 Code[0].OpInfo = 0;
350 Code[1].FrameOffset = AllocSize / 8;
351 cCodes = 2;
352 }
353 else // if (AllocSize > 0x7FFF8)
354 {
355 Code[0].UnwindOp = UWOP_ALLOC_LARGE;
356 Code[0].OpInfo = 1;
357 Code[1].FrameOffset = (USHORT)AllocSize;
358 Code[2].FrameOffset = (USHORT)(AllocSize >> 16);
359 cCodes = 3;
360 }
361 break;
362 }
363
364 if (Info)
365 {
366 /* Move old codes */
367 for (i = Info->CountOfCodes - 1; i >= 0; i--)
368 {
369 Info->UnwindCode[i + cCodes] = Info->UnwindCode[i];
370 }
371
372 /* Copy new codes */
373 for (i = 0; i < cCodes; i++)
374 {
375 Info->UnwindCode[i] = Code[i];
376 }
377
378 Info->CountOfCodes += cCodes;
379 }
380
381 return cCodes;
382 }
383
384 #define GetxdataSize(cFuncs, cUWOP, cScopes) \
385 ( cFuncs * (sizeof(UNWIND_INFO) + 2 + 4 + 4) \
386 + cUWOP * sizeof(UNWIND_CODE) \
387 + cScopes * sizeof(C_SCOPE_TABLE_ENTRY) )
388
389 ULONG
StoreUnwindInfo(PUNWIND_INFO Info,PDW2FDE pFde,ULONG FunctionStart)390 StoreUnwindInfo(PUNWIND_INFO Info, PDW2FDE pFde, ULONG FunctionStart)
391 {
392 ULONG cbSize;
393 DW2CFSTATE State;
394 char *pInst;
395 ULONG c;
396 DW2CIE Cie;
397
398 cbSize = 4; // sizeof(UNWIND_INFO);
399 Info->Version = 1;
400 Info->Flags = 0;
401 Info->SizeOfProlog = 0;
402 Info->CountOfCodes = 0;
403 Info->FrameRegister = 0;
404 Info->FrameOffset = 0;
405
406 /* Decode the CIE */
407 DwDecodeCie(&Cie, pFde->CiePointer);
408
409 /* Initialize state */
410 State.Location = FunctionStart;
411 State.FramePtr = 0;
412 State.TryLevel = 0;
413 State.cScopes = 0;
414
415 /* Parse the CIE's initial instructions */
416 pInst = Cie.Instructions;
417 while (pInst < Cie.Next)
418 {
419 pInst += DwExecIntruction(&State, pInst);
420 }
421
422 /* Parse the FDE instructions */
423 pInst = pFde->Instructions;
424 while (pInst < pFde->Next)
425 {
426 pInst += DwExecIntruction(&State, pInst);
427
428 if (State.IsUwop)
429 {
430 c = StoreUnwindCodes(Info, &State, FunctionStart);
431 cbSize += c * sizeof(UNWIND_CODE);
432 Info->SizeOfProlog = State.Location - FunctionStart;
433 }
434 }
435 cbSize = ROUND_UP(cbSize, 4);
436
437 /* Do we have scope table to write? */
438 if (State.cScopes > 0)
439 {
440 unsigned long i;
441 ULONG *pExceptionHandler;
442 PC_SCOPE_TABLE pScopeTable;
443
444 /* Set flag for exception handler */
445 Info->Flags |= UNW_FLAG_EHANDLER;
446
447 /* Store address of handler and number of scope tables */
448 pExceptionHandler = (ULONG*)((char*)Info + cbSize);
449 // HACK for testing purpose
450 *pExceptionHandler = FunctionStart; // _C_specific_handler
451
452 pScopeTable = (PC_SCOPE_TABLE)(pExceptionHandler + 1);
453 pScopeTable->NumEntries = State.cScopes;
454
455 /* Store the scope table entries */
456 for (i = 0; i < State.cScopes; i++)
457 {
458 pScopeTable->Entry[i].Begin = State.SehBlock[i].BeginTry;
459 pScopeTable->Entry[i].End = State.SehBlock[i].EndTry;
460 pScopeTable->Entry[i].Handler = 1;//State.SehBlock[i].Handler;
461 pScopeTable->Entry[i].Target = State.SehBlock[i].Target;
462 }
463
464 /* Update size */
465 cbSize += 8 + State.cScopes * sizeof(C_SCOPE_TABLE_ENTRY);
466 }
467
468 return cbSize;
469 }
470
471 void
CountUnwindData(PFILE_INFO File)472 CountUnwindData(PFILE_INFO File)
473 {
474 DW2CIEFDE *p;
475 DW2FDE Fde;
476 char *pInst, *pmax;
477 DW2CFSTATE State;
478
479 File->cFuncs = 0;
480 File->cScopes = 0;
481 File->cUWOP = 0;
482 State.FramePtr = 0;
483 State.TryLevel = 0;
484
485 p = File->eh_frame.p;
486 pmax = (char*)p + File->eh_frame.psh->Misc.VirtualSize;
487 for (; p->Length && (char*)p < pmax; p = NextCIE(p))
488 {
489 /* Is this an FDE? */
490 if (p->CiePointer != 0)
491 {
492 File->cFuncs++;
493 DwDecodeFde(&Fde, (char*)p);
494
495 pInst = Fde.Instructions;
496 while (pInst < Fde.Next)
497 {
498 pInst += DwExecIntruction(&State, pInst);
499 File->cUWOP += StoreUnwindCodes(NULL, &State, 0);
500 File->cScopes += State.Scope ? 1 : 0;
501 }
502 }
503 }
504
505 return;
506 }
507
CompFunc(const void * p1,const void * p2)508 int CompFunc(const void *p1, const void *p2)
509 {
510 PRUNTIME_FUNCTION prf1 = (void*)p1, prf2 = (void*)p2;
511 return (prf1->FunctionStart > prf2->FunctionStart ? 1 : -1);
512 }
513
514 void
GeneratePData(PFILE_INFO File)515 GeneratePData(PFILE_INFO File)
516 {
517 DW2CIEFDE *p;
518 DW2FDE Fde;
519 PIMAGE_DATA_DIRECTORY Dir;
520 ULONG i, Offset;
521 void * eh_frame;
522 PRUNTIME_FUNCTION pdata;
523 ULONG xdata_va;
524 char *xdata_p;
525 ULONG cbSize;
526 PIMAGE_SECTION_HEADER pshp, pshx;
527 ULONG FileAlignment;
528 char *pmax;
529
530 FileAlignment = File->OptionalHeader->FileAlignment;
531
532 /* Get pointer to eh_frame section */
533 eh_frame = File->eh_frame.p;
534 g_ehframep = (ULONG)eh_frame;
535
536 /* Get sizes */
537 CountUnwindData(File);
538 // printf("cFuncs = %ld, cUWOPS = %ld, cScopes = %ld\n",
539 // File->cFuncs, File->cUWOP, File->cScopes);
540
541 /* Initialize section header for .pdata */
542 i = File->pdata.idx = File->UsedSections;
543 pshp = File->pdata.psh = &File->NewSectionHeaders[i];
544 memcpy(pshp->Name, ".pdata", 7);
545 pshp->Misc.VirtualSize = (File->cFuncs + 1) * sizeof(RUNTIME_FUNCTION);
546 pshp->VirtualAddress = File->NewSectionHeaders[i - 1].VirtualAddress +
547 File->NewSectionHeaders[i - 1].SizeOfRawData;
548 pshp->SizeOfRawData = ROUND_UP(pshp->Misc.VirtualSize, FileAlignment);
549 pshp->PointerToRawData = File->NewSectionHeaders[i - 1].PointerToRawData +
550 File->NewSectionHeaders[i - 1].SizeOfRawData;
551 pshp->PointerToRelocations = 0;
552 pshp->PointerToLinenumbers = 0;
553 pshp->NumberOfRelocations = 0;
554 pshp->NumberOfLinenumbers = 0;
555 pshp->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_NOT_PAGED |
556 IMAGE_SCN_CNT_INITIALIZED_DATA;
557
558 /* Allocate .pdata buffer */
559 pdata = File->pdata.p = malloc(pshp->SizeOfRawData);
560 memset(File->pdata.p, 0, pshp->SizeOfRawData);
561
562 /* Init exception data dir */
563 Dir = &File->OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
564 Dir->VirtualAddress = pshp->VirtualAddress;
565 Dir->Size = pshp->Misc.VirtualSize;
566
567 /* Initialize section header for .xdata */
568 File->xdata.idx = File->pdata.idx + 1;
569 pshx = File->xdata.psh = &File->NewSectionHeaders[File->xdata.idx];
570 memcpy(pshx->Name, ".xdata", 7);
571 pshx->Misc.VirtualSize = GetxdataSize(File->cFuncs, File->cUWOP, File->cScopes);
572 pshx->VirtualAddress = pshp->VirtualAddress + pshp->SizeOfRawData;
573 pshx->SizeOfRawData = ROUND_UP(pshx->Misc.VirtualSize, FileAlignment);
574 pshx->PointerToRawData = pshp->PointerToRawData + pshp->SizeOfRawData;
575 pshx->PointerToRelocations = 0;
576 pshx->PointerToLinenumbers = 0;
577 pshx->NumberOfRelocations = 0;
578 pshx->NumberOfLinenumbers = 0;
579 pshx->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_NOT_PAGED |
580 IMAGE_SCN_CNT_INITIALIZED_DATA;
581
582 /* Allocate .xdata buffer */
583 File->xdata.p = malloc(pshx->SizeOfRawData);
584 memset(File->xdata.p, 0, pshx->SizeOfRawData);
585
586 i = 0;
587 Offset = File->eh_frame.psh->VirtualAddress;
588 xdata_va = pshx->VirtualAddress;
589 xdata_p = File->xdata.p;
590 pmax = (char*)eh_frame + File->eh_frame.psh->Misc.VirtualSize - 100;
591
592 for (p = eh_frame; p->Length && (char*)p < pmax; p = NextCIE(p))
593 {
594 /* Is this an FDE? */
595 if (p->CiePointer != 0)
596 {
597 DwDecodeFde(&Fde, (char*)p);
598 pdata[i].FunctionStart = Offset + 8 + Fde.PcBegin;
599 pdata[i].FunctionEnd = pdata[i].FunctionStart + Fde.PcRange;
600 pdata[i].UnwindInfo = xdata_va;
601
602 // printf("%ld: RUNTIME_FUNCTION: {0x%lx, 0x%lx, 0x%lx}\n", i, pdata[i].FunctionStart, pdata[i].FunctionEnd, pdata[i].UnwindInfo);
603
604 cbSize = StoreUnwindInfo((void*)xdata_p, &Fde, pdata[i].FunctionStart);
605 xdata_va += cbSize;
606 xdata_p += cbSize;
607 i++;
608 }
609 Offset += 4 + p->Length;
610 }
611
612 /* Sort the RUNTIME_FUNCTIONS */
613 qsort(pdata, i, sizeof(RUNTIME_FUNCTION), CompFunc);
614
615 }
616
617 /** Functions for COFF ********************************************************/
618
619
620 WORD
CalculateChecksum(DWORD Start,void * pFile,ULONG cbSize)621 CalculateChecksum(DWORD Start, void *pFile, ULONG cbSize)
622 {
623 WORD *Ptr = pFile;
624 DWORD i;
625 DWORD checksum = Start;
626
627 for (i = 0; i < (cbSize + 1) / sizeof(WORD); i++)
628 {
629 checksum += Ptr[i];
630 checksum = (checksum + (checksum >> 16)) & 0xffff;
631 }
632
633 return checksum ;
634 }
635
636 void
WriteOutFile(FILE * handle,PFILE_INFO File)637 WriteOutFile(FILE *handle, PFILE_INFO File)
638 {
639 int ret, Size, Pos = 0;
640 DWORD CheckSum;
641 ULONG i, Alignment;
642
643 Alignment = File->OptionalHeader->FileAlignment;
644
645 /* Update section count */
646 File->FileHeader->NumberOfSections = File->UsedSections + 2; // FIXME!!!
647
648 /* Update SizeOfImage */
649 Size = File->xdata.psh->VirtualAddress
650 + File->xdata.psh->SizeOfRawData;
651 File->OptionalHeader->SizeOfImage = Size;
652
653 /* Recalculate checksum */
654 CheckSum = CalculateChecksum(0, File->FilePtr, File->HeaderSize);
655 for (i = 0; i < File->AllSections; i++)
656 {
657 if (File->UseSection[i])
658 {
659 Size = File->SectionHeaders[i].SizeOfRawData;
660 if (Size)
661 {
662 void *p;
663 p = File->FilePtr + File->SectionHeaders[i].PointerToRawData;
664 CheckSum = CalculateChecksum(CheckSum, p, Size);
665 }
666 }
667 }
668 Size = File->pdata.psh->Misc.VirtualSize;
669 CheckSum = CalculateChecksum(CheckSum, File->pdata.p, Size);
670 Size = File->xdata.psh->Misc.VirtualSize;
671 CheckSum = CalculateChecksum(CheckSum, File->xdata.p, Size);
672 CheckSum += File->HeaderSize;
673 CheckSum += File->pdata.psh->Misc.VirtualSize;
674 CheckSum += File->xdata.psh->Misc.VirtualSize;
675 File->OptionalHeader->CheckSum = CheckSum;
676
677 /* Write file header */
678 Size = File->HeaderSize;
679 ret = fwrite(File->DosHeader, 1, Size, handle);
680 Pos = Size;
681
682 /* Write Section headers */
683 Size = File->NewSectionHeaderSize;
684 ret = fwrite(File->NewSectionHeaders, 1, Size, handle);
685 Pos += Size;
686
687 /* Fill up to next alignement */
688 Size = ROUND_UP(Pos, Alignment) - Pos;
689 ret = fwrite(File->AlignBuf, 1, Size, handle);
690 Pos += Size;
691
692 /* Write sections */
693 for (i = 0; i < File->AllSections; i++)
694 {
695 if (File->UseSection[i])
696 {
697 void *p;
698 Size = File->SectionHeaders[i].SizeOfRawData;
699 if (Size)
700 {
701 p = File->FilePtr + File->SectionHeaders[i].PointerToRawData;
702 ret = fwrite(p, 1, Size, handle);
703 Pos += Size;
704 }
705 }
706 }
707
708 /* Write .pdata section */
709 Size = File->pdata.psh->SizeOfRawData;
710 ret = fwrite(File->pdata.p, 1, Size, handle);
711 Pos += Size;
712
713 /* Write .xdata section */
714 Size = File->xdata.psh->SizeOfRawData;
715 ret = fwrite(File->xdata.p, 1, Size, handle);
716 Pos += Size;
717
718 }
719
720
721 int
ParsePEHeaders(PFILE_INFO File)722 ParsePEHeaders(PFILE_INFO File)
723 {
724 DWORD OldChecksum, Checksum;
725 ULONG Alignment, CurrentPos;
726 int i, j;
727
728 /* Check if MZ header exists */
729 File->DosHeader = (PIMAGE_DOS_HEADER)File->FilePtr;
730 if ((File->DosHeader->e_magic != IMAGE_DOS_MAGIC) ||
731 (File->DosHeader->e_lfanew == 0L))
732 {
733 perror("Input file is not a PE image.\n");
734 return -1;
735 }
736
737 /* Locate PE file header */
738 File->FileHeader = (PIMAGE_FILE_HEADER)(File->FilePtr +
739 File->DosHeader->e_lfanew + sizeof(ULONG));
740
741 /* Check for x64 image */
742 if (File->FileHeader->Machine != IMAGE_FILE_MACHINE_AMD64)
743 {
744 perror("Input file is not an x64 image.\n");
745 return -1;
746 }
747
748 /* Locate optional header */
749 File->OptionalHeader = (PIMAGE_OPTIONAL_HEADER64)(File->FileHeader + 1);
750
751 /* Check if checksum is correct */
752 OldChecksum = File->OptionalHeader->CheckSum;
753 File->OptionalHeader->CheckSum = 0;
754 Checksum = CalculateChecksum(0, File->FilePtr, File->cbInFileSize);
755 Checksum += File->cbInFileSize;
756 if ((Checksum & 0xffff) != (OldChecksum & 0xffff))
757 {
758 fprintf(stderr, "Input file has incorrect PE checksum: 0x%lx (calculated: 0x%lx)\n",
759 OldChecksum, Checksum);
760 // return 0;
761 }
762
763 /* Locate PE section headers */
764 File->SectionHeaders = (PIMAGE_SECTION_HEADER)((char*)File->OptionalHeader
765 + File->FileHeader->SizeOfOptionalHeader);
766
767 File->HeaderSize = File->DosHeader->e_lfanew
768 + sizeof(ULONG)
769 + sizeof(IMAGE_FILE_HEADER)
770 + File->FileHeader->SizeOfOptionalHeader;
771
772 /* Create some shortcuts */
773 File->ImageBase = File->OptionalHeader->ImageBase;
774 File->Symbols = File->FilePtr + File->FileHeader->PointerToSymbolTable;
775 File->Strings = (char*)File->Symbols + File->FileHeader->NumberOfSymbols * 18;
776
777 /* Check section names */
778 File->AllSections = File->FileHeader->NumberOfSections;
779 Alignment = File->OptionalHeader->FileAlignment;
780 File->NewSectionHeaders = malloc((File->AllSections+2) * sizeof(IMAGE_SECTION_HEADER));
781 File->UsedSections = 0;
782 File->eh_frame.idx = -1;
783
784 /* Allocate array of chars, specifying whether to copy the section */
785 File->UseSection = malloc(File->AllSections);
786
787 for (i = 0; i < File->AllSections; i++)
788 {
789 char *pName = (char*)File->SectionHeaders[i].Name;
790 File->UseSection[i] = 1;
791
792 /* Check for long name */
793 if (pName[0] == '/')
794 {
795 unsigned long index = strtoul(pName+1, 0, 10);
796 pName = File->Strings + index;
797
798 // Hack, simply remove all sections with long names
799 File->UseSection[i] = 0;
800 }
801
802 /* Chek if we have the eh_frame section */
803 if (strcmp(pName, ".eh_frame") == 0)
804 {
805 File->eh_frame.psh = &File->SectionHeaders[i];
806 File->eh_frame.idx = i;
807 File->eh_frame.p = File->FilePtr + File->eh_frame.psh->PointerToRawData;
808 }
809
810 /* Increase number of used sections */
811 if (File->UseSection[i])
812 File->UsedSections = i+1;
813
814 }
815
816 /* This is the actual size of the new section headers */
817 File->NewSectionHeaderSize =
818 (File->UsedSections+2) * sizeof(IMAGE_SECTION_HEADER);
819
820 /* Calculate the position to start writing the sections to */
821 CurrentPos = File->HeaderSize + File->NewSectionHeaderSize;
822 CurrentPos = ROUND_UP(CurrentPos, Alignment);
823
824 /* Create new section headers */
825 for (i = 0, j = 0; i < File->UsedSections; i++)
826 {
827 /* Copy section header */
828 File->NewSectionHeaders[j] = File->SectionHeaders[i];
829
830 /* Shall we strip the section? */
831 if (File->UseSection[i] == 0)
832 {
833 /* Make it a bss section */
834 File->NewSectionHeaders[j].PointerToRawData = 0;
835 File->NewSectionHeaders[j].SizeOfRawData = 0;
836 File->NewSectionHeaders[j].Characteristics = 0xC0500080;
837 }
838
839 /* Fix Offset into File */
840 File->NewSectionHeaders[j].PointerToRawData =
841 File->NewSectionHeaders[j].PointerToRawData ? CurrentPos : 0;
842 CurrentPos += File->NewSectionHeaders[j].SizeOfRawData;
843 j++;
844 }
845
846 if (File->eh_frame.idx == -1)
847 {
848 //fprintf(stderr, "No .eh_frame section found\n");
849 return 0;
850 }
851
852 return 1;
853 }
854
main(int argc,char * argv[])855 int main(int argc, char* argv[])
856 {
857 char* pszInFile;
858 char* pszOutFile;
859 FILE_INFO File;
860 FILE* outfile;
861 int ret;
862 int arg, argstate = 0;
863 char *SourcePath = NULL;
864
865 for (arg = 1; arg < argc; arg++)
866 {
867 switch (argstate)
868 {
869 default:
870 argstate = -1;
871 break;
872
873 case 0:
874 if (!strcmp(argv[arg], "-s"))
875 {
876 argstate = 1;
877 }
878 else
879 {
880 argstate = 2;
881 pszInFile = convert_path(argv[arg]);
882 }
883 break;
884
885 case 1:
886 free(SourcePath);
887 SourcePath = strdup(argv[arg]);
888 argstate = 0;
889 break;
890
891 case 2:
892 pszOutFile = convert_path(argv[arg]);
893 argstate = 3;
894 break;
895 }
896 }
897
898 if (argstate != 3)
899 {
900 fprintf(stderr, "Usage: rsym [-s <sources>] <input> <output>\n");
901 exit(1);
902 }
903
904 File.FilePtr = load_file(pszInFile, &File.cbInFileSize);
905 if (!File.FilePtr)
906 {
907 fprintf(stderr, "An error occured loading '%s'\n", pszInFile);
908 exit(1);
909 }
910
911 ret = ParsePEHeaders(&File);
912 if (ret != 1)
913 {
914 free(File.FilePtr);
915 exit(ret == -1 ? 1 : 0);
916 }
917
918 File.AlignBuf = malloc(File.OptionalHeader->FileAlignment);
919 memset(File.AlignBuf, 0, File.OptionalHeader->FileAlignment);
920
921 GeneratePData(&File);
922
923 outfile = fopen(pszOutFile, "wb");
924 if (outfile == NULL)
925 {
926 perror("Cannot open output file");
927 free(File.FilePtr);
928 exit(1);
929 }
930
931 WriteOutFile(outfile, &File);
932
933 fclose(outfile);
934
935 return 0;
936 }
937