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