]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/Common/BasePeCoff.c
Check In tool source code based on Build tool project revision r1655.
[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 //
860 // Assume success
861 //
862 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
863
864 //
865 // Copy the provided context info into our local version, get what we
866 // can from the original image, and then use that to make sure everything
867 // is legit.
868 //
869 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
870
871 Status = PeCoffLoaderGetImageInfo (&CheckContext);
872 if (RETURN_ERROR (Status)) {
873 return Status;
874 }
875
876 //
877 // Make sure there is enough allocated space for the image being loaded
878 //
879 if (ImageContext->ImageSize < CheckContext.ImageSize) {
880 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
881 return RETURN_BUFFER_TOO_SMALL;
882 }
883
884 //
885 // If there's no relocations, then make sure it's not a runtime driver,
886 // and that it's being loaded at the linked address.
887 //
888 if (CheckContext.RelocationsStripped) {
889 //
890 // If the image does not contain relocations and it is a runtime driver
891 // then return an error.
892 //
893 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
894 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
895 return RETURN_LOAD_ERROR;
896 }
897 //
898 // If the image does not contain relocations, and the requested load address
899 // is not the linked address, then return an error.
900 //
901 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
902 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
903 return RETURN_INVALID_PARAMETER;
904 }
905 }
906 //
907 // Make sure the allocated space has the proper section alignment
908 //
909 if (!(ImageContext->IsTeImage)) {
910 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
911 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
912 return RETURN_INVALID_PARAMETER;
913 }
914 }
915 //
916 // Read the entire PE/COFF or TE header into memory
917 //
918 if (!(ImageContext->IsTeImage)) {
919 Status = ImageContext->ImageRead (
920 ImageContext->Handle,
921 0,
922 &ImageContext->SizeOfHeaders,
923 (VOID *) (UINTN) ImageContext->ImageAddress
924 );
925
926 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)
927 ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
928
929 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
930
931 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
932 (UINTN)ImageContext->ImageAddress +
933 ImageContext->PeCoffHeaderOffset +
934 sizeof(UINT32) +
935 sizeof(EFI_IMAGE_FILE_HEADER) +
936 PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
937 );
938 NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections);
939 } else {
940 Status = ImageContext->ImageRead (
941 ImageContext->Handle,
942 0,
943 &ImageContext->SizeOfHeaders,
944 (VOID *) (UINTN) ImageContext->ImageAddress
945 );
946
947 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
948
949 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
950 (UINTN)ImageContext->ImageAddress +
951 sizeof(EFI_TE_IMAGE_HEADER)
952 );
953 NumberOfSections = (UINTN) (TeHdr->NumberOfSections);
954
955 }
956
957 if (RETURN_ERROR (Status)) {
958 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
959 return RETURN_LOAD_ERROR;
960 }
961
962 //
963 // Load each section of the image
964 //
965 Section = FirstSection;
966 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {
967
968 //
969 // Compute sections address
970 //
971 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);
972 End = PeCoffLoaderImageAddress (
973 ImageContext,
974 Section->VirtualAddress + Section->Misc.VirtualSize - 1
975 );
976 if (ImageContext->IsTeImage) {
977 Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
978 End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
979 }
980
981 if (End > MaxEnd) {
982 MaxEnd = End;
983 }
984 //
985 // If the base start or end address resolved to 0, then fail.
986 //
987 if ((Base == NULL) || (End == NULL)) {
988 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
989 return RETURN_LOAD_ERROR;
990 }
991
992 //
993 // Read the section
994 //
995 Size = (UINTN) Section->Misc.VirtualSize;
996 if ((Size == 0) || (Size > Section->SizeOfRawData)) {
997 Size = (UINTN) Section->SizeOfRawData;
998 }
999
1000 if (Section->SizeOfRawData) {
1001 if (!(ImageContext->IsTeImage)) {
1002 Status = ImageContext->ImageRead (
1003 ImageContext->Handle,
1004 Section->PointerToRawData,
1005 &Size,
1006 Base
1007 );
1008 } else {
1009 Status = ImageContext->ImageRead (
1010 ImageContext->Handle,
1011 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,
1012 &Size,
1013 Base
1014 );
1015 }
1016
1017 if (RETURN_ERROR (Status)) {
1018 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1019 return Status;
1020 }
1021 }
1022
1023 //
1024 // If raw size is less then virt size, zero fill the remaining
1025 //
1026
1027 if (Size < Section->Misc.VirtualSize) {
1028 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
1029 }
1030
1031 //
1032 // Next Section
1033 //
1034 Section += 1;
1035 }
1036
1037 //
1038 // Get image's entry point
1039 //
1040 if (!(ImageContext->IsTeImage)) {
1041 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (
1042 ImageContext,
1043 PeHdr->Pe32.OptionalHeader.AddressOfEntryPoint
1044 );
1045 } else {
1046 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (
1047 (UINTN)ImageContext->ImageAddress +
1048 (UINTN)TeHdr->AddressOfEntryPoint +
1049 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1050 (UINTN) TeHdr->StrippedSize
1051 );
1052 }
1053
1054 //
1055 // Determine the size of the fixup data
1056 //
1057 // Per the PE/COFF spec, you can't assume that a given data directory
1058 // is present in the image. You have to check the NumberOfRvaAndSizes in
1059 // the optional header to verify a desired directory entry is there.
1060 //
1061 if (!(ImageContext->IsTeImage)) {
1062 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1063 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1064 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
1065 &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1066 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1067 } else {
1068 ImageContext->FixupDataSize = 0;
1069 }
1070 } else {
1071 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1072 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
1073 &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1074 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1075 } else {
1076 ImageContext->FixupDataSize = 0;
1077 }
1078 }
1079 } else {
1080 DirectoryEntry = &TeHdr->DataDirectory[0];
1081 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1082 }
1083 //
1084 // Consumer must allocate a buffer for the relocation fixup log.
1085 // Only used for runtime drivers.
1086 //
1087 ImageContext->FixupData = NULL;
1088
1089 //
1090 // Load the Codeview info if present
1091 //
1092 if (ImageContext->DebugDirectoryEntryRva != 0) {
1093 if (!(ImageContext->IsTeImage)) {
1094 DebugEntry = PeCoffLoaderImageAddress (
1095 ImageContext,
1096 ImageContext->DebugDirectoryEntryRva
1097 );
1098 } else {
1099 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
1100 ImageContext->ImageAddress +
1101 ImageContext->DebugDirectoryEntryRva +
1102 sizeof(EFI_TE_IMAGE_HEADER) -
1103 TeHdr->StrippedSize
1104 );
1105 }
1106
1107 if (DebugEntry != NULL) {
1108 TempDebugEntryRva = DebugEntry->RVA;
1109 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
1110 Section--;
1111 if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {
1112 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
1113 } else {
1114 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
1115 }
1116 }
1117
1118 if (TempDebugEntryRva != 0) {
1119 if (!(ImageContext->IsTeImage)) {
1120 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);
1121 } else {
1122 ImageContext->CodeView = (VOID *)(
1123 (UINTN)ImageContext->ImageAddress +
1124 (UINTN)TempDebugEntryRva +
1125 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1126 (UINTN) TeHdr->StrippedSize
1127 );
1128 }
1129
1130 if (ImageContext->CodeView == NULL) {
1131 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1132 return RETURN_LOAD_ERROR;
1133 }
1134
1135 if (DebugEntry->RVA == 0) {
1136 Size = DebugEntry->SizeOfData;
1137 if (!(ImageContext->IsTeImage)) {
1138 Status = ImageContext->ImageRead (
1139 ImageContext->Handle,
1140 DebugEntry->FileOffset,
1141 &Size,
1142 ImageContext->CodeView
1143 );
1144 } else {
1145 Status = ImageContext->ImageRead (
1146 ImageContext->Handle,
1147 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,
1148 &Size,
1149 ImageContext->CodeView
1150 );
1151 //
1152 // Should we apply fix up to this field according to the size difference between PE and TE?
1153 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1154 // in original PE image.
1155 //
1156 }
1157
1158 if (RETURN_ERROR (Status)) {
1159 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1160 return RETURN_LOAD_ERROR;
1161 }
1162
1163 DebugEntry->RVA = TempDebugEntryRva;
1164 }
1165
1166 switch (*(UINT32 *) ImageContext->CodeView) {
1167 case CODEVIEW_SIGNATURE_NB10:
1168 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
1169 break;
1170
1171 case CODEVIEW_SIGNATURE_RSDS:
1172 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
1173 break;
1174
1175 default:
1176 break;
1177 }
1178 }
1179 }
1180 }
1181
1182 return Status;
1183 }
1184
1185 /**
1186 Returns a pointer to the PDB file name for a raw PE/COFF image that is not
1187 loaded into system memory with the PE/COFF Loader Library functions.
1188
1189 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If
1190 the PE/COFF image specified by Pe32Data is not a valid, then NULL is
1191 returned. If the PE/COFF image specified by Pe32Data does not contain a
1192 debug directory entry, then NULL is returned. If the debug directory entry
1193 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
1194 then NULL is returned.
1195 If Pe32Data is NULL, then return NULL.
1196
1197 @param Pe32Data Pointer to the PE/COFF image that is loaded in system
1198 memory.
1199
1200 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
1201 if it cannot be retrieved.
1202
1203 **/
1204 VOID *
1205 EFIAPI
1206 PeCoffLoaderGetPdbPointer (
1207 IN VOID *Pe32Data
1208 )
1209 {
1210 EFI_IMAGE_DOS_HEADER *DosHdr;
1211 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1212 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
1213 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
1214 UINTN DirCount;
1215 VOID *CodeViewEntryPointer;
1216 INTN TEImageAdjust;
1217 UINT32 NumberOfRvaAndSizes;
1218 UINT16 Magic;
1219 EFI_IMAGE_SECTION_HEADER *SectionHeader;
1220 UINT32 Index, Index1;
1221
1222 if (Pe32Data == NULL) {
1223 return NULL;
1224 }
1225
1226 TEImageAdjust = 0;
1227 DirectoryEntry = NULL;
1228 DebugEntry = NULL;
1229 NumberOfRvaAndSizes = 0;
1230 Index = 0;
1231 Index1 = 0;
1232 SectionHeader = NULL;
1233
1234 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
1235 if (EFI_IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
1236 //
1237 // DOS image header is present, so read the PE header after the DOS image header.
1238 //
1239 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
1240 } else {
1241 //
1242 // DOS image header is not present, so PE header is at the image base.
1243 //
1244 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
1245 }
1246
1247 if (EFI_TE_IMAGE_HEADER_SIGNATURE == Hdr.Te->Signature) {
1248 if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {
1249 DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];
1250 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
1251
1252 //
1253 // Get the DebugEntry offset in the raw data image.
1254 //
1255 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (Hdr.Te + 1);
1256 Index = Hdr.Te->NumberOfSections;
1257 for (Index1 = 0; Index1 < Index; Index1 ++) {
1258 if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
1259 (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1260 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +
1261 DirectoryEntry->VirtualAddress -
1262 SectionHeader [Index1].VirtualAddress +
1263 SectionHeader [Index1].PointerToRawData +
1264 TEImageAdjust);
1265 break;
1266 }
1267 }
1268 }
1269 } else if (EFI_IMAGE_NT_SIGNATURE == Hdr.Pe32->Signature) {
1270 //
1271 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
1272 // It is due to backward-compatibility, for some system might
1273 // generate PE32+ image with PE32 Magic.
1274 //
1275 switch (Hdr.Pe32->FileHeader.Machine) {
1276 case EFI_IMAGE_MACHINE_IA32:
1277 case EFI_IMAGE_MACHINE_ARMT:
1278 //
1279 // Assume PE32 image with IA32 Machine field.
1280 //
1281 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
1282 break;
1283 case EFI_IMAGE_MACHINE_X64:
1284 case EFI_IMAGE_MACHINE_IPF:
1285 //
1286 // Assume PE32+ image with X64 or IPF Machine field
1287 //
1288 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1289 break;
1290 default:
1291 //
1292 // For unknow Machine field, use Magic in optional Header
1293 //
1294 Magic = Hdr.Pe32->OptionalHeader.Magic;
1295 }
1296
1297 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
1298 (UINT8 *) Hdr.Pe32 +
1299 sizeof (UINT32) +
1300 sizeof (EFI_IMAGE_FILE_HEADER) +
1301 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
1302 );
1303 Index = Hdr.Pe32->FileHeader.NumberOfSections;
1304
1305 if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC == Magic) {
1306 //
1307 // Use PE32 offset get Debug Directory Entry
1308 //
1309 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1310 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
1311 } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1312 //
1313 // Use PE32+ offset get Debug Directory Entry
1314 //
1315 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1316 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
1317 }
1318
1319 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG || DirectoryEntry->VirtualAddress == 0) {
1320 DirectoryEntry = NULL;
1321 DebugEntry = NULL;
1322 } else {
1323 //
1324 // Get the DebugEntry offset in the raw data image.
1325 //
1326 for (Index1 = 0; Index1 < Index; Index1 ++) {
1327 if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
1328 (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1329 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (
1330 (UINTN) Pe32Data +
1331 DirectoryEntry->VirtualAddress -
1332 SectionHeader[Index1].VirtualAddress +
1333 SectionHeader[Index1].PointerToRawData);
1334 break;
1335 }
1336 }
1337 }
1338 } else {
1339 return NULL;
1340 }
1341
1342 if (NULL == DebugEntry || NULL == DirectoryEntry) {
1343 return NULL;
1344 }
1345
1346 //
1347 // Scan the directory to find the debug entry.
1348 //
1349 for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {
1350 if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW == DebugEntry->Type) {
1351 if (DebugEntry->SizeOfData > 0) {
1352 //
1353 // Get the DebugEntry offset in the raw data image.
1354 //
1355 for (Index1 = 0; Index1 < Index; Index1 ++) {
1356 if ((DebugEntry->RVA >= SectionHeader[Index1].VirtualAddress) &&
1357 (DebugEntry->RVA < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1358 CodeViewEntryPointer = (VOID *) (
1359 ((UINTN)Pe32Data) +
1360 (UINTN) DebugEntry->RVA -
1361 SectionHeader[Index1].VirtualAddress +
1362 SectionHeader[Index1].PointerToRawData +
1363 (UINTN)TEImageAdjust);
1364 break;
1365 }
1366 }
1367 if (Index1 >= Index) {
1368 //
1369 // Can't find CodeViewEntryPointer in raw PE/COFF image.
1370 //
1371 continue;
1372 }
1373 switch (* (UINT32 *) CodeViewEntryPointer) {
1374 case CODEVIEW_SIGNATURE_NB10:
1375 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));
1376 case CODEVIEW_SIGNATURE_RSDS:
1377 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));
1378 default:
1379 break;
1380 }
1381 }
1382 }
1383 }
1384
1385 return NULL;
1386 }