]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/Common/BasePeCoff.c
Sync basetools' source and binary files with r1707 of the basetools project.
[mirror_edk2.git] / BaseTools / Source / C / Common / BasePeCoff.c
CommitLineData
30fdf114
LG
1/** @file\r
2\r
3 Functions to get info and load PE/COFF image.\r
4\r
5Copyright (c) 2004 - 2008, Intel Corporation \r
6All rights reserved. This program and the accompanying materials \r
7are licensed and made available under the terms and conditions of the BSD License \r
8which accompanies this distribution. The full text of the license may be found at \r
9http://opensource.org/licenses/bsd-license.php \r
10 \r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
13\r
14**/\r
15\r
16#include <Common/UefiBaseTypes.h>\r
17#include <CommonLib.h>\r
18#include <IndustryStandard/PeImage.h>\r
19#include "PeCoffLib.h"\r
20\r
21typedef union {\r
22 VOID *Header; \r
23 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;\r
24 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;\r
25} EFI_IMAGE_OPTIONAL_HEADER_POINTER;\r
26\r
27STATIC\r
28RETURN_STATUS\r
29PeCoffLoaderGetPeHeader (\r
30 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
31 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,\r
32 OUT EFI_TE_IMAGE_HEADER **TeHdr\r
33 );\r
34\r
35STATIC\r
36RETURN_STATUS\r
37PeCoffLoaderCheckImageType (\r
38 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
39 IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,\r
40 IN EFI_TE_IMAGE_HEADER *TeHdr\r
41 );\r
42\r
43STATIC\r
44VOID *\r
45PeCoffLoaderImageAddress (\r
46 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
47 IN UINTN Address\r
48 );\r
49\r
50RETURN_STATUS\r
51PeCoffLoaderRelocateIa32Image (\r
52 IN UINT16 *Reloc,\r
53 IN OUT CHAR8 *Fixup,\r
54 IN OUT CHAR8 **FixupData,\r
55 IN UINT64 Adjust\r
56 );\r
57\r
58RETURN_STATUS\r
59PeCoffLoaderRelocateX64Image (\r
60 IN UINT16 *Reloc,\r
61 IN OUT CHAR8 *Fixup,\r
62 IN OUT CHAR8 **FixupData,\r
63 IN UINT64 Adjust\r
64 );\r
65\r
66RETURN_STATUS\r
67PeCoffLoaderRelocateIpfImage (\r
68 IN UINT16 *Reloc,\r
69 IN OUT CHAR8 *Fixup,\r
70 IN OUT CHAR8 **FixupData,\r
71 IN UINT64 Adjust\r
72 );\r
73\r
74STATIC\r
75RETURN_STATUS\r
76PeCoffLoaderGetPeHeader (\r
77 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
78 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,\r
79 OUT EFI_TE_IMAGE_HEADER **TeHdr\r
80 )\r
81/*++\r
82\r
83Routine Description:\r
84\r
85 Retrieves the PE or TE Header from a PE/COFF or TE image\r
86\r
87Arguments:\r
88\r
89 ImageContext - The context of the image being loaded\r
90\r
91 PeHdr - The buffer in which to return the PE header\r
92 \r
93 TeHdr - The buffer in which to return the TE header\r
94\r
95Returns:\r
96\r
97 RETURN_SUCCESS if the PE or TE Header is read, \r
98 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.\r
99\r
100--*/\r
101{\r
102 RETURN_STATUS Status;\r
103 EFI_IMAGE_DOS_HEADER DosHdr;\r
104 UINTN Size;\r
105\r
106 ImageContext->IsTeImage = FALSE;\r
107 //\r
108 // Read the DOS image headers\r
109 //\r
110 Size = sizeof (EFI_IMAGE_DOS_HEADER);\r
111 Status = ImageContext->ImageRead (\r
112 ImageContext->Handle,\r
113 0,\r
114 &Size,\r
115 &DosHdr\r
116 );\r
117 if (RETURN_ERROR (Status)) {\r
118 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
119 return Status;\r
120 }\r
121\r
122 ImageContext->PeCoffHeaderOffset = 0;\r
123 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
124 //\r
125 // DOS image header is present, so read the PE header after the DOS image header\r
126 //\r
127 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;\r
128 }\r
129 //\r
130 // Get the PE/COFF Header pointer\r
131 //\r
132 *PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);\r
133 if ((*PeHdr)->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
134 //\r
135 // Check the PE/COFF Header Signature. If not, then try to get a TE header\r
136 //\r
137 *TeHdr = (EFI_TE_IMAGE_HEADER *)*PeHdr; \r
138 if ((*TeHdr)->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
139 return RETURN_UNSUPPORTED;\r
140 }\r
141 ImageContext->IsTeImage = TRUE;\r
142 }\r
143\r
144 return RETURN_SUCCESS;\r
145}\r
146\r
147STATIC\r
148RETURN_STATUS\r
149PeCoffLoaderCheckImageType (\r
150 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
151 IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,\r
152 IN EFI_TE_IMAGE_HEADER *TeHdr\r
153 )\r
154/*++\r
155\r
156Routine Description:\r
157\r
158 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported\r
159\r
160Arguments:\r
161\r
162 ImageContext - The context of the image being loaded\r
163\r
164 PeHdr - The buffer in which to return the PE header\r
165 \r
166 TeHdr - The buffer in which to return the TE header\r
167\r
168Returns:\r
169\r
170 RETURN_SUCCESS if the PE/COFF or TE image is supported\r
171 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.\r
172\r
173--*/\r
174{\r
175 //\r
176 // See if the machine type is supported. \r
177 // We support a native machine type (IA-32/Itanium-based)\r
178 //\r
179 if (ImageContext->IsTeImage == FALSE) {\r
180 ImageContext->Machine = PeHdr->Pe32.FileHeader.Machine;\r
181 } else {\r
182 ImageContext->Machine = TeHdr->Machine;\r
183 }\r
184 \r
185 if (ImageContext->Machine != EFI_IMAGE_MACHINE_IA32 && \\r
186 ImageContext->Machine != EFI_IMAGE_MACHINE_IA64 && \\r
187 ImageContext->Machine != EFI_IMAGE_MACHINE_X64 && \\r
188 ImageContext->Machine != EFI_IMAGE_MACHINE_ARMT && \\r
189 ImageContext->Machine != EFI_IMAGE_MACHINE_EBC) {\r
190 if (ImageContext->Machine == IMAGE_FILE_MACHINE_ARM) {\r
191 //\r
192 // There are two types of ARM images. Pure ARM and ARM/Thumb. \r
193 // If we see the ARM say it is the ARM/Thumb so there is only\r
194 // a single machine type we need to check for ARM.\r
195 //\r
196 ImageContext->Machine = EFI_IMAGE_MACHINE_ARMT;\r
197 if (ImageContext->IsTeImage == FALSE) {\r
198 PeHdr->Pe32.FileHeader.Machine = ImageContext->Machine;\r
199 } else {\r
200 TeHdr->Machine = ImageContext->Machine;\r
201 }\r
202\r
203 } else {\r
204 //\r
205 // unsupported PeImage machine type \r
206 // \r
207 return RETURN_UNSUPPORTED;\r
208 }\r
209 }\r
210\r
211 //\r
212 // See if the image type is supported. We support EFI Applications,\r
213 // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.\r
214 //\r
215 if (ImageContext->IsTeImage == FALSE) {\r
216 ImageContext->ImageType = PeHdr->Pe32.OptionalHeader.Subsystem;\r
217 } else {\r
218 ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);\r
219 }\r
220\r
221 if (ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION && \\r
222 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER && \\r
223 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER && \\r
224 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER) {\r
225 //\r
226 // upsupported PeImage subsystem type \r
227 // \r
228 return RETURN_UNSUPPORTED;\r
229 }\r
230\r
231 return RETURN_SUCCESS;\r
232}\r
233\r
234RETURN_STATUS\r
235EFIAPI\r
236PeCoffLoaderGetImageInfo (\r
237 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
238 )\r
239/*++\r
240\r
241Routine Description:\r
242\r
243 Retrieves information on a PE/COFF image\r
244\r
245Arguments:\r
246\r
247 This - Calling context\r
248 ImageContext - The context of the image being loaded\r
249\r
250Returns:\r
251\r
252 RETURN_SUCCESS - The information on the PE/COFF image was collected.\r
253 RETURN_INVALID_PARAMETER - ImageContext is NULL.\r
254 RETURN_UNSUPPORTED - The PE/COFF image is not supported.\r
255 Otherwise - The error status from reading the PE/COFF image using the\r
256 ImageContext->ImageRead() function\r
257\r
258--*/\r
259{\r
260 RETURN_STATUS Status;\r
261 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;\r
262 EFI_TE_IMAGE_HEADER *TeHdr;\r
263 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;\r
264 UINTN Size;\r
265 UINTN Index;\r
266 UINTN DebugDirectoryEntryRva;\r
267 UINTN DebugDirectoryEntryFileOffset;\r
268 UINTN SectionHeaderOffset;\r
269 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
270 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;\r
271 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;\r
272\r
273 PeHdr = NULL;\r
274 TeHdr = NULL;\r
275 DebugDirectoryEntry = NULL;\r
276 DebugDirectoryEntryRva = 0;\r
277\r
278 if (NULL == ImageContext) {\r
279 return RETURN_INVALID_PARAMETER;\r
280 }\r
281 //\r
282 // Assume success\r
283 //\r
284 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
285\r
286 Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);\r
287 if (RETURN_ERROR (Status)) {\r
288 return Status;\r
289 }\r
290\r
291 //\r
292 // Verify machine type\r
293 //\r
294 Status = PeCoffLoaderCheckImageType (ImageContext, PeHdr, TeHdr);\r
295 if (RETURN_ERROR (Status)) {\r
296 return Status;\r
297 }\r
298 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);\r
299\r
300 //\r
301 // Retrieve the base address of the image\r
302 //\r
303 if (!(ImageContext->IsTeImage)) {\r
304 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
305 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional32->ImageBase;\r
306 } else {\r
307 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional64->ImageBase;\r
308 }\r
309 } else {\r
310 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr->ImageBase + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
311 }\r
312 //\r
313 // Initialize the alternate destination address to 0 indicating that it\r
314 // should not be used.\r
315 //\r
316 ImageContext->DestinationAddress = 0;\r
317\r
318 //\r
319 // Initialize the codeview pointer.\r
320 //\r
321 ImageContext->CodeView = NULL;\r
322 ImageContext->PdbPointer = NULL;\r
323\r
324 //\r
325 // Three cases with regards to relocations:\r
326 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable\r
327 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r
328 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r
329 // has no base relocs to apply\r
330 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r
331 //\r
332 // Look at the file header to determine if relocations have been stripped, and\r
333 // save this info in the image context for later use.\r
334 //\r
335 if ((!(ImageContext->IsTeImage)) && ((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {\r
336 ImageContext->RelocationsStripped = TRUE;\r
337 } else if ((ImageContext->IsTeImage) && (TeHdr->DataDirectory[0].Size == 0)) {\r
338 ImageContext->RelocationsStripped = TRUE;\r
339 } else {\r
340 ImageContext->RelocationsStripped = FALSE;\r
341 }\r
342\r
343 if (!(ImageContext->IsTeImage)) {\r
344\r
345 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
346 ImageContext->ImageSize = (UINT64) OptionHeader.Optional32->SizeOfImage;\r
347 ImageContext->SectionAlignment = OptionHeader.Optional32->SectionAlignment;\r
348 ImageContext->SizeOfHeaders = OptionHeader.Optional32->SizeOfHeaders;\r
349 \r
350 //\r
351 // Modify ImageSize to contain .PDB file name if required and initialize\r
352 // PdbRVA field...\r
353 //\r
354 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
355 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
356 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
357 }\r
358 } else {\r
359 ImageContext->ImageSize = (UINT64) OptionHeader.Optional64->SizeOfImage;\r
360 ImageContext->SectionAlignment = OptionHeader.Optional64->SectionAlignment;\r
361 ImageContext->SizeOfHeaders = OptionHeader.Optional64->SizeOfHeaders;\r
362 \r
363 //\r
364 // Modify ImageSize to contain .PDB file name if required and initialize\r
365 // PdbRVA field...\r
366 //\r
367 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
368 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
369 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
370 }\r
371 }\r
372 \r
373 if (DebugDirectoryEntryRva != 0) {\r
374 //\r
375 // Determine the file offset of the debug directory... This means we walk\r
376 // the sections to find which section contains the RVA of the debug\r
377 // directory\r
378 //\r
379 DebugDirectoryEntryFileOffset = 0;\r
380\r
381 SectionHeaderOffset = (UINTN)(\r
382 ImageContext->PeCoffHeaderOffset +\r
383 sizeof (UINT32) + \r
384 sizeof (EFI_IMAGE_FILE_HEADER) + \r
385 PeHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
386 );\r
387\r
388 for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) {\r
389 //\r
390 // Read section header from file\r
391 //\r
392 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
393 Status = ImageContext->ImageRead (\r
394 ImageContext->Handle,\r
395 SectionHeaderOffset,\r
396 &Size,\r
397 &SectionHeader\r
398 );\r
399 if (RETURN_ERROR (Status)) {\r
400 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
401 return Status;\r
402 }\r
403\r
404 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
405 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
406 DebugDirectoryEntryFileOffset =\r
407 DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r
408 break;\r
409 }\r
410\r
411 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
412 }\r
413\r
414 if (DebugDirectoryEntryFileOffset != 0) { \r
415 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {\r
416 //\r
417 // Read next debug directory entry\r
418 //\r
419 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); \r
420 Status = ImageContext->ImageRead (\r
421 ImageContext->Handle,\r
422 DebugDirectoryEntryFileOffset + Index,\r
423 &Size,\r
424 &DebugEntry\r
425 );\r
426 if (RETURN_ERROR (Status)) {\r
427 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
428 return Status;\r
429 }\r
430\r
431 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
432 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);\r
433 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
434 ImageContext->ImageSize += DebugEntry.SizeOfData;\r
435 }\r
436\r
437 return RETURN_SUCCESS;\r
438 }\r
439 }\r
440 }\r
441 }\r
442 } else {\r
443 ImageContext->ImageSize = 0;\r
444 ImageContext->SectionAlignment = 4096;\r
445 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr->BaseOfCode - (UINTN) TeHdr->StrippedSize;\r
446\r
447 DebugDirectoryEntry = &TeHdr->DataDirectory[1];\r
448 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
449 SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));\r
450\r
451 DebugDirectoryEntryFileOffset = 0;\r
452\r
453 for (Index = 0; Index < TeHdr->NumberOfSections;) {\r
454 //\r
455 // Read section header from file\r
456 //\r
457 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
458 Status = ImageContext->ImageRead (\r
459 ImageContext->Handle,\r
460 SectionHeaderOffset,\r
461 &Size,\r
462 &SectionHeader\r
463 );\r
464 if (RETURN_ERROR (Status)) {\r
465 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
466 return Status;\r
467 }\r
468\r
469 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
470 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
471 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -\r
472 SectionHeader.VirtualAddress +\r
473 SectionHeader.PointerToRawData +\r
474 sizeof (EFI_TE_IMAGE_HEADER) -\r
475 TeHdr->StrippedSize;\r
476\r
477 //\r
478 // File offset of the debug directory was found, if this is not the last\r
479 // section, then skip to the last section for calculating the image size.\r
480 //\r
481 if (Index < (UINTN) TeHdr->NumberOfSections - 1) {\r
482 SectionHeaderOffset += (TeHdr->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);\r
483 Index = TeHdr->NumberOfSections - 1;\r
484 continue;\r
485 }\r
486 }\r
487\r
488 //\r
489 // In Te image header there is not a field to describe the ImageSize.\r
490 // Actually, the ImageSize equals the RVA plus the VirtualSize of \r
491 // the last section mapped into memory (Must be rounded up to \r
492 // a mulitple of Section Alignment). Per the PE/COFF specification, the\r
493 // section headers in the Section Table must appear in order of the RVA\r
494 // values for the corresponding sections. So the ImageSize can be determined\r
495 // by the RVA and the VirtualSize of the last section header in the\r
496 // Section Table.\r
497 //\r
498 if ((++Index) == (UINTN) TeHdr->NumberOfSections) {\r
499 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +\r
500 ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);\r
501 }\r
502\r
503 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
504 }\r
505\r
506 if (DebugDirectoryEntryFileOffset != 0) {\r
507 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {\r
508 //\r
509 // Read next debug directory entry\r
510 //\r
511 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
512 Status = ImageContext->ImageRead (\r
513 ImageContext->Handle,\r
514 DebugDirectoryEntryFileOffset,\r
515 &Size,\r
516 &DebugEntry\r
517 );\r
518 if (RETURN_ERROR (Status)) {\r
519 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
520 return Status;\r
521 }\r
522\r
523 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
524 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);\r
525 return RETURN_SUCCESS;\r
526 }\r
527 }\r
528 }\r
529 }\r
530\r
531 return RETURN_SUCCESS;\r
532}\r
533\r
534STATIC\r
535VOID *\r
536PeCoffLoaderImageAddress (\r
537 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
538 IN UINTN Address\r
539 )\r
540/*++\r
541\r
542Routine Description:\r
543\r
544 Converts an image address to the loaded address\r
545\r
546Arguments:\r
547\r
548 ImageContext - The context of the image being loaded\r
549\r
550 Address - The address to be converted to the loaded address\r
551\r
552Returns:\r
553\r
554 NULL if the address can not be converted, otherwise, the converted address\r
555\r
556--*/\r
557{\r
558 if (Address >= ImageContext->ImageSize) {\r
559 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
560 return NULL;\r
561 }\r
562\r
563 return (UINT8 *) ((UINTN) ImageContext->ImageAddress + Address);\r
564}\r
565\r
566RETURN_STATUS\r
567EFIAPI\r
568PeCoffLoaderRelocateImage (\r
569 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
570 )\r
571/*++\r
572\r
573Routine Description:\r
574\r
575 Relocates a PE/COFF image in memory\r
576\r
577Arguments:\r
578\r
579 This - Calling context\r
580\r
581 ImageContext - Contains information on the loaded image to relocate\r
582\r
583Returns:\r
584\r
585 RETURN_SUCCESS if the PE/COFF image was relocated\r
586 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image\r
587 RETURN_UNSUPPORTED not support\r
588\r
589--*/\r
590{\r
591 RETURN_STATUS Status;\r
592 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;\r
593 EFI_TE_IMAGE_HEADER *TeHdr;\r
594 EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
595 UINT64 Adjust;\r
596 EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
597 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
598 UINT16 *Reloc;\r
599 UINT16 *RelocEnd;\r
600 CHAR8 *Fixup;\r
601 CHAR8 *FixupBase;\r
602 UINT16 *F16;\r
603 UINT32 *F32;\r
604 CHAR8 *FixupData;\r
605 PHYSICAL_ADDRESS BaseAddress;\r
606 UINT16 MachineType;\r
607 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;\r
608\r
609 PeHdr = NULL;\r
610 TeHdr = NULL;\r
611 //\r
612 // Assume success\r
613 //\r
614 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
615\r
616 //\r
617 // If there are no relocation entries, then we are done\r
618 //\r
619 if (ImageContext->RelocationsStripped) {\r
620 return RETURN_SUCCESS;\r
621 }\r
622\r
623 //\r
624 // If the destination address is not 0, use that rather than the\r
625 // image address as the relocation target.\r
626 //\r
627 if (ImageContext->DestinationAddress) {\r
628 BaseAddress = ImageContext->DestinationAddress;\r
629 } else {\r
630 BaseAddress = ImageContext->ImageAddress;\r
631 }\r
632\r
633 if (!(ImageContext->IsTeImage)) {\r
634 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)ImageContext->ImageAddress + \r
635 ImageContext->PeCoffHeaderOffset);\r
636 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);\r
637 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
638 Adjust = (UINT64) BaseAddress - OptionHeader.Optional32->ImageBase;\r
639 OptionHeader.Optional32->ImageBase = (UINT32) BaseAddress;\r
640 MachineType = ImageContext->Machine;\r
641 //\r
642 // Find the relocation block\r
643 //\r
644 // Per the PE/COFF spec, you can't assume that a given data directory\r
645 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
646 // the optional header to verify a desired directory entry is there.\r
647 //\r
648 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
649 RelocDir = &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
650 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
651 RelocBaseEnd = PeCoffLoaderImageAddress (\r
652 ImageContext,\r
653 RelocDir->VirtualAddress + RelocDir->Size - 1\r
654 );\r
655 } else {\r
656 //\r
657 // Set base and end to bypass processing below.\r
658 //\r
659 RelocBase = RelocBaseEnd = 0;\r
660 }\r
661 } else {\r
662 Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase;\r
663 OptionHeader.Optional64->ImageBase = BaseAddress;\r
664 MachineType = ImageContext->Machine;\r
665 //\r
666 // Find the relocation block\r
667 //\r
668 // Per the PE/COFF spec, you can't assume that a given data directory\r
669 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
670 // the optional header to verify a desired directory entry is there.\r
671 //\r
672 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
673 RelocDir = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
674 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
675 RelocBaseEnd = PeCoffLoaderImageAddress (\r
676 ImageContext,\r
677 RelocDir->VirtualAddress + RelocDir->Size - 1\r
678 );\r
679 } else {\r
680 //\r
681 // Set base and end to bypass processing below.\r
682 //\r
683 RelocBase = RelocBaseEnd = 0;\r
684 }\r
685 }\r
686 } else {\r
687 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r
688 Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);\r
689 TeHdr->ImageBase = (UINT64) (BaseAddress);\r
690 MachineType = TeHdr->Machine;\r
691 \r
692 //\r
693 // Find the relocation block\r
694 //\r
695 RelocDir = &TeHdr->DataDirectory[0];\r
696 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
697 ImageContext->ImageAddress + \r
698 RelocDir->VirtualAddress +\r
699 sizeof(EFI_TE_IMAGE_HEADER) - \r
700 TeHdr->StrippedSize\r
701 );\r
702 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
703 }\r
704 \r
705 //\r
706 // Run the relocation information and apply the fixups\r
707 //\r
708 FixupData = ImageContext->FixupData;\r
709 while (RelocBase < RelocBaseEnd) {\r
710\r
711 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
712 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
713 if (!(ImageContext->IsTeImage)) {\r
714 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
715 } else {\r
716 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r
717 RelocBase->VirtualAddress +\r
718 sizeof(EFI_TE_IMAGE_HEADER) - \r
719 TeHdr->StrippedSize\r
720 );\r
721 }\r
722\r
723 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r
724 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + \r
725 (UINTN)ImageContext->ImageSize)) {\r
726 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
727 return RETURN_LOAD_ERROR;\r
728 }\r
729\r
730 //\r
731 // Run this relocation record\r
732 //\r
733 while (Reloc < RelocEnd) {\r
734\r
735 Fixup = FixupBase + (*Reloc & 0xFFF);\r
736 switch ((*Reloc) >> 12) {\r
737 case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
738 break;\r
739\r
740 case EFI_IMAGE_REL_BASED_HIGH:\r
741 F16 = (UINT16 *) Fixup;\r
742 *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
743 if (FixupData != NULL) {\r
744 *(UINT16 *) FixupData = *F16;\r
745 FixupData = FixupData + sizeof (UINT16);\r
746 }\r
747 break;\r
748\r
749 case EFI_IMAGE_REL_BASED_LOW:\r
750 F16 = (UINT16 *) Fixup;\r
751 *F16 = (UINT16) (*F16 + (UINT16) Adjust);\r
752 if (FixupData != NULL) {\r
753 *(UINT16 *) FixupData = *F16;\r
754 FixupData = FixupData + sizeof (UINT16);\r
755 }\r
756 break;\r
757\r
758 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
759 F32 = (UINT32 *) Fixup;\r
760 *F32 = *F32 + (UINT32) Adjust;\r
761 if (FixupData != NULL) {\r
762 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
763 *(UINT32 *) FixupData = *F32;\r
764 FixupData = FixupData + sizeof (UINT32);\r
765 }\r
766 break;\r
767\r
768 case EFI_IMAGE_REL_BASED_HIGHADJ:\r
769 //\r
770 // Return the same EFI_UNSUPPORTED return code as\r
771 // PeCoffLoaderRelocateImageEx() returns if it does not recognize\r
772 // the relocation type.\r
773 //\r
774 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
775 return RETURN_UNSUPPORTED;\r
776\r
777 default:\r
778 switch (MachineType) {\r
779 case EFI_IMAGE_MACHINE_IA32:\r
780 case EFI_IMAGE_MACHINE_ARMT:\r
781 Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust);\r
782 break;\r
783 case EFI_IMAGE_MACHINE_X64:\r
784 Status = PeCoffLoaderRelocateX64Image (Reloc, Fixup, &FixupData, Adjust);\r
785 break;\r
786 case EFI_IMAGE_MACHINE_IA64:\r
787 Status = PeCoffLoaderRelocateIpfImage (Reloc, Fixup, &FixupData, Adjust);\r
788 break;\r
789 default:\r
790 Status = RETURN_UNSUPPORTED;\r
791 break;\r
792 }\r
793 if (RETURN_ERROR (Status)) {\r
794 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
795 return Status;\r
796 }\r
797 }\r
798\r
799 //\r
800 // Next relocation record\r
801 //\r
802 Reloc += 1;\r
803 }\r
804\r
805 //\r
806 // Next reloc block\r
807 //\r
808 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
809 }\r
810\r
811 return RETURN_SUCCESS;\r
812}\r
813\r
814RETURN_STATUS\r
815EFIAPI\r
816PeCoffLoaderLoadImage (\r
817 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
818 )\r
819/*++\r
820\r
821Routine Description:\r
822\r
823 Loads a PE/COFF image into memory\r
824\r
825Arguments:\r
826\r
827 This - Calling context\r
828\r
829 ImageContext - Contains information on image to load into memory\r
830\r
831Returns:\r
832\r
833 RETURN_SUCCESS if the PE/COFF image was loaded\r
834 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer\r
835 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations\r
836 RETURN_INVALID_PARAMETER if the image address is invalid\r
837\r
838--*/\r
839{\r
840 RETURN_STATUS Status;\r
841 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;\r
842 EFI_TE_IMAGE_HEADER *TeHdr;\r
843 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r
844 EFI_IMAGE_SECTION_HEADER *FirstSection;\r
845 EFI_IMAGE_SECTION_HEADER *Section;\r
846 UINTN NumberOfSections;\r
847 UINTN Index;\r
848 CHAR8 *Base;\r
849 CHAR8 *End;\r
850 CHAR8 *MaxEnd;\r
851 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
852 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
853 UINTN Size;\r
854 UINT32 TempDebugEntryRva;\r
855 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;\r
856\r
857 PeHdr = NULL;\r
858 TeHdr = NULL;\r
fd171542 859 OptionHeader.Header = NULL;\r
30fdf114
LG
860 //\r
861 // Assume success\r
862 //\r
863 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
864\r
865 //\r
866 // Copy the provided context info into our local version, get what we\r
867 // can from the original image, and then use that to make sure everything\r
868 // is legit.\r
869 //\r
870 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r
871\r
872 Status = PeCoffLoaderGetImageInfo (&CheckContext);\r
873 if (RETURN_ERROR (Status)) {\r
874 return Status;\r
875 }\r
876\r
877 //\r
878 // Make sure there is enough allocated space for the image being loaded\r
879 //\r
880 if (ImageContext->ImageSize < CheckContext.ImageSize) {\r
881 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
882 return RETURN_BUFFER_TOO_SMALL;\r
883 }\r
884\r
885 //\r
886 // If there's no relocations, then make sure it's not a runtime driver,\r
887 // and that it's being loaded at the linked address.\r
888 //\r
889 if (CheckContext.RelocationsStripped) {\r
890 //\r
891 // If the image does not contain relocations and it is a runtime driver\r
892 // then return an error.\r
893 //\r
894 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
895 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
896 return RETURN_LOAD_ERROR;\r
897 }\r
898 //\r
899 // If the image does not contain relocations, and the requested load address\r
900 // is not the linked address, then return an error.\r
901 //\r
902 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r
903 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
904 return RETURN_INVALID_PARAMETER;\r
905 }\r
906 }\r
907 //\r
908 // Make sure the allocated space has the proper section alignment\r
909 //\r
910 if (!(ImageContext->IsTeImage)) {\r
911 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r
912 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r
913 return RETURN_INVALID_PARAMETER;\r
914 }\r
915 }\r
916 //\r
917 // Read the entire PE/COFF or TE header into memory\r
918 //\r
919 if (!(ImageContext->IsTeImage)) {\r
920 Status = ImageContext->ImageRead (\r
921 ImageContext->Handle,\r
922 0,\r
923 &ImageContext->SizeOfHeaders,\r
924 (VOID *) (UINTN) ImageContext->ImageAddress\r
925 );\r
926\r
927 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)\r
928 ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
929\r
930 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);\r
931 \r
932 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
933 (UINTN)ImageContext->ImageAddress +\r
934 ImageContext->PeCoffHeaderOffset +\r
935 sizeof(UINT32) + \r
936 sizeof(EFI_IMAGE_FILE_HEADER) + \r
937 PeHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
938 );\r
939 NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections);\r
940 } else {\r
941 Status = ImageContext->ImageRead (\r
942 ImageContext->Handle,\r
943 0,\r
944 &ImageContext->SizeOfHeaders,\r
945 (VOID *) (UINTN) ImageContext->ImageAddress\r
946 );\r
947\r
948 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r
949\r
950 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
951 (UINTN)ImageContext->ImageAddress +\r
952 sizeof(EFI_TE_IMAGE_HEADER)\r
953 );\r
954 NumberOfSections = (UINTN) (TeHdr->NumberOfSections);\r
955\r
956 }\r
957\r
958 if (RETURN_ERROR (Status)) {\r
959 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
960 return RETURN_LOAD_ERROR;\r
961 }\r
962\r
963 //\r
964 // Load each section of the image\r
965 //\r
966 Section = FirstSection;\r
967 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
968\r
969 //\r
970 // Compute sections address\r
971 //\r
972 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);\r
973 End = PeCoffLoaderImageAddress (\r
974 ImageContext,\r
975 Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
976 );\r
977 if (ImageContext->IsTeImage) {\r
978 Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r
979 End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r
980 }\r
981\r
982 if (End > MaxEnd) {\r
983 MaxEnd = End;\r
984 }\r
985 //\r
986 // If the base start or end address resolved to 0, then fail.\r
987 //\r
988 if ((Base == NULL) || (End == NULL)) {\r
989 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
990 return RETURN_LOAD_ERROR;\r
991 }\r
992\r
993 //\r
994 // Read the section\r
995 //\r
996 Size = (UINTN) Section->Misc.VirtualSize;\r
997 if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
998 Size = (UINTN) Section->SizeOfRawData;\r
999 }\r
1000\r
1001 if (Section->SizeOfRawData) {\r
1002 if (!(ImageContext->IsTeImage)) {\r
1003 Status = ImageContext->ImageRead (\r
1004 ImageContext->Handle,\r
1005 Section->PointerToRawData,\r
1006 &Size,\r
1007 Base\r
1008 );\r
1009 } else {\r
1010 Status = ImageContext->ImageRead (\r
1011 ImageContext->Handle,\r
1012 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,\r
1013 &Size,\r
1014 Base\r
1015 );\r
1016 }\r
1017\r
1018 if (RETURN_ERROR (Status)) {\r
1019 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1020 return Status;\r
1021 }\r
1022 }\r
1023\r
1024 //\r
1025 // If raw size is less then virt size, zero fill the remaining\r
1026 //\r
1027\r
1028 if (Size < Section->Misc.VirtualSize) {\r
1029 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);\r
1030 }\r
1031\r
1032 //\r
1033 // Next Section\r
1034 //\r
1035 Section += 1;\r
1036 }\r
1037\r
1038 //\r
1039 // Get image's entry point\r
1040 //\r
1041 if (!(ImageContext->IsTeImage)) {\r
1042 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (\r
1043 ImageContext,\r
1044 PeHdr->Pe32.OptionalHeader.AddressOfEntryPoint\r
1045 );\r
1046 } else {\r
1047 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (\r
1048 (UINTN)ImageContext->ImageAddress +\r
1049 (UINTN)TeHdr->AddressOfEntryPoint +\r
1050 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
1051 (UINTN) TeHdr->StrippedSize\r
1052 );\r
1053 }\r
1054\r
1055 //\r
1056 // Determine the size of the fixup data\r
1057 //\r
1058 // Per the PE/COFF spec, you can't assume that a given data directory\r
1059 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
1060 // the optional header to verify a desired directory entry is there.\r
1061 //\r
1062 if (!(ImageContext->IsTeImage)) {\r
1063 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1064 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1065 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)\r
1066 &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1067 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1068 } else {\r
1069 ImageContext->FixupDataSize = 0;\r
1070 }\r
1071 } else {\r
1072 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1073 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)\r
1074 &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1075 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1076 } else {\r
1077 ImageContext->FixupDataSize = 0;\r
1078 }\r
1079 }\r
1080 } else {\r
1081 DirectoryEntry = &TeHdr->DataDirectory[0];\r
1082 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1083 }\r
1084 //\r
1085 // Consumer must allocate a buffer for the relocation fixup log.\r
1086 // Only used for runtime drivers.\r
1087 //\r
1088 ImageContext->FixupData = NULL;\r
1089\r
1090 //\r
1091 // Load the Codeview info if present\r
1092 //\r
1093 if (ImageContext->DebugDirectoryEntryRva != 0) {\r
1094 if (!(ImageContext->IsTeImage)) {\r
1095 DebugEntry = PeCoffLoaderImageAddress (\r
1096 ImageContext,\r
1097 ImageContext->DebugDirectoryEntryRva\r
1098 );\r
1099 } else {\r
1100 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
1101 ImageContext->ImageAddress +\r
1102 ImageContext->DebugDirectoryEntryRva +\r
1103 sizeof(EFI_TE_IMAGE_HEADER) -\r
1104 TeHdr->StrippedSize\r
1105 );\r
1106 }\r
1107\r
1108 if (DebugEntry != NULL) {\r
1109 TempDebugEntryRva = DebugEntry->RVA;\r
1110 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r
1111 Section--;\r
1112 if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
1113 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
1114 } else {\r
1115 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
1116 }\r
1117 }\r
1118\r
1119 if (TempDebugEntryRva != 0) {\r
1120 if (!(ImageContext->IsTeImage)) {\r
1121 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);\r
1122 } else {\r
1123 ImageContext->CodeView = (VOID *)(\r
1124 (UINTN)ImageContext->ImageAddress +\r
1125 (UINTN)TempDebugEntryRva +\r
1126 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
1127 (UINTN) TeHdr->StrippedSize\r
1128 );\r
1129 }\r
1130\r
1131 if (ImageContext->CodeView == NULL) {\r
1132 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1133 return RETURN_LOAD_ERROR;\r
1134 }\r
1135\r
1136 if (DebugEntry->RVA == 0) {\r
1137 Size = DebugEntry->SizeOfData;\r
1138 if (!(ImageContext->IsTeImage)) {\r
1139 Status = ImageContext->ImageRead (\r
1140 ImageContext->Handle,\r
1141 DebugEntry->FileOffset,\r
1142 &Size,\r
1143 ImageContext->CodeView\r
1144 );\r
1145 } else {\r
1146 Status = ImageContext->ImageRead (\r
1147 ImageContext->Handle,\r
1148 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,\r
1149 &Size,\r
1150 ImageContext->CodeView\r
1151 );\r
1152 //\r
1153 // Should we apply fix up to this field according to the size difference between PE and TE?\r
1154 // Because now we maintain TE header fields unfixed, this field will also remain as they are\r
1155 // in original PE image.\r
1156 //\r
1157 }\r
1158\r
1159 if (RETURN_ERROR (Status)) {\r
1160 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1161 return RETURN_LOAD_ERROR;\r
1162 }\r
1163\r
1164 DebugEntry->RVA = TempDebugEntryRva;\r
1165 }\r
1166\r
1167 switch (*(UINT32 *) ImageContext->CodeView) {\r
1168 case CODEVIEW_SIGNATURE_NB10:\r
1169 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
1170 break;\r
1171\r
1172 case CODEVIEW_SIGNATURE_RSDS:\r
1173 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
1174 break;\r
1175\r
1176 default:\r
1177 break;\r
1178 }\r
1179 }\r
1180 }\r
1181 }\r
1182\r
1183 return Status;\r
1184}\r
1185\r
1186/**\r
1187 Returns a pointer to the PDB file name for a raw PE/COFF image that is not\r
1188 loaded into system memory with the PE/COFF Loader Library functions.\r
1189\r
1190 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If\r
1191 the PE/COFF image specified by Pe32Data is not a valid, then NULL is\r
1192 returned. If the PE/COFF image specified by Pe32Data does not contain a\r
1193 debug directory entry, then NULL is returned. If the debug directory entry\r
1194 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,\r
1195 then NULL is returned.\r
1196 If Pe32Data is NULL, then return NULL.\r
1197\r
1198 @param Pe32Data Pointer to the PE/COFF image that is loaded in system\r
1199 memory.\r
1200\r
1201 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL\r
1202 if it cannot be retrieved.\r
1203\r
1204**/\r
1205VOID *\r
1206EFIAPI\r
1207PeCoffLoaderGetPdbPointer (\r
1208 IN VOID *Pe32Data\r
1209 )\r
1210{\r
1211 EFI_IMAGE_DOS_HEADER *DosHdr;\r
1212 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
1213 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
1214 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
1215 UINTN DirCount;\r
1216 VOID *CodeViewEntryPointer;\r
1217 INTN TEImageAdjust;\r
1218 UINT32 NumberOfRvaAndSizes;\r
1219 UINT16 Magic;\r
1220 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
1221 UINT32 Index, Index1;\r
1222\r
1223 if (Pe32Data == NULL) {\r
1224 return NULL;\r
1225 }\r
1226\r
1227 TEImageAdjust = 0;\r
1228 DirectoryEntry = NULL;\r
1229 DebugEntry = NULL;\r
1230 NumberOfRvaAndSizes = 0;\r
1231 Index = 0;\r
1232 Index1 = 0;\r
1233 SectionHeader = NULL;\r
1234\r
1235 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
1236 if (EFI_IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {\r
1237 //\r
1238 // DOS image header is present, so read the PE header after the DOS image header.\r
1239 //\r
1240 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
1241 } else {\r
1242 //\r
1243 // DOS image header is not present, so PE header is at the image base.\r
1244 //\r
1245 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
1246 }\r
1247\r
1248 if (EFI_TE_IMAGE_HEADER_SIGNATURE == Hdr.Te->Signature) {\r
1249 if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {\r
1250 DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
1251 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;\r
1252 \r
1253 //\r
1254 // Get the DebugEntry offset in the raw data image.\r
1255 //\r
fd171542 1256 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (Hdr.Te + 1);\r
1257 Index = Hdr.Te->NumberOfSections;\r
30fdf114 1258 for (Index1 = 0; Index1 < Index; Index1 ++) {\r
fd171542 1259 if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) && \r
1260 (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {\r
30fdf114
LG
1261 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +\r
1262 DirectoryEntry->VirtualAddress - \r
1263 SectionHeader [Index1].VirtualAddress + \r
1264 SectionHeader [Index1].PointerToRawData + \r
1265 TEImageAdjust);\r
1266 break;\r
1267 }\r
1268 }\r
1269 }\r
1270 } else if (EFI_IMAGE_NT_SIGNATURE == Hdr.Pe32->Signature) {\r
1271 //\r
1272 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.\r
1273 // It is due to backward-compatibility, for some system might\r
1274 // generate PE32+ image with PE32 Magic.\r
1275 //\r
1276 switch (Hdr.Pe32->FileHeader.Machine) {\r
1277 case EFI_IMAGE_MACHINE_IA32:\r
1278 case EFI_IMAGE_MACHINE_ARMT:\r
1279 //\r
1280 // Assume PE32 image with IA32 Machine field.\r
1281 //\r
1282 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
1283 break;\r
1284 case EFI_IMAGE_MACHINE_X64:\r
1285 case EFI_IMAGE_MACHINE_IPF:\r
1286 //\r
1287 // Assume PE32+ image with X64 or IPF Machine field\r
1288 //\r
1289 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1290 break;\r
1291 default:\r
1292 //\r
1293 // For unknow Machine field, use Magic in optional Header\r
1294 //\r
1295 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
1296 }\r
1297\r
1298 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
1299 (UINT8 *) Hdr.Pe32 +\r
1300 sizeof (UINT32) + \r
1301 sizeof (EFI_IMAGE_FILE_HEADER) + \r
1302 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
1303 );\r
1304 Index = Hdr.Pe32->FileHeader.NumberOfSections;\r
1305\r
1306 if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC == Magic) {\r
1307 //\r
1308 // Use PE32 offset get Debug Directory Entry\r
1309 //\r
1310 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
1311 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
1312 } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
1313 //\r
1314 // Use PE32+ offset get Debug Directory Entry\r
1315 //\r
1316 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
1317 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
1318 }\r
1319\r
1320 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG || DirectoryEntry->VirtualAddress == 0) {\r
1321 DirectoryEntry = NULL;\r
1322 DebugEntry = NULL;\r
1323 } else {\r
1324 //\r
1325 // Get the DebugEntry offset in the raw data image.\r
1326 //\r
1327 for (Index1 = 0; Index1 < Index; Index1 ++) {\r
fd171542 1328 if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) && \r
1329 (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {\r
30fdf114
LG
1330 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (\r
1331 (UINTN) Pe32Data + \r
1332 DirectoryEntry->VirtualAddress - \r
1333 SectionHeader[Index1].VirtualAddress + \r
1334 SectionHeader[Index1].PointerToRawData);\r
1335 break;\r
1336 }\r
1337 }\r
1338 }\r
1339 } else {\r
1340 return NULL;\r
1341 }\r
1342\r
1343 if (NULL == DebugEntry || NULL == DirectoryEntry) {\r
1344 return NULL;\r
1345 }\r
1346\r
1347 //\r
1348 // Scan the directory to find the debug entry.\r
1349 // \r
1350 for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {\r
1351 if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW == DebugEntry->Type) {\r
1352 if (DebugEntry->SizeOfData > 0) {\r
fd171542 1353 //\r
1354 // Get the DebugEntry offset in the raw data image.\r
1355 //\r
1356 CodeViewEntryPointer = NULL;\r
1357 for (Index1 = 0; Index1 < Index; Index1 ++) {\r
1358 if ((DebugEntry->RVA >= SectionHeader[Index1].VirtualAddress) && \r
1359 (DebugEntry->RVA < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {\r
1360 CodeViewEntryPointer = (VOID *) (\r
1361 ((UINTN)Pe32Data) + \r
1362 (UINTN) DebugEntry->RVA - \r
1363 SectionHeader[Index1].VirtualAddress + \r
1364 SectionHeader[Index1].PointerToRawData + \r
1365 (UINTN)TEImageAdjust);\r
1366 break;\r
1367 }\r
1368 }\r
1369 if (Index1 >= Index) {\r
1370 //\r
1371 // Can't find CodeViewEntryPointer in raw PE/COFF image.\r
1372 //\r
1373 continue;\r
1374 }\r
30fdf114
LG
1375 switch (* (UINT32 *) CodeViewEntryPointer) {\r
1376 case CODEVIEW_SIGNATURE_NB10:\r
1377 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));\r
1378 case CODEVIEW_SIGNATURE_RSDS:\r
1379 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));\r
1380 default:\r
1381 break;\r
1382 }\r
1383 }\r
1384 }\r
1385 }\r
1386\r
1387 return NULL;\r
1388}\r