878ddf1f |
1 | /** @file\r |
2 | Tiano PE/COFF loader.\r |
3 | \r |
4 | Copyright (c) 2006, Intel Corporation\r |
5 | All rights reserved. This program and the accompanying materials\r |
6 | are licensed and made available under the terms and conditions of the BSD License\r |
7 | which accompanies this distribution. The full text of the license may be found at\r |
8 | http://opensource.org/licenses/bsd-license.php\r |
9 | \r |
10 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r |
11 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r |
12 | \r |
13 | Module Name: PeCoffLoader.c\r |
14 | \r |
15 | **/\r |
16 | \r |
4ba61e5e |
17 | /**\r |
18 | Performs an Itanium-based specific relocation fixup.\r |
878ddf1f |
19 | \r |
4ba61e5e |
20 | @param Reloc Pointer to the relocation record.\r |
21 | @param Fixup Pointer to the address to fix up.\r |
22 | @param FixupData Pointer to a buffer to log the fixups.\r |
23 | @param Adjust The offset to adjust the fixup.\r |
878ddf1f |
24 | \r |
4ba61e5e |
25 | @return Status code.\r |
878ddf1f |
26 | \r |
4ba61e5e |
27 | **/\r |
878ddf1f |
28 | RETURN_STATUS\r |
29 | PeCoffLoaderRelocateImageEx (\r |
30 | IN UINT16 *Reloc,\r |
31 | IN OUT CHAR8 *Fixup,\r |
32 | IN OUT CHAR8 **FixupData,\r |
33 | IN UINT64 Adjust\r |
34 | );\r |
35 | \r |
36 | \r |
37 | \r |
38 | /**\r |
39 | Retrieves the PE or TE Header from a PE/COFF or TE image.\r |
40 | \r |
cd14fe3d |
41 | @param ImageContext The context of the image being loaded.\r |
42 | @param PeHdr The buffer in which to return the PE header.\r |
43 | @param TeHdr The buffer in which to return the TE header.\r |
878ddf1f |
44 | \r |
cd14fe3d |
45 | @retval RETURN_SUCCESS The PE or TE Header is read.\r |
46 | @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.\r |
878ddf1f |
47 | \r |
48 | **/\r |
49 | STATIC\r |
50 | RETURN_STATUS\r |
51 | PeCoffLoaderGetPeHeader (\r |
52 | IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r |
53 | OUT EFI_IMAGE_NT_HEADERS *PeHdr,\r |
54 | OUT EFI_TE_IMAGE_HEADER *TeHdr\r |
55 | )\r |
56 | {\r |
cd14fe3d |
57 | RETURN_STATUS Status;\r |
878ddf1f |
58 | EFI_IMAGE_DOS_HEADER DosHdr;\r |
59 | UINTN Size;\r |
60 | \r |
61 | ImageContext->IsTeImage = FALSE;\r |
62 | //\r |
63 | // Read the DOS image headers\r |
64 | //\r |
65 | Size = sizeof (EFI_IMAGE_DOS_HEADER);\r |
66 | Status = ImageContext->ImageRead (\r |
cd14fe3d |
67 | ImageContext->Handle,\r |
68 | 0,\r |
69 | &Size,\r |
70 | &DosHdr\r |
71 | );\r |
878ddf1f |
72 | if (RETURN_ERROR (Status)) {\r |
73 | ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r |
74 | return Status;\r |
75 | }\r |
76 | \r |
77 | ImageContext->PeCoffHeaderOffset = 0;\r |
78 | if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r |
79 | //\r |
80 | // DOS image header is present, so read the PE header after the DOS image header\r |
81 | //\r |
82 | ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;\r |
83 | }\r |
84 | //\r |
85 | // Read the PE/COFF Header\r |
86 | //\r |
87 | Size = sizeof (EFI_IMAGE_NT_HEADERS);\r |
88 | Status = ImageContext->ImageRead (\r |
cd14fe3d |
89 | ImageContext->Handle,\r |
90 | ImageContext->PeCoffHeaderOffset,\r |
91 | &Size,\r |
92 | PeHdr\r |
93 | );\r |
878ddf1f |
94 | if (RETURN_ERROR (Status)) {\r |
95 | ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r |
96 | return Status;\r |
97 | }\r |
98 | //\r |
99 | // Check the PE/COFF Header Signature. If not, then try to read a TE header\r |
100 | //\r |
101 | if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r |
102 | Size = sizeof (EFI_TE_IMAGE_HEADER);\r |
103 | Status = ImageContext->ImageRead (\r |
cd14fe3d |
104 | ImageContext->Handle,\r |
105 | 0,\r |
106 | &Size,\r |
107 | TeHdr\r |
108 | );\r |
878ddf1f |
109 | if (TeHdr->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {\r |
110 | return RETURN_UNSUPPORTED;\r |
111 | }\r |
112 | \r |
113 | ImageContext->IsTeImage = TRUE;\r |
114 | }\r |
115 | \r |
116 | return RETURN_SUCCESS;\r |
117 | }\r |
118 | \r |
119 | /**\r |
120 | Checks the PE or TE header of a PE/COFF or TE image to determine if it supported.\r |
121 | \r |
cd14fe3d |
122 | @param ImageContext The context of the image being loaded.\r |
123 | @param PeHdr The buffer in which to return the PE header.\r |
124 | @param TeHdr The buffer in which to return the TE header.\r |
878ddf1f |
125 | \r |
cd14fe3d |
126 | @retval RETURN_SUCCESS The PE/COFF or TE image is supported.\r |
127 | @retval RETURN_UNSUPPORTED The PE/COFF or TE image is not supported.\r |
878ddf1f |
128 | \r |
129 | **/\r |
130 | STATIC\r |
131 | RETURN_STATUS\r |
132 | PeCoffLoaderCheckImageType (\r |
133 | IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r |
134 | IN EFI_IMAGE_NT_HEADERS *PeHdr,\r |
135 | IN EFI_TE_IMAGE_HEADER *TeHdr\r |
136 | )\r |
137 | {\r |
138 | //\r |
139 | // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)\r |
140 | // and the machine type for the Virtual Machine.\r |
141 | //\r |
142 | if (ImageContext->IsTeImage == FALSE) {\r |
143 | ImageContext->Machine = PeHdr->FileHeader.Machine;\r |
144 | } else {\r |
145 | ImageContext->Machine = TeHdr->Machine;\r |
146 | }\r |
147 | \r |
148 | if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext->Machine))) {\r |
149 | ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r |
150 | return RETURN_UNSUPPORTED;\r |
151 | }\r |
152 | \r |
153 | //\r |
154 | // See if the image type is supported. We support EFI Applications,\r |
155 | // EFI Boot Service Drivers, and EFI Runtime Drivers.\r |
156 | //\r |
157 | if (ImageContext->IsTeImage == FALSE) {\r |
158 | ImageContext->ImageType = PeHdr->OptionalHeader.Subsystem;\r |
159 | } else {\r |
160 | ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);\r |
161 | }\r |
162 | \r |
163 | \r |
164 | return RETURN_SUCCESS;\r |
165 | }\r |
166 | \r |
167 | /**\r |
cd14fe3d |
168 | Retrieves information about a PE/COFF image.\r |
169 | \r |
170 | Computes the PeCoffHeaderOffset, ImageAddress, ImageSize, DestinationAddress, CodeView,\r |
171 | PdbPointer, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva\r |
172 | fields of the ImageContext structure. If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.\r |
173 | If the PE/COFF image accessed through the ImageRead service in the ImageContext structure is not\r |
174 | a supported PE/COFF image type, then return RETURN_UNSUPPORTED. If any errors occur while\r |
175 | computing the fields of ImageContext, then the error status is returned in the ImageError field of\r |
176 | ImageContext. \r |
878ddf1f |
177 | \r |
cd14fe3d |
178 | @param ImageContext Pointer to the image context structure that describes the PE/COFF\r |
179 | image that needs to be examined by this function.\r |
878ddf1f |
180 | \r |
4ba61e5e |
181 | @retval RETURN_SUCCESS The information on the PE/COFF image was collected.\r |
182 | @retval RETURN_INVALID_PARAMETER ImageContext is NULL.\r |
183 | @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.\r |
878ddf1f |
184 | \r |
185 | **/\r |
186 | RETURN_STATUS\r |
187 | EFIAPI\r |
188 | PeCoffLoaderGetImageInfo (\r |
189 | IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r |
190 | )\r |
191 | {\r |
cd14fe3d |
192 | RETURN_STATUS Status;\r |
878ddf1f |
193 | EFI_IMAGE_NT_HEADERS PeHdr;\r |
194 | EFI_TE_IMAGE_HEADER TeHdr;\r |
195 | EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;\r |
196 | UINTN Size;\r |
197 | UINTN Index;\r |
198 | UINTN DebugDirectoryEntryRva;\r |
199 | UINTN DebugDirectoryEntryFileOffset;\r |
200 | UINTN SectionHeaderOffset;\r |
201 | EFI_IMAGE_SECTION_HEADER SectionHeader;\r |
202 | EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;\r |
203 | \r |
204 | if (NULL == ImageContext) {\r |
205 | return RETURN_INVALID_PARAMETER;\r |
206 | }\r |
207 | //\r |
208 | // Assume success\r |
209 | //\r |
210 | ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r |
211 | \r |
212 | Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);\r |
213 | if (RETURN_ERROR (Status)) {\r |
214 | return Status;\r |
215 | }\r |
216 | //\r |
217 | // Verify machine type\r |
218 | //\r |
219 | Status = PeCoffLoaderCheckImageType (ImageContext, &PeHdr, &TeHdr);\r |
220 | if (RETURN_ERROR (Status)) {\r |
221 | return Status;\r |
222 | }\r |
223 | //\r |
224 | // Retrieve the base address of the image\r |
225 | //\r |
226 | if (!(ImageContext->IsTeImage)) {\r |
227 | ImageContext->ImageAddress = PeHdr.OptionalHeader.ImageBase;\r |
228 | } else {\r |
229 | ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr.ImageBase);\r |
230 | }\r |
231 | //\r |
232 | // Initialize the alternate destination address to 0 indicating that it\r |
233 | // should not be used.\r |
234 | //\r |
235 | ImageContext->DestinationAddress = 0;\r |
236 | \r |
237 | //\r |
238 | // Initialize the codeview pointer.\r |
239 | //\r |
240 | ImageContext->CodeView = NULL;\r |
241 | ImageContext->PdbPointer = NULL;\r |
242 | \r |
243 | //\r |
244 | // Three cases with regards to relocations:\r |
245 | // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable\r |
246 | // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r |
247 | // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r |
248 | // has no base relocs to apply\r |
249 | // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r |
250 | //\r |
251 | // Look at the file header to determine if relocations have been stripped, and\r |
252 | // save this info in the image context for later use.\r |
253 | //\r |
254 | if ((!(ImageContext->IsTeImage)) && ((PeHdr.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {\r |
255 | ImageContext->RelocationsStripped = TRUE;\r |
256 | } else {\r |
257 | ImageContext->RelocationsStripped = FALSE;\r |
258 | }\r |
259 | \r |
260 | if (!(ImageContext->IsTeImage)) {\r |
261 | ImageContext->ImageSize = (UINT64) PeHdr.OptionalHeader.SizeOfImage;\r |
262 | ImageContext->SectionAlignment = PeHdr.OptionalHeader.SectionAlignment;\r |
263 | ImageContext->SizeOfHeaders = PeHdr.OptionalHeader.SizeOfHeaders;\r |
264 | \r |
265 | //\r |
266 | // Modify ImageSize to contain .PDB file name if required and initialize\r |
267 | // PdbRVA field...\r |
268 | //\r |
269 | if (PeHdr.OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r |
270 | DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r |
271 | \r |
272 | DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r |
273 | \r |
274 | //\r |
275 | // Determine the file offset of the debug directory... This means we walk\r |
276 | // the sections to find which section contains the RVA of the debug\r |
277 | // directory\r |
278 | //\r |
279 | DebugDirectoryEntryFileOffset = 0;\r |
280 | \r |
281 | SectionHeaderOffset = (UINTN)(\r |
282 | ImageContext->PeCoffHeaderOffset +\r |
283 | sizeof (UINT32) + \r |
284 | sizeof (EFI_IMAGE_FILE_HEADER) + \r |
285 | PeHdr.FileHeader.SizeOfOptionalHeader\r |
286 | );\r |
287 | \r |
288 | for (Index = 0; Index < PeHdr.FileHeader.NumberOfSections; Index++) {\r |
289 | //\r |
290 | // Read section header from file\r |
291 | //\r |
292 | Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r |
293 | Status = ImageContext->ImageRead (\r |
294 | ImageContext->Handle,\r |
295 | SectionHeaderOffset,\r |
296 | &Size,\r |
297 | &SectionHeader\r |
298 | );\r |
299 | if (RETURN_ERROR (Status)) {\r |
300 | ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r |
301 | return Status;\r |
302 | }\r |
303 | \r |
304 | if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r |
305 | DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r |
306 | DebugDirectoryEntryFileOffset =\r |
307 | DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r |
308 | break;\r |
309 | }\r |
310 | \r |
311 | SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r |
312 | }\r |
313 | \r |
314 | if (DebugDirectoryEntryFileOffset != 0) {\r |
315 | for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r |
316 | //\r |
317 | // Read next debug directory entry\r |
318 | //\r |
319 | Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r |
320 | Status = ImageContext->ImageRead (\r |
321 | ImageContext->Handle,\r |
322 | DebugDirectoryEntryFileOffset,\r |
323 | &Size,\r |
324 | &DebugEntry\r |
325 | );\r |
326 | if (RETURN_ERROR (Status)) {\r |
327 | ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r |
328 | return Status;\r |
329 | }\r |
330 | \r |
331 | if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r |
332 | ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r |
333 | if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r |
334 | ImageContext->ImageSize += DebugEntry.SizeOfData;\r |
335 | }\r |
336 | \r |
337 | return RETURN_SUCCESS;\r |
338 | }\r |
339 | }\r |
340 | }\r |
341 | }\r |
342 | } else {\r |
343 | ImageContext->ImageSize = 0;\r |
344 | ImageContext->SectionAlignment = 4096;\r |
345 | ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr.BaseOfCode - (UINTN) TeHdr.StrippedSize;\r |
346 | \r |
347 | DebugDirectoryEntry = &TeHdr.DataDirectory[1];\r |
348 | DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r |
349 | SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));\r |
350 | \r |
351 | DebugDirectoryEntryFileOffset = 0;\r |
352 | \r |
353 | for (Index = 0; Index < TeHdr.NumberOfSections;) {\r |
354 | //\r |
355 | // Read section header from file\r |
356 | //\r |
cd14fe3d |
357 | Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r |
878ddf1f |
358 | Status = ImageContext->ImageRead (\r |
359 | ImageContext->Handle,\r |
360 | SectionHeaderOffset,\r |
361 | &Size,\r |
362 | &SectionHeader\r |
363 | );\r |
364 | if (RETURN_ERROR (Status)) {\r |
365 | ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r |
366 | return Status;\r |
367 | }\r |
368 | \r |
369 | if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r |
370 | DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r |
371 | DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -\r |
cd14fe3d |
372 | SectionHeader.VirtualAddress +\r |
373 | SectionHeader.PointerToRawData +\r |
374 | sizeof (EFI_TE_IMAGE_HEADER) -\r |
375 | TeHdr.StrippedSize;\r |
878ddf1f |
376 | \r |
377 | //\r |
378 | // File offset of the debug directory was found, if this is not the last\r |
379 | // section, then skip to the last section for calculating the image size.\r |
380 | //\r |
381 | if (Index < (UINTN) TeHdr.NumberOfSections - 1) {\r |
382 | SectionHeaderOffset += (TeHdr.NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);\r |
383 | Index = TeHdr.NumberOfSections - 1;\r |
384 | continue;\r |
385 | }\r |
386 | }\r |
387 | \r |
388 | //\r |
389 | // In Te image header there is not a field to describe the ImageSize.\r |
390 | // Actually, the ImageSize equals the RVA plus the VirtualSize of \r |
391 | // the last section mapped into memory (Must be rounded up to \r |
392 | // a mulitple of Section Alignment). Per the PE/COFF specification, the\r |
393 | // section headers in the Section Table must appear in order of the RVA\r |
394 | // values for the corresponding sections. So the ImageSize can be determined\r |
395 | // by the RVA and the VirtualSize of the last section header in the\r |
396 | // Section Table.\r |
397 | //\r |
398 | if ((++Index) == (UINTN) TeHdr.NumberOfSections) {\r |
399 | ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +\r |
400 | ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);\r |
401 | }\r |
402 | \r |
403 | SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r |
404 | }\r |
405 | \r |
406 | if (DebugDirectoryEntryFileOffset != 0) {\r |
407 | for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r |
408 | //\r |
409 | // Read next debug directory entry\r |
410 | //\r |
411 | Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r |
412 | Status = ImageContext->ImageRead (\r |
413 | ImageContext->Handle,\r |
414 | DebugDirectoryEntryFileOffset,\r |
415 | &Size,\r |
416 | &DebugEntry\r |
417 | );\r |
418 | if (RETURN_ERROR (Status)) {\r |
419 | ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r |
420 | return Status;\r |
421 | }\r |
422 | \r |
423 | if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r |
424 | ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r |
425 | return RETURN_SUCCESS;\r |
426 | }\r |
427 | }\r |
428 | }\r |
429 | }\r |
430 | \r |
431 | return RETURN_SUCCESS;\r |
432 | }\r |
433 | \r |
434 | /**\r |
435 | Converts an image address to the loaded address.\r |
436 | \r |
cd14fe3d |
437 | @param ImageContext The context of the image being loaded.\r |
438 | @param Address The address to be converted to the loaded address.\r |
878ddf1f |
439 | \r |
cd14fe3d |
440 | @return The converted address or NULL if the address can not be converted.\r |
878ddf1f |
441 | \r |
442 | **/\r |
443 | STATIC\r |
444 | VOID *\r |
445 | PeCoffLoaderImageAddress (\r |
446 | IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r |
447 | IN UINTN Address\r |
448 | )\r |
449 | {\r |
450 | if (Address >= ImageContext->ImageSize) {\r |
451 | ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r |
452 | return NULL;\r |
453 | }\r |
454 | \r |
455 | return (CHAR8 *) ((UINTN) ImageContext->ImageAddress + Address);\r |
456 | }\r |
457 | \r |
458 | /**\r |
cd14fe3d |
459 | Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().\r |
878ddf1f |
460 | \r |
cd14fe3d |
461 | If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of\r |
462 | ImageContext as the relocation base address. Otherwise, use the DestinationAddress field\r |
463 | of ImageContext as the relocation base address. The caller must allocate the relocation\r |
464 | fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function. \r |
465 | If ImageContext is NULL, then ASSERT().\r |
466 | \r |
467 | @param ImageContext Pointer to the image context structure that describes the PE/COFF\r |
468 | image that is being relocated.\r |
878ddf1f |
469 | \r |
cd14fe3d |
470 | @retval RETURN_SUCCESS The PE/COFF image was relocated.\r |
471 | Extended status information is in the ImageError field of ImageContext.\r |
472 | @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.\r |
473 | Extended status information is in the ImageError field of ImageContext.\r |
474 | @retval RETURN_UNSUPPORTED A relocation record type is not supported.\r |
475 | Extended status information is in the ImageError field of ImageContext.\r |
878ddf1f |
476 | \r |
477 | **/\r |
478 | RETURN_STATUS\r |
479 | EFIAPI\r |
480 | PeCoffLoaderRelocateImage (\r |
481 | IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r |
482 | )\r |
483 | {\r |
484 | RETURN_STATUS Status;\r |
485 | EFI_IMAGE_NT_HEADERS *PeHdr;\r |
486 | EFI_TE_IMAGE_HEADER *TeHdr;\r |
487 | EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r |
488 | UINT64 Adjust;\r |
489 | EFI_IMAGE_BASE_RELOCATION *RelocBase;\r |
490 | EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r |
491 | UINT16 *Reloc;\r |
492 | UINT16 *RelocEnd;\r |
493 | CHAR8 *Fixup;\r |
494 | CHAR8 *FixupBase;\r |
495 | UINT16 *F16;\r |
496 | UINT32 *F32;\r |
497 | CHAR8 *FixupData;\r |
498 | PHYSICAL_ADDRESS BaseAddress;\r |
499 | \r |
cd14fe3d |
500 | ASSERT (ImageContext != NULL);\r |
501 | \r |
878ddf1f |
502 | PeHdr = NULL;\r |
503 | TeHdr = NULL;\r |
504 | //\r |
505 | // Assume success\r |
506 | //\r |
507 | ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r |
508 | \r |
509 | //\r |
510 | // If there are no relocation entries, then we are done\r |
511 | //\r |
512 | if (ImageContext->RelocationsStripped) {\r |
513 | return RETURN_SUCCESS;\r |
514 | }\r |
515 | \r |
516 | //\r |
517 | // If the destination address is not 0, use that rather than the\r |
518 | // image address as the relocation target.\r |
519 | //\r |
cd14fe3d |
520 | if (ImageContext->DestinationAddress != 0) {\r |
878ddf1f |
521 | BaseAddress = ImageContext->DestinationAddress;\r |
522 | } else {\r |
523 | BaseAddress = ImageContext->ImageAddress;\r |
524 | }\r |
525 | \r |
526 | if (!(ImageContext->IsTeImage)) {\r |
527 | PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext->ImageAddress + \r |
528 | ImageContext->PeCoffHeaderOffset);\r |
cd14fe3d |
529 | \r |
878ddf1f |
530 | Adjust = (UINT64) BaseAddress - PeHdr->OptionalHeader.ImageBase;\r |
531 | PeHdr->OptionalHeader.ImageBase = (UINTN)BaseAddress;\r |
532 | \r |
533 | //\r |
534 | // Find the relocation block\r |
535 | //\r |
536 | // Per the PE/COFF spec, you can't assume that a given data directory\r |
537 | // is present in the image. You have to check the NumberOfRvaAndSizes in\r |
538 | // the optional header to verify a desired directory entry is there.\r |
539 | //\r |
540 | if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r |
541 | RelocDir = &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r |
542 | RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r |
543 | RelocBaseEnd = PeCoffLoaderImageAddress (\r |
544 | ImageContext,\r |
545 | RelocDir->VirtualAddress + RelocDir->Size - 1\r |
546 | );\r |
547 | } else {\r |
548 | //\r |
549 | // Set base and end to bypass processing below.\r |
550 | //\r |
551 | RelocBase = RelocBaseEnd = 0;\r |
552 | }\r |
553 | } else {\r |
554 | TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r |
555 | Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);\r |
556 | TeHdr->ImageBase = (UINT64) (BaseAddress);\r |
557 | \r |
558 | //\r |
559 | // Find the relocation block\r |
560 | //\r |
561 | RelocDir = &TeHdr->DataDirectory[0];\r |
562 | RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r |
24e25d11 |
563 | ImageContext->ImageAddress + \r |
564 | RelocDir->VirtualAddress +\r |
565 | sizeof(EFI_TE_IMAGE_HEADER) - \r |
566 | TeHdr->StrippedSize\r |
567 | );\r |
878ddf1f |
568 | RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r |
569 | }\r |
570 | \r |
571 | //\r |
572 | // Run the relocation information and apply the fixups\r |
573 | //\r |
574 | FixupData = ImageContext->FixupData;\r |
575 | while (RelocBase < RelocBaseEnd) {\r |
576 | \r |
577 | Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r |
578 | RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r |
579 | if (!(ImageContext->IsTeImage)) {\r |
580 | FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r |
581 | } else {\r |
582 | FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r |
24e25d11 |
583 | RelocBase->VirtualAddress +\r |
584 | sizeof(EFI_TE_IMAGE_HEADER) - \r |
585 | TeHdr->StrippedSize\r |
586 | );\r |
878ddf1f |
587 | }\r |
588 | \r |
589 | if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r |
590 | (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + \r |
591 | (UINTN)ImageContext->ImageSize)) {\r |
592 | ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r |
593 | return RETURN_LOAD_ERROR;\r |
594 | }\r |
595 | \r |
596 | //\r |
597 | // Run this relocation record\r |
598 | //\r |
599 | while (Reloc < RelocEnd) {\r |
600 | \r |
601 | Fixup = FixupBase + (*Reloc & 0xFFF);\r |
602 | switch ((*Reloc) >> 12) {\r |
603 | case EFI_IMAGE_REL_BASED_ABSOLUTE:\r |
604 | break;\r |
605 | \r |
606 | case EFI_IMAGE_REL_BASED_HIGH:\r |
607 | F16 = (UINT16 *) Fixup;\r |
608 | *F16 = (UINT16) ((*F16 << 16) + (UINT16) Adjust);\r |
609 | if (FixupData != NULL) {\r |
610 | *(UINT16 *) FixupData = *F16;\r |
611 | FixupData = FixupData + sizeof (UINT16);\r |
612 | }\r |
613 | break;\r |
614 | \r |
615 | case EFI_IMAGE_REL_BASED_LOW:\r |
616 | F16 = (UINT16 *) Fixup;\r |
617 | *F16 = (UINT16) (*F16 + (UINT16) Adjust);\r |
618 | if (FixupData != NULL) {\r |
619 | *(UINT16 *) FixupData = *F16;\r |
620 | FixupData = FixupData + sizeof (UINT16);\r |
621 | }\r |
622 | break;\r |
623 | \r |
624 | case EFI_IMAGE_REL_BASED_HIGHLOW:\r |
625 | F32 = (UINT32 *) Fixup;\r |
626 | *F32 = *F32 + (UINT32) Adjust;\r |
627 | if (FixupData != NULL) {\r |
628 | FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r |
629 | *(UINT32 *) FixupData = *F32;\r |
630 | FixupData = FixupData + sizeof (UINT32);\r |
631 | }\r |
632 | break;\r |
633 | \r |
634 | case EFI_IMAGE_REL_BASED_HIGHADJ:\r |
635 | //\r |
636 | // Return the same EFI_UNSUPPORTED return code as\r |
637 | // PeCoffLoaderRelocateImageEx() returns if it does not recognize\r |
638 | // the relocation type.\r |
639 | //\r |
640 | ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r |
641 | return RETURN_UNSUPPORTED;\r |
642 | \r |
643 | default:\r |
644 | Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r |
645 | if (RETURN_ERROR (Status)) {\r |
646 | ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r |
647 | return Status;\r |
648 | }\r |
649 | }\r |
650 | \r |
651 | //\r |
652 | // Next relocation record\r |
653 | //\r |
654 | Reloc += 1;\r |
655 | }\r |
656 | \r |
657 | //\r |
658 | // Next reloc block\r |
659 | //\r |
660 | RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r |
661 | }\r |
662 | \r |
663 | return RETURN_SUCCESS;\r |
664 | }\r |
665 | \r |
666 | /**\r |
667 | Loads a PE/COFF image into memory.\r |
668 | \r |
cd14fe3d |
669 | Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer\r |
670 | specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate\r |
671 | the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.\r |
672 | The EntryPoint, FixupDataSize, CodeView, and PdbPointer fields of ImageContext are computed.\r |
4ba61e5e |
673 | If ImageContext is NULL, then ASSERT().\r |
cd14fe3d |
674 | \r |
675 | @param ImageContext Pointer to the image context structure that describes the PE/COFF\r |
676 | image that is being loaded.\r |
878ddf1f |
677 | \r |
cd14fe3d |
678 | @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by\r |
679 | the ImageAddress and ImageSize fields of ImageContext.\r |
680 | Extended status information is in the ImageError field of ImageContext.\r |
681 | @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.\r |
682 | Extended status information is in the ImageError field of ImageContext.\r |
683 | @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.\r |
684 | Extended status information is in the ImageError field of ImageContext.\r |
685 | @retval RETURN_INVALID_PARAMETER The image address is invalid.\r |
686 | Extended status information is in the ImageError field of ImageContext.\r |
878ddf1f |
687 | \r |
688 | **/\r |
689 | RETURN_STATUS\r |
690 | EFIAPI\r |
691 | PeCoffLoaderLoadImage (\r |
692 | IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r |
693 | )\r |
694 | {\r |
cd14fe3d |
695 | RETURN_STATUS Status;\r |
878ddf1f |
696 | EFI_IMAGE_NT_HEADERS *PeHdr;\r |
697 | EFI_TE_IMAGE_HEADER *TeHdr;\r |
cd14fe3d |
698 | PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r |
878ddf1f |
699 | EFI_IMAGE_SECTION_HEADER *FirstSection;\r |
700 | EFI_IMAGE_SECTION_HEADER *Section;\r |
701 | UINTN NumberOfSections;\r |
702 | UINTN Index;\r |
703 | CHAR8 *Base;\r |
704 | CHAR8 *End;\r |
705 | CHAR8 *MaxEnd;\r |
706 | EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r |
707 | EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r |
708 | UINTN Size;\r |
709 | UINT32 TempDebugEntryRva;\r |
710 | \r |
4ba61e5e |
711 | ASSERT (ImageContext != NULL);\r |
712 | \r |
878ddf1f |
713 | PeHdr = NULL;\r |
714 | TeHdr = NULL;\r |
4ba61e5e |
715 | \r |
878ddf1f |
716 | //\r |
717 | // Assume success\r |
718 | //\r |
719 | ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r |
720 | \r |
721 | //\r |
722 | // Copy the provided context info into our local version, get what we\r |
723 | // can from the original image, and then use that to make sure everything\r |
724 | // is legit.\r |
725 | //\r |
726 | CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r |
727 | \r |
728 | Status = PeCoffLoaderGetImageInfo (&CheckContext);\r |
729 | if (RETURN_ERROR (Status)) {\r |
730 | return Status;\r |
731 | }\r |
732 | \r |
733 | //\r |
734 | // Make sure there is enough allocated space for the image being loaded\r |
735 | //\r |
736 | if (ImageContext->ImageSize < CheckContext.ImageSize) {\r |
737 | ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;\r |
738 | return RETURN_BUFFER_TOO_SMALL;\r |
739 | }\r |
4ba61e5e |
740 | if (ImageContext->ImageAddress == 0) {\r |
741 | //\r |
742 | // Image cannot be loaded into 0 address.\r |
743 | //\r |
744 | ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r |
745 | return RETURN_INVALID_PARAMETER;\r |
746 | }\r |
878ddf1f |
747 | //\r |
748 | // If there's no relocations, then make sure it's not a runtime driver,\r |
749 | // and that it's being loaded at the linked address.\r |
750 | //\r |
751 | if (CheckContext.RelocationsStripped) {\r |
752 | //\r |
753 | // If the image does not contain relocations and it is a runtime driver\r |
754 | // then return an error.\r |
755 | //\r |
756 | if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r |
757 | ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r |
758 | return RETURN_LOAD_ERROR;\r |
759 | }\r |
760 | //\r |
761 | // If the image does not contain relocations, and the requested load address\r |
762 | // is not the linked address, then return an error.\r |
763 | //\r |
764 | if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r |
765 | ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r |
766 | return RETURN_INVALID_PARAMETER;\r |
767 | }\r |
768 | }\r |
769 | //\r |
770 | // Make sure the allocated space has the proper section alignment\r |
771 | //\r |
772 | if (!(ImageContext->IsTeImage)) {\r |
773 | if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r |
774 | ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r |
775 | return RETURN_INVALID_PARAMETER;\r |
776 | }\r |
777 | }\r |
778 | //\r |
779 | // Read the entire PE/COFF or TE header into memory\r |
780 | //\r |
781 | if (!(ImageContext->IsTeImage)) {\r |
782 | Status = ImageContext->ImageRead (\r |
783 | ImageContext->Handle,\r |
784 | 0,\r |
785 | &ImageContext->SizeOfHeaders,\r |
786 | (VOID *) (UINTN) ImageContext->ImageAddress\r |
787 | );\r |
788 | \r |
789 | PeHdr = (EFI_IMAGE_NT_HEADERS *)\r |
790 | ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r |
791 | \r |
792 | FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r |
793 | (UINTN)ImageContext->ImageAddress +\r |
794 | ImageContext->PeCoffHeaderOffset +\r |
795 | sizeof(UINT32) + \r |
796 | sizeof(EFI_IMAGE_FILE_HEADER) + \r |
797 | PeHdr->FileHeader.SizeOfOptionalHeader\r |
798 | );\r |
799 | NumberOfSections = (UINTN) (PeHdr->FileHeader.NumberOfSections);\r |
800 | } else {\r |
801 | Status = ImageContext->ImageRead (\r |
802 | ImageContext->Handle,\r |
803 | 0,\r |
804 | &ImageContext->SizeOfHeaders,\r |
805 | (void *) (UINTN) ImageContext->ImageAddress\r |
806 | );\r |
807 | \r |
808 | TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r |
809 | \r |
810 | FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r |
24e25d11 |
811 | (UINTN)ImageContext->ImageAddress +\r |
812 | sizeof(EFI_TE_IMAGE_HEADER)\r |
813 | );\r |
878ddf1f |
814 | NumberOfSections = (UINTN) (TeHdr->NumberOfSections);\r |
815 | \r |
816 | }\r |
817 | \r |
818 | if (RETURN_ERROR (Status)) {\r |
819 | ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r |
820 | return RETURN_LOAD_ERROR;\r |
821 | }\r |
822 | \r |
823 | //\r |
824 | // Load each section of the image\r |
825 | //\r |
826 | Section = FirstSection;\r |
827 | for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r |
828 | \r |
829 | //\r |
830 | // Compute sections address\r |
831 | //\r |
832 | Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);\r |
833 | End = PeCoffLoaderImageAddress (\r |
834 | ImageContext,\r |
835 | Section->VirtualAddress + Section->Misc.VirtualSize - 1\r |
836 | );\r |
837 | if (ImageContext->IsTeImage) {\r |
838 | Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r |
839 | End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r |
840 | }\r |
841 | \r |
842 | if (End > MaxEnd) {\r |
843 | MaxEnd = End;\r |
844 | }\r |
845 | //\r |
846 | // If the base start or end address resolved to 0, then fail.\r |
847 | //\r |
848 | if ((Base == NULL) || (End == NULL)) {\r |
849 | ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r |
850 | return RETURN_LOAD_ERROR;\r |
851 | }\r |
852 | \r |
853 | //\r |
854 | // Read the section\r |
855 | //\r |
856 | Size = (UINTN) Section->Misc.VirtualSize;\r |
857 | if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r |
858 | Size = (UINTN) Section->SizeOfRawData;\r |
859 | }\r |
860 | \r |
861 | if (Section->SizeOfRawData) {\r |
862 | if (!(ImageContext->IsTeImage)) {\r |
863 | Status = ImageContext->ImageRead (\r |
864 | ImageContext->Handle,\r |
865 | Section->PointerToRawData,\r |
866 | &Size,\r |
867 | Base\r |
868 | );\r |
869 | } else {\r |
870 | Status = ImageContext->ImageRead (\r |
871 | ImageContext->Handle,\r |
872 | Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,\r |
873 | &Size,\r |
874 | Base\r |
875 | );\r |
876 | }\r |
877 | \r |
878 | if (RETURN_ERROR (Status)) {\r |
879 | ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r |
880 | return Status;\r |
881 | }\r |
882 | }\r |
883 | \r |
884 | //\r |
885 | // If raw size is less then virt size, zero fill the remaining\r |
886 | //\r |
887 | \r |
888 | if (Size < Section->Misc.VirtualSize) {\r |
889 | ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);\r |
890 | }\r |
891 | \r |
892 | //\r |
893 | // Next Section\r |
894 | //\r |
895 | Section += 1;\r |
896 | }\r |
897 | \r |
898 | //\r |
899 | // Get image's entry point\r |
900 | //\r |
901 | if (!(ImageContext->IsTeImage)) {\r |
902 | ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (\r |
903 | ImageContext,\r |
904 | PeHdr->OptionalHeader.AddressOfEntryPoint\r |
905 | );\r |
906 | } else {\r |
907 | ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (\r |
24e25d11 |
908 | (UINTN)ImageContext->ImageAddress +\r |
909 | (UINTN)TeHdr->AddressOfEntryPoint +\r |
910 | (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r |
878ddf1f |
911 | (UINTN) TeHdr->StrippedSize\r |
912 | );\r |
913 | }\r |
914 | \r |
915 | //\r |
916 | // Determine the size of the fixup data\r |
917 | //\r |
918 | // Per the PE/COFF spec, you can't assume that a given data directory\r |
919 | // is present in the image. You have to check the NumberOfRvaAndSizes in\r |
920 | // the optional header to verify a desired directory entry is there.\r |
921 | //\r |
922 | if (!(ImageContext->IsTeImage)) {\r |
923 | if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r |
924 | DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)\r |
925 | &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r |
926 | ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r |
927 | } else {\r |
928 | ImageContext->FixupDataSize = 0;\r |
929 | }\r |
930 | } else {\r |
931 | DirectoryEntry = &TeHdr->DataDirectory[0];\r |
932 | ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r |
933 | }\r |
934 | //\r |
935 | // Consumer must allocate a buffer for the relocation fixup log.\r |
936 | // Only used for runtime drivers.\r |
937 | //\r |
938 | ImageContext->FixupData = NULL;\r |
939 | \r |
940 | //\r |
941 | // Load the Codeview info if present\r |
942 | //\r |
943 | if (ImageContext->DebugDirectoryEntryRva != 0) {\r |
944 | if (!(ImageContext->IsTeImage)) {\r |
945 | DebugEntry = PeCoffLoaderImageAddress (\r |
946 | ImageContext,\r |
947 | ImageContext->DebugDirectoryEntryRva\r |
948 | );\r |
949 | } else {\r |
950 | DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r |
24e25d11 |
951 | ImageContext->ImageAddress +\r |
952 | ImageContext->DebugDirectoryEntryRva +\r |
953 | sizeof(EFI_TE_IMAGE_HEADER) -\r |
954 | TeHdr->StrippedSize\r |
955 | );\r |
878ddf1f |
956 | }\r |
957 | \r |
958 | if (DebugEntry != NULL) {\r |
959 | TempDebugEntryRva = DebugEntry->RVA;\r |
960 | if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r |
961 | Section--;\r |
962 | if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {\r |
963 | TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r |
964 | } else {\r |
965 | TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r |
966 | }\r |
967 | }\r |
968 | \r |
969 | if (TempDebugEntryRva != 0) {\r |
970 | if (!(ImageContext->IsTeImage)) {\r |
971 | ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);\r |
972 | } else {\r |
973 | ImageContext->CodeView = (VOID *)(\r |
24e25d11 |
974 | (UINTN)ImageContext->ImageAddress +\r |
975 | (UINTN)TempDebugEntryRva +\r |
976 | (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r |
878ddf1f |
977 | (UINTN) TeHdr->StrippedSize\r |
978 | );\r |
979 | }\r |
980 | \r |
981 | if (ImageContext->CodeView == NULL) {\r |
982 | ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r |
983 | return RETURN_LOAD_ERROR;\r |
984 | }\r |
985 | \r |
986 | if (DebugEntry->RVA == 0) {\r |
987 | Size = DebugEntry->SizeOfData;\r |
988 | if (!(ImageContext->IsTeImage)) {\r |
989 | Status = ImageContext->ImageRead (\r |
990 | ImageContext->Handle,\r |
991 | DebugEntry->FileOffset,\r |
992 | &Size,\r |
993 | ImageContext->CodeView\r |
994 | );\r |
995 | } else {\r |
996 | Status = ImageContext->ImageRead (\r |
997 | ImageContext->Handle,\r |
998 | DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,\r |
999 | &Size,\r |
1000 | ImageContext->CodeView\r |
1001 | );\r |
1002 | //\r |
1003 | // Should we apply fix up to this field according to the size difference between PE and TE?\r |
1004 | // Because now we maintain TE header fields unfixed, this field will also remain as they are\r |
1005 | // in original PE image.\r |
1006 | //\r |
1007 | }\r |
1008 | \r |
1009 | if (RETURN_ERROR (Status)) {\r |
1010 | ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r |
1011 | return RETURN_LOAD_ERROR;\r |
1012 | }\r |
1013 | \r |
1014 | DebugEntry->RVA = TempDebugEntryRva;\r |
1015 | }\r |
1016 | \r |
1017 | switch (*(UINT32 *) ImageContext->CodeView) {\r |
1018 | case CODEVIEW_SIGNATURE_NB10:\r |
1019 | ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r |
1020 | break;\r |
1021 | \r |
1022 | case CODEVIEW_SIGNATURE_RSDS:\r |
1023 | ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r |
1024 | break;\r |
1025 | \r |
1026 | default:\r |
1027 | break;\r |
1028 | }\r |
1029 | }\r |
1030 | }\r |
1031 | }\r |
1032 | \r |
1033 | return Status;\r |
1034 | }\r |