3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
24 EdbLoadSymbolSingleEntry (
25 IN EFI_DEBUGGER_SYMBOL_OBJECT
*Object
,
29 IN EFI_DEBUGGER_SYMBOL_TYPE Type
35 Load single symbol entry
39 Object - Symbol file object
42 Address - Symbol address
47 EFI_SUCCESS - add single symbol entry successfully
51 EFI_DEBUGGER_SYMBOL_ENTRY
*Entry
;
54 // Check Count VS MaxCount
56 if (Object
->EntryCount
>= Object
->MaxEntryCount
) {
58 // reallocate (for codebuffer too)
61 return EFI_OUT_OF_RESOURCES
;
64 Entry
= &Object
->Entry
[Object
->EntryCount
];
69 if (sizeof (UINTN
) == sizeof(UINT64
)) {
70 DEBUG ((DEBUG_ERROR
, " Symbol: %a, Address: 0x%016lx (%d)\n", Name
, (UINT64
)Address
, (UINTN
)Type
));
72 DEBUG ((DEBUG_ERROR
, " Symbol: %a, Address: 0x%08x (%d)\n", Name
, Address
, (UINTN
)Type
));
76 // Fill the entry - name, RVA, type
78 AsciiStrnCpyS (Entry
->Name
, sizeof(Entry
->Name
), Name
, sizeof(Entry
->Name
) - 1);
79 if (ObjName
!= NULL
) {
80 AsciiStrnCpyS (Entry
->ObjName
, sizeof(Entry
->ObjName
), ObjName
, sizeof(Entry
->ObjName
) - 1);
82 Entry
->RVA
= Address
% EFI_DEBUGGER_DEFAULT_LINK_IMAGEBASE
;
97 EdbEbcMapParseStateUninitialized
,
98 EdbEbcMapParseStateSymbolStart
,
99 EdbEbcMapParseStateSeHandlerSymbol
,
100 EdbEbcMapParseStateFunctionSymbol
,
101 EdbEbcMapParseStateVarbssInitSymbol
,
102 EdbEbcMapParseStateCrtSymbol
,
103 EdbEbcMapParseStateVariableSymbol
,
104 EdbEbcMapParseStateStaticFunctionSymbol
,
105 EdbEbcMapParseStateMax
,
106 } EDB_EBC_MAP_PARSE_STATE
;
109 EdbEbcSymbolParseStateUninitialized
,
110 EdbEbcSymbolParseStateReadyForName
,
111 EdbEbcSymbolParseStateReadyForRVA
,
112 EdbEbcSymbolParseStateReadyForType
,
113 EdbEbcSymbolParseStateReadyForObject
,
114 EdbEbcSymbolParseStateMax
,
115 } EDB_EBC_SYMBOL_PARSE_STATE
;
119 The following code depends on the MAP file generated by IEC compiler (actually Microsoft linker).
121 Sample as follows: EbcTest.map
122 ===============================================================================
125 Timestamp is 45b02718 (Fri Jan 19 10:04:08 2007)
127 Preferred load address is 10000000
129 Start Length Name Class
130 0001:00000000 00000370H .text CODE
131 0002:00000000 00000030H _VARBSS_INIT CODE
132 0003:00000000 00000004H .CRT$TSA DATA
133 0003:00000004 00000004H .CRT$TSC DATA
134 0003:00000008 00000004H .CRT$X DATA
135 0003:0000000c 00000008H .CRT$XCU DATA
136 0003:00000014 00000004H .CRT$Z DATA
137 0003:00000020 0000001cH .rdata DATA
138 0003:0000003c 00000000H .edata DATA
139 0003:0000003c 00000056H .rdata$debug DATA
140 0004:00000000 00000070H .data DATA
141 0004:00000070 00000020H .bss DATA
143 Address Publics by Value Rva+Base Lib:Object
145 0000:00000000 ___safe_se_handler_table 00000000 <absolute>
146 0000:00000000 ___safe_se_handler_count 00000000 <absolute>
147 0001:00000042 TestSubRoutine 10000442 f EbcTest.obj
148 0001:0000011a EfiMain 1000051a f EbcTest.obj
149 0001:00000200 TestSubRoutineSub 10000600 f EbcTestSub.obj
150 0001:00000220 EfiStart 10000620 f EbcLib:EbcLib.obj
151 0002:00000000 varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b02717 10000800 f EbcTest.obj
152 0002:00000020 varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTestSub$c45af77f3 10000820 f EbcTestSub.obj
153 0003:00000000 CrtThunkBegin 10000a00 EbcLib:EbcLib.obj
154 0003:00000004 CrtThunkEnd 10000a04 EbcLib:EbcLib.obj
155 0003:00000008 CrtBegin 10000a08 EbcLib:EbcLib.obj
156 0003:00000014 CrtEnd 10000a14 EbcLib:EbcLib.obj
157 0004:00000070 TestStr 10000c70 EbcTest.obj
158 0004:00000078 TestVariable1 10000c78 EbcTest.obj
159 0004:00000080 TestSubVariableSub 10000c80 EbcTestSub.obj
161 entry point at 0001:00000220
165 0001:00000000 TestSubRoutine2 10000400 f EbcTest.obj
166 ===============================================================================
170 EdbLoadSymbolEntryByIec (
171 IN EFI_DEBUGGER_SYMBOL_OBJECT
*Object
,
179 Load symbol entry by Iec
183 DebuggerPrivate - EBC Debugger private data structure
184 Object - Symbol file object
185 BufferSize - Symbol file buffer size
186 Buffer - Symbol file buffer
190 EFI_SUCCESS - add symbol entry successfully
196 EFI_DEBUGGER_SYMBOL_ENTRY
*Entry
;
197 EDB_EBC_MAP_PARSE_STATE MapParseState
;
198 EDB_EBC_SYMBOL_PARSE_STATE SymbolParseState
;
202 EFI_DEBUGGER_SYMBOL_TYPE Type
;
204 Entry
= Object
->Entry
;
207 // Begin to parse the Buffer
209 LineBuffer
= AsciiStrGetNewTokenLine (Buffer
, "\n\r");
210 MapParseState
= EdbEbcMapParseStateUninitialized
;
214 while (LineBuffer
!= NULL
) {
215 FieldBuffer
= AsciiStrGetNewTokenField (LineBuffer
, " ");
216 SymbolParseState
= EdbEbcSymbolParseStateUninitialized
;
223 Type
= EfiDebuggerSymbolTypeMax
;
227 while (FieldBuffer
!= NULL
) {
228 if (AsciiStrCmp (FieldBuffer
, "") == 0) {
229 FieldBuffer
= AsciiStrGetNextTokenField (" ");
235 if (AsciiStrCmp (FieldBuffer
, "Address") == 0) {
236 MapParseState
= EdbEbcMapParseStateSymbolStart
;
242 if (AsciiStrCmp (FieldBuffer
, "Static") == 0) {
243 MapParseState
= EdbEbcMapParseStateStaticFunctionSymbol
;
247 if (MapParseState
== EdbEbcMapParseStateUninitialized
) {
249 // Do not parse anything until get "Address" or "Static"
253 if (AsciiStrCmp (FieldBuffer
, "entry") == 0) {
261 // Now we start to parse this line for Name, Address, and Object
263 switch (SymbolParseState
) {
264 case EdbEbcSymbolParseStateUninitialized
:
268 SymbolParseState
= EdbEbcSymbolParseStateReadyForName
;
270 case EdbEbcSymbolParseStateReadyForName
:
274 if (AsciiStrnCmp (FieldBuffer
, "___safe_se_handler", AsciiStrLen ("___safe_se_handler")) == 0) {
278 MapParseState
= EdbEbcMapParseStateSeHandlerSymbol
;
280 } else if (AsciiStrnCmp (FieldBuffer
, "varbss_init", AsciiStrLen ("varbss_init")) == 0) {
284 MapParseState
= EdbEbcMapParseStateVarbssInitSymbol
;
285 // goto ExitFieldParse;
287 SymbolParseState
= EdbEbcSymbolParseStateReadyForRVA
;
288 } else if (AsciiStrnCmp (FieldBuffer
, "Crt", AsciiStrLen ("Crt")) == 0) {
292 MapParseState
= EdbEbcMapParseStateCrtSymbol
;
293 // goto ExitFieldParse;
295 SymbolParseState
= EdbEbcSymbolParseStateReadyForRVA
;
298 // Now, it is normal function
300 switch (MapParseState
) {
301 case EdbEbcMapParseStateSeHandlerSymbol
:
302 MapParseState
= EdbEbcMapParseStateFunctionSymbol
;
304 case EdbEbcMapParseStateCrtSymbol
:
305 MapParseState
= EdbEbcMapParseStateVariableSymbol
;
307 case EdbEbcMapParseStateFunctionSymbol
:
308 case EdbEbcMapParseStateVariableSymbol
:
309 case EdbEbcMapParseStateStaticFunctionSymbol
:
316 SymbolParseState
= EdbEbcSymbolParseStateReadyForRVA
;
319 case EdbEbcSymbolParseStateReadyForRVA
:
323 Address
= AsciiXtoi (FieldBuffer
);
324 SymbolParseState
= EdbEbcSymbolParseStateReadyForType
;
326 case EdbEbcSymbolParseStateReadyForType
:
328 // Get the Type. This is optional, only for "f".
330 if (AsciiStrCmp (FieldBuffer
, "f") == 0) {
331 SymbolParseState
= EdbEbcSymbolParseStateReadyForObject
;
332 switch (MapParseState
) {
333 case EdbEbcMapParseStateFunctionSymbol
:
334 case EdbEbcMapParseStateVarbssInitSymbol
:
335 Type
= EfiDebuggerSymbolFunction
;
337 case EdbEbcMapParseStateStaticFunctionSymbol
:
338 Type
= EfiDebuggerSymbolStaticFunction
;
347 // Else it should be Object.
348 // let it bypass here
350 case EdbEbcSymbolParseStateReadyForObject
:
352 case EfiDebuggerSymbolTypeMax
:
353 switch (MapParseState
) {
354 case EdbEbcMapParseStateVariableSymbol
:
355 case EdbEbcMapParseStateCrtSymbol
:
356 Type
= EfiDebuggerSymbolGlobalVariable
;
358 case EdbEbcMapParseStateSeHandlerSymbol
:
368 case EfiDebuggerSymbolFunction
:
369 case EfiDebuggerSymbolStaticFunction
:
378 ObjName
= FieldBuffer
;
379 SymbolParseState
= EdbEbcSymbolParseStateUninitialized
;
387 // Get the next field
389 FieldBuffer
= AsciiStrGetNextTokenField (" ");
393 // Add the entry if we get everything.
395 if ((Name
!= NULL
) && (Type
!= EfiDebuggerSymbolTypeMax
)) {
396 EdbLoadSymbolSingleEntry (Object
, Name
, ObjName
, Address
, Type
);
403 LineBuffer
= AsciiStrGetNextTokenLine ("\n\r");
414 IN EFI_DEBUGGER_SYMBOL_OBJECT
*Object
,
426 Object - Symbol file object
427 BufferSize - Symbol file buffer size
428 Buffer - Symbol file buffer
432 EFI_SUCCESS - add symbol entry successfully
437 // MAP file format depends on the compiler (actually linker).
439 // It is possible to check the different MAP file format in this routine.
440 // Now only IEC is supported.
442 return EdbLoadSymbolEntryByIec (Object
, BufferSize
, Buffer
);
445 EFI_DEBUGGER_SYMBOL_OBJECT
*
447 IN EFI_DEBUGGER_PRIVATE_DATA
*DebuggerPrivate
,
449 IN OUT UINTN
*Index OPTIONAL
455 Find symbol file by name
459 DebuggerPrivate - EBC Debugger private data structure
460 FileName - Symbol file name
461 Index - Symbol file index
474 for (ObjectIndex
= 0; ObjectIndex
< DebuggerPrivate
->DebuggerSymbolContext
.ObjectCount
; ObjectIndex
++) {
475 if (StrCmp (FileName
, DebuggerPrivate
->DebuggerSymbolContext
.Object
[ObjectIndex
].Name
) == 0) {
477 // Name match, found it
480 *Index
= ObjectIndex
;
482 return &DebuggerPrivate
->DebuggerSymbolContext
.Object
[ObjectIndex
];
493 EbdFindSymbolAddress (
495 IN EDB_MATCH_SYMBOL_TYPE Type
,
496 OUT EFI_DEBUGGER_SYMBOL_OBJECT
**RetObject
,
497 OUT EFI_DEBUGGER_SYMBOL_ENTRY
**RetEntry
503 Find symbol by address
507 Address - Symbol address
509 RetObject - Symbol object
510 RetEntry - Symbol entry
514 Nearest symbol address
520 UINTN CandidateLowerAddress
;
521 UINTN CandidateUpperAddress
;
522 EFI_DEBUGGER_SYMBOL_OBJECT
*Object
;
523 EFI_DEBUGGER_SYMBOL_ENTRY
*Entry
;
524 EFI_DEBUGGER_SYMBOL_ENTRY
*LowEntry
;
525 EFI_DEBUGGER_SYMBOL_ENTRY
*UpperEntry
;
526 EFI_DEBUGGER_SYMBOL_OBJECT
*LowObject
;
527 EFI_DEBUGGER_SYMBOL_OBJECT
*UpperObject
;
529 if ((Type
< 0) || (Type
>= EdbMatchSymbolTypeMax
)) {
536 CandidateLowerAddress
= 0;
537 CandidateUpperAddress
= (UINTN
)-1;
544 // Go through each object
546 Object
= mDebuggerPrivate
.DebuggerSymbolContext
.Object
;
547 for (Index
= 0; Index
< mDebuggerPrivate
.DebuggerSymbolContext
.ObjectCount
; Index
++, Object
++) {
548 if (Object
->EntryCount
== 0) {
552 // Go through each entry
554 Entry
= Object
->Entry
;
555 for (SubIndex
= 0; SubIndex
< Object
->EntryCount
; SubIndex
++, Entry
++) {
556 if (Address
!= Entry
->RVA
+ Object
->BaseAddress
) {
558 // Check for nearest address
560 if (Address
> Entry
->RVA
+ Object
->BaseAddress
) {
562 // Record it if Current RVA < Address
564 if (CandidateLowerAddress
< Entry
->RVA
+ Object
->BaseAddress
) {
565 CandidateLowerAddress
= Entry
->RVA
+ Object
->BaseAddress
;
571 // Record it if Current RVA > Address
573 if (CandidateUpperAddress
> Entry
->RVA
+ Object
->BaseAddress
) {
574 CandidateUpperAddress
= Entry
->RVA
+ Object
->BaseAddress
;
576 UpperObject
= Object
;
582 // address match, return directly
591 // No Match, provide latest symbol
594 if ((Address
- CandidateLowerAddress
) < EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE
) {
596 // Check for lower address
598 if (((Type
== EdbMatchSymbolTypeNearestAddress
) &&
599 ((CandidateUpperAddress
- Address
) > (Address
- CandidateLowerAddress
))) ||
600 (Type
== EdbMatchSymbolTypeLowerAddress
)) {
602 // return nearest lower address
604 *RetEntry
= LowEntry
;
605 *RetObject
= LowObject
;
606 return CandidateLowerAddress
;
610 if ((CandidateUpperAddress
- Address
) < EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE
) {
612 // Check for upper address
614 if (((Type
== EdbMatchSymbolTypeNearestAddress
) &&
615 ((CandidateUpperAddress
- Address
) < (Address
- CandidateLowerAddress
))) ||
616 (Type
== EdbMatchSymbolTypeUpperAddress
)) {
618 // return nearest upper address
620 *RetEntry
= UpperEntry
;
621 *RetObject
= UpperObject
;
622 return CandidateUpperAddress
;
627 // No match and nearest one, return NULL
634 IN EFI_DEBUGGER_PRIVATE_DATA
*DebuggerPrivate
,
641 Unload symbol file by name
645 DebuggerPrivate - EBC Debugger private data structure
646 FileName - Symbol file name
650 EFI_SUCCESS - unload symbol successfully
654 EFI_DEBUGGER_SYMBOL_OBJECT
*Object
;
657 EFI_DEBUGGER_SYMBOL_ENTRY
*OldEntry
;
660 VOID
**OldSourceBuffer
;
665 Object
= EdbFindSymbolFile (DebuggerPrivate
, FileName
, &ObjectIndex
);
666 if (Object
== NULL
) {
667 EDBPrint (L
"SymbolFile is not loaded!\n");
668 return EFI_DEBUG_CONTINUE
;
674 Object
= DebuggerPrivate
->DebuggerSymbolContext
.Object
;
675 OldEntry
= Object
->Entry
;
676 OldSourceBuffer
= Object
->SourceBuffer
;
677 MaxEntryCount
= Object
->MaxEntryCount
;
678 OldEntryCount
= Object
->EntryCount
;
681 // Remove the matched Object
683 for (Index
= ObjectIndex
; Index
< DebuggerPrivate
->DebuggerSymbolContext
.ObjectCount
- 1; Index
++) {
684 CopyMem (&Object
[Index
], &Object
[Index
+ 1], sizeof(EFI_DEBUGGER_SYMBOL_OBJECT
));
686 ZeroMem (&Object
[Index
], sizeof(Object
[Index
]));
689 // Move old data to new place
691 Object
[Index
].Entry
= OldEntry
;
692 Object
[Index
].SourceBuffer
= OldSourceBuffer
;
693 Object
[Index
].MaxEntryCount
= MaxEntryCount
;
694 DebuggerPrivate
->DebuggerSymbolContext
.ObjectCount
--;
697 // Clean old entry data
699 for (Index
= 0; Index
< OldEntryCount
; Index
++) {
700 ZeroMem (&OldEntry
[Index
], sizeof(OldEntry
[Index
]));
704 // Free OldSourceBuffer
706 for (Index
= 0; OldSourceBuffer
[Index
] != NULL
; Index
++) {
707 gBS
->FreePool (OldSourceBuffer
[Index
]);
708 OldSourceBuffer
[Index
] = NULL
;
716 IN EFI_DEBUGGER_PRIVATE_DATA
*DebuggerPrivate
,
725 Load symbol file by name
729 DebuggerPrivate - EBC Debugger private data structure
730 FileName - Symbol file name
731 BufferSize - Symbol file buffer size
732 Buffer - Symbol file buffer
736 EFI_SUCCESS - load symbol successfully
740 EFI_DEBUGGER_SYMBOL_OBJECT
*Object
;
744 // Check duplicated File
746 Object
= EdbFindSymbolFile (DebuggerPrivate
, FileName
, NULL
);
747 if (Object
!= NULL
) {
748 Status
= EdbUnloadSymbol (DebuggerPrivate
, FileName
);
749 if (EFI_ERROR(Status
)) {
750 DEBUG ((DEBUG_ERROR
, "Unload Duplicated Symbol File Error!\n"));
756 // Check Count VS MaxCount
758 if (DebuggerPrivate
->DebuggerSymbolContext
.ObjectCount
>= DebuggerPrivate
->DebuggerSymbolContext
.MaxObjectCount
) {
763 return EFI_OUT_OF_RESOURCES
;
766 Object
= &DebuggerPrivate
->DebuggerSymbolContext
.Object
[DebuggerPrivate
->DebuggerSymbolContext
.ObjectCount
];
771 Object
->EntryCount
= 0;
772 Object
->MaxEntryCount
= EFI_DEBUGGER_SYMBOL_ENTRY_MAX
;
777 DEBUG ((DEBUG_ERROR
, "Symbol File: %s\n", FileName
));
778 Status
= EdbLoadSymbolEntry (Object
, BufferSize
, Buffer
);
779 if (EFI_ERROR (Status
)) {
786 StrnCpyS (Object
->Name
, sizeof(Object
->Name
) / sizeof(CHAR16
),
787 FileName
, (sizeof(Object
->Name
) / sizeof(CHAR16
)) - 1);
788 Object
->BaseAddress
= 0;
791 // Increase the object count
793 DebuggerPrivate
->DebuggerSymbolContext
.ObjectCount
++;
806 Located PDB path name in PE image
810 ImageBase - base of PE to search
814 Pointer into image at offset of PDB file name if PDB file name is found,
815 Otherwise a pointer to an empty string.
821 EFI_IMAGE_DOS_HEADER
*DosHdr
;
822 EFI_IMAGE_OPTIONAL_HEADER_UNION
*NtHdr
;
823 EFI_IMAGE_OPTIONAL_HEADER32
*OptionalHdr32
;
824 EFI_IMAGE_OPTIONAL_HEADER64
*OptionalHdr64
;
825 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
826 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
827 VOID
*CodeViewEntryPointer
;
832 CodeViewEntryPointer
= NULL
;
839 if (DosHdr
->e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
842 NtHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINT8
*) DosHdr
+ DosHdr
->e_lfanew
);
844 // Check Machine, filter for EBC
846 if (NtHdr
->Pe32
.FileHeader
.Machine
!= EFI_IMAGE_MACHINE_EBC
) {
848 // If not EBC, return NULL
854 // Get DirectoryEntry
855 // EBC spec says PE32+, but implementation uses PE32. So check dynamically here.
857 if (NtHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
858 OptionalHdr32
= (VOID
*) &NtHdr
->Pe32
.OptionalHeader
;
859 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionalHdr32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
860 } else if (NtHdr
->Pe32Plus
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
861 OptionalHdr64
= (VOID
*) &NtHdr
->Pe32Plus
.OptionalHeader
;
862 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionalHdr64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
866 if (DirectoryEntry
->VirtualAddress
== 0) {
870 // Go through DirectoryEntry
873 (DirCount
< DirectoryEntry
->Size
/ sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) && CodeViewEntryPointer
== NULL
;
876 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) (DirectoryEntry
->VirtualAddress
+ (UINTN
) ImageBase
+ DirCount
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
877 if (DebugEntry
->Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
879 // Match DebugEntry, only CODEVIEW_SIGNATURE_NB10 and CODEVIEW_SIGNATURE_RSDS are supported.
881 CodeViewEntryPointer
= (VOID
*) ((UINTN
) DebugEntry
->RVA
+ (UINTN
) ImageBase
);
882 switch (*(UINT32
*) CodeViewEntryPointer
) {
883 case CODEVIEW_SIGNATURE_NB10
:
884 PdbPath
= (CHAR8
*) CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
886 case CODEVIEW_SIGNATURE_RSDS
:
887 PdbPath
= (CHAR8
*) CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
903 IN CHAR8
*PdbFileName
,
904 IN CHAR16
*MapFileName
910 Check whether PDB file and MAP file have same name
914 PdbFileName - PDB file name
915 MapFileName - MAP file name
919 TRUE - PDB and MAP file name match
920 FALSE - PDB and MAP file name not match
926 CHAR8
*PurePdbFileName
;
932 PurePdbFileName
= PdbFileName
;
933 for (Index
= 0; PdbFileName
[Index
] != 0; Index
++) {
934 if (PdbFileName
[Index
] == '\\') {
935 PurePdbFileName
= &PdbFileName
[Index
+ 1];
938 PdbFileName
= PurePdbFileName
;
943 PdbNameSize
= AsciiStrLen (PdbFileName
);
944 MapNameSize
= StrLen (MapFileName
);
946 if (PdbNameSize
!= MapNameSize
) {
953 for (Index
= 0; Index
< MapNameSize
- 4; Index
++) {
954 if ((PdbFileName
[Index
] | 0x20) != (MapFileName
[Index
] | 0x20)) {
963 // BUGBUG: work-around start
966 EFI_DEBUG_IMAGE_INFO
*EfiDebugImageInfoTable
;
967 volatile UINT32 UpdateStatus
;
969 } EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD
;
971 EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugImageInfoTableHeader
;
974 EdbFixDebugImageInfoTable (
975 IN OUT EFI_DEBUG_IMAGE_INFO_TABLE_HEADER
**DebugImageInfoTableHeader
978 For compatibility consideration, we handle 2 cases:
982 +------------------------+ +------------------------+
983 | EfiDebugImageInfoTable | | UpdateStatus |
984 +------------------------+ +------------------------+
985 | UpdateStatus | | TableSize |
986 +------------------------+ +------------------------+
987 | TableSize | | EfiDebugImageInfoTable |
988 +------------------------+ +------------------------+
992 +------------------------+ +------------------------+
993 | EfiDebugImageInfoTable | | UpdateStatus |
994 | | +------------------------+
996 +------------------------+ +------------------------+
997 | UpdateStatus | | EfiDebugImageInfoTable |
998 +------------------------+ | |
1000 +------------------------+ +------------------------+
1004 mDebugImageInfoTableHeader
.EfiDebugImageInfoTable
= ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD
*)(*DebugImageInfoTableHeader
))->EfiDebugImageInfoTable
;
1005 mDebugImageInfoTableHeader
.UpdateStatus
= ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD
*)(*DebugImageInfoTableHeader
))->UpdateStatus
;
1006 mDebugImageInfoTableHeader
.TableSize
= ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD
*)(*DebugImageInfoTableHeader
))->TableSize
;
1008 if ((*DebugImageInfoTableHeader
)->UpdateStatus
> 3) {
1009 *DebugImageInfoTableHeader
= &mDebugImageInfoTableHeader
;
1013 if ((*DebugImageInfoTableHeader
)->TableSize
% (EFI_PAGE_SIZE
/ (sizeof (VOID
*))) != 0) {
1014 *DebugImageInfoTableHeader
= &mDebugImageInfoTableHeader
;
1021 // BUGBUG: work-around end
1026 IN EFI_DEBUGGER_PRIVATE_DATA
*DebuggerPrivate
,
1027 IN CHAR16
*FileName
,
1028 IN EDB_EBC_IMAGE_RVA_SEARCH_TYPE SearchType
1032 Routine Description:
1038 DebuggerPrivate - EBC Debugger private data structure
1039 FileName - Symbol file name
1040 SearchType - Search type for Object
1044 EFI_SUCCESS - Patch symbol RVA successfully
1045 EFI_NOT_FOUND - Symbol RVA base not found
1051 EFI_DEBUG_IMAGE_INFO
*ImageTable
;
1054 VOID
*CandidateImageBase
;
1055 EFI_DEBUGGER_SYMBOL_OBJECT
*Object
;
1057 if (SearchType
< 0 || SearchType
>= EdbEbcImageRvaSearchTypeMax
) {
1058 return EFI_INVALID_PARAMETER
;
1062 // Get the related object
1064 Object
= EdbFindSymbolFile (DebuggerPrivate
, FileName
, NULL
);
1065 if (Object
== NULL
) {
1066 return EFI_NOT_FOUND
;
1070 // Try again to get DebugImageInfoTable
1072 if (mDebuggerPrivate
.DebugImageInfoTableHeader
== NULL
) {
1073 Status
= EfiGetSystemConfigurationTable (
1074 &gEfiDebugImageInfoTableGuid
,
1075 (VOID
**) &mDebuggerPrivate
.DebugImageInfoTableHeader
1077 if (EFI_ERROR (Status
)) {
1078 EDBPrint (L
"DebugImageInfoTable not found!\n");
1082 DEBUG ((DEBUG_ERROR
, "DebugImageInfoTableHeader: %x\n", mDebuggerPrivate
.DebugImageInfoTableHeader
));
1085 // BUGBUG: work-around start
1087 EdbFixDebugImageInfoTable (&mDebuggerPrivate
.DebugImageInfoTableHeader
);
1089 // BUGBUG: work-around end
1093 // Go through DebugImageInfoTable for each Image
1095 CandidateImageBase
= NULL
;
1096 ImageTable
= mDebuggerPrivate
.DebugImageInfoTableHeader
->EfiDebugImageInfoTable
;
1097 for (ImageNumber
= 0; ImageNumber
< mDebuggerPrivate
.DebugImageInfoTableHeader
->TableSize
; ImageNumber
++) {
1098 if (ImageTable
[ImageNumber
].NormalImage
== NULL
) {
1101 ImageBase
= ImageTable
[ImageNumber
].NormalImage
->LoadedImageProtocolInstance
->ImageBase
;
1105 PdbPath
= GetPdbPath (ImageBase
);
1106 if (PdbPath
== NULL
) {
1112 if (!MatchPdbAndMap (PdbPath
, FileName
)) {
1115 DEBUG ((DEBUG_ERROR
, "ImageBase: %x\n", ImageBase
));
1120 if (SearchType
== EdbEbcImageRvaSearchTypeAny
|| SearchType
== EdbEbcImageRvaSearchTypeFirst
) {
1122 // Assign base address and return
1124 Object
->BaseAddress
= (UINTN
)ImageBase
;
1129 // Get CandidateImageBase for EdbEbcImageRvaSearchTypeLast
1131 CandidateImageBase
= ImageBase
;
1135 // Check EdbEbcImageRvaSearchTypeLast
1137 if (SearchType
== EdbEbcImageRvaSearchTypeLast
) {
1138 if (CandidateImageBase
== NULL
) {
1139 return EFI_NOT_FOUND
;
1142 // Assign base address and return
1144 Object
->BaseAddress
= (UINTN
)CandidateImageBase
;
1151 return EFI_NOT_FOUND
;
1156 IN CHAR8
*ObjFileName
,
1157 IN CHAR16
*CodFileName
1161 Routine Description:
1163 Check whether OBJ file and COD file have same name
1167 ObjFileName - OBJ file name
1168 CodFileName - COD file name
1172 TRUE - OBJ and COD file name match
1173 FALSE - OBJ and COD file name not match
1179 CHAR8
*PureObjFileName
;
1183 // remove library name
1185 PureObjFileName
= ObjFileName
;
1186 for (Index
= 0; ObjFileName
[Index
] != 0; Index
++) {
1187 if (ObjFileName
[Index
] == ':') {
1188 PureObjFileName
= &ObjFileName
[Index
+ 1];
1192 ObjFileName
= PureObjFileName
;
1197 ObjNameSize
= AsciiStrLen (ObjFileName
);
1198 CodNameSize
= StrLen (CodFileName
);
1200 if (ObjNameSize
!= CodNameSize
) {
1207 for (Index
= 0; Index
< CodNameSize
- 4; Index
++) {
1208 if ((ObjFileName
[Index
] | 0x20) != (CodFileName
[Index
] | 0x20)) {
1217 EdbEbcCodParseStateUninitialized
,
1218 EdbEbcCodParseStateSymbolInitialized
,
1219 EdbEbcCodParseStateSymbolStart
,
1220 EdbEbcCodParseStateSymbolEnd
,
1221 EdbEbcCodParseStateMax
,
1222 } EDB_EBC_COD_PARSE_STATE
;
1226 The following code depends on the COD file generated by IEC compiler.
1228 Sample as follows: EbcTest.cod
1229 ===============================================================================
1230 ; -- Machine type EFI
1231 ; mark_description "Intel(R) C Compiler for EFI Byte Code, Version 1.2 Build 20040123";
1232 ; mark_description "XXX";
1233 ;ident "Intel(R) C Compiler for EFI Byte Code, Version 1.2 Build 20040123"
1237 _TEXT SEGMENT PARA PUBLIC USE32 'CODE'
1239 _DATA SEGMENT PARA PUBLIC USE32 'DATA'
1242 _BSS SEGMENT PARA PUBLIC USE32 'BSS'
1245 _VARBSS SEGMENT PARA PUBLIC USE32 'BSS'
1248 ASSUME CS:FLAT,DS:FLAT,SS:FLAT
1249 _DATA SEGMENT PARA PUBLIC USE32 'DATA'
1250 TestVariable2 DD 000000003H,000000000H ; u64
1252 _DATA SEGMENT PARA PUBLIC USE32 'DATA'
1254 _TEXT SEGMENT PARA PUBLIC USE32 'CODE'
1264 0011a 60 00 70 80 MOVqw R0, R0(+0,-112) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:117
1267 ;118 ; UINT16 test = 0x1234;
1269 0011e 77 58 58 00 34
1270 12 MOVIww @R0(+0,+88), +4660 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:118
1273 ;121 ; EFI_STATUS Status;
1275 ;121 ; SystemTable->ConOut->OutputString (
1277 00124 72 87 01 12 MOVnw R7, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:121
1278 00128 72 f7 85 21 MOVnw R7, @R7(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:121
1281 ;122 ; SystemTable->ConOut,
1283 0012c 72 84 01 12 MOVnw R4, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
1284 00130 72 c8 85 21 MOVnw @R0, @R4(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
1285 00134 b9 34 00 00 00
1286 00 MOVreld R4, __STRING$1 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
1287 0013a b2 48 01 10 MOVnw @R0(+1,+0), R4 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
1288 0013e 83 2f 01 00 00
1289 10 CALLEX @R7(+1,+0) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:122
1293 ;125 ; L"Hello EBC Test!\n\r"
1295 ;125 ; EFI_BREAKPOINT ();
1297 00144 00 03 BREAK 3 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:125
1301 ;126 ; TestVariable1 = 6;
1303 00146 b9 37 00 00 00
1304 00 MOVreld R7, TestVariable1 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:126
1305 0014c 78 0f 06 00 MOVInw @R7, (0,6) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:126
1308 ;127 ; TestSubRoutineSub (1, 5);
1310 00150 78 08 01 00 MOVInw @R0, (0,1) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:127
1311 00154 78 48 01 10 05
1312 00 MOVInw @R0(1,0), (0,5) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:127
1313 0015a 83 10 00 00 00
1314 00 CALL TestSubRoutineSub ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:127
1319 ;129 ; SystemTable->ConOut->OutputString (
1321 00160 72 87 01 12 MOVnw R7, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:129
1322 00164 72 f7 85 21 MOVnw R7, @R7(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:129
1325 ;130 ; SystemTable->ConOut,
1327 00168 72 84 01 12 MOVnw R4, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:130
1328 0016c 72 c8 85 21 MOVnw @R0, @R4(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:130
1333 00170 b9 34 00 00 00
1334 00 MOVreld R4, TestStr ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:131
1335 00176 b2 c8 01 10 MOVnw @R0(+1, +0), @R4 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:131
1336 0017a 83 2f 01 00 00
1337 10 CALLEX @R7(+1,+0) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:131
1343 ;134 ; test = test & 0xFF;
1345 00180 de 88 58 00 58
1346 00 MOVww @R0(+0,+88), @R0(+0,+88) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:134
1349 ;139 ; if (test != 0x34) {
1350 ;139 ; // EFI_BREAKPOINT ();
1353 ;139 ; Status = TestSubRoutine (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1355 00186 78 08 01 00 MOVInw @R0, (0,1) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1356 0018a 78 48 01 10 02
1357 00 MOVInw @R0(1,0), (0,2) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1358 00190 78 48 02 10 03
1359 00 MOVInw @R0(2,0), (0,3) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1360 00196 78 48 03 10 04
1361 00 MOVInw @R0(3,0), (0,4) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1362 0019c 78 48 04 20 05
1363 00 MOVInw @R0(4,0), (0,5) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1364 001a2 78 48 05 20 06
1365 00 MOVInw @R0(5,0), (0,6) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1366 001a8 78 48 06 20 07
1367 00 MOVInw @R0(6,0), (0,7) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1368 001ae 78 48 07 20 08
1369 00 MOVInw @R0(7,0), (0,8) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1370 001b4 78 48 08 20 09
1371 00 MOVInw @R0(8,0), (0,9) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1372 001ba 78 48 09 20 0a
1373 00 MOVInw @R0(9,0), (0,10) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1374 001c0 83 10 00 00 00
1375 00 CALL TestSubRoutine ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1377 001c6 b2 78 60 00 MOVnw @R0(+0,+96), R7 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1380 001ca f2 88 50 00 60
1381 00 MOVnw @R0(+0,+80), @R0(+0,+96) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:139
1385 ;141 ; SystemTable->ConOut->OutputString (
1387 001d0 72 87 01 12 MOVnw R7, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:141
1388 001d4 72 f7 85 21 MOVnw R7, @R7(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:141
1391 ;142 ; SystemTable->ConOut,
1393 001d8 72 84 01 12 MOVnw R4, @R0(+1,+128) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
1394 001dc 72 c8 85 21 MOVnw @R0, @R4(+5,+24) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
1395 001e0 b9 34 00 00 00
1396 00 MOVreld R4, __STRING$2 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
1397 001e6 b2 48 01 10 MOVnw @R0(+1,+0), R4 ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
1398 001ea 83 2f 01 00 00
1399 10 CALLEX @R7(+1,+0) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:142
1403 ;146 ; L"Goodbye EBC Test!\n\r"
1406 ;146 ; return Status;
1408 001f0 72 87 50 00 MOVnw R7, @R0(+0,+80) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:146
1409 001f4 60 00 70 00 MOVqw R0, R0(+0,+112) ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:146
1410 001f8 04 00 RET ;C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest.c:146
1414 _DATA SEGMENT PARA PUBLIC USE32 'DATA'
1416 __STRING$2 DW 71 ; u16
1436 __STRING$1 DW 72 ; u16
1455 _DATA SEGMENT PARA PUBLIC USE32 'DATA'
1458 _DATA SEGMENT PARA PUBLIC USE32 'DATA'
1459 __STRING$0 DW 55 ; u16
1472 _VARBSS SEGMENT PARA PUBLIC USE32 'BSS'
1474 TestStr DD 2 DUP (?) ; pad
1475 PUBLIC TestVariable1
1476 TestVariable1 DD 2 DUP (?) ; pad
1478 _VARBSS_INIT SEGMENT DWORD PUBLIC USE32 'CODE'
1479 ; -- Begin varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2
1480 PUBLIC varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2
1481 varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2 PROC NEAR
1482 00000 b9 34 00 00 00
1483 00 MOVreld R4, TestStr
1484 00006 b9 35 00 00 00
1485 00 MOVreld R5, __STRING$0
1486 0000c 33 5c MOVnd @R4, R5
1487 0000e b9 34 00 00 00
1488 00 MOVreld R4, TestVariable1
1489 00014 78 0c 04 00 MOVInw @R4, (0,4)
1491 ; -- End varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b815d2
1493 _DATA SEGMENT PARA PUBLIC USE32 'DATA'
1495 EXTRN TestSubRoutineSub:PROC
1498 ===============================================================================
1502 EdbLoadCodBySymbolByIec (
1505 IN UINTN BufferSize
,
1506 OUT UINTN
*CodeBufferSize
,
1507 OUT UINTN
*FuncOffset
1511 Routine Description:
1513 Load code by symbol by Iec
1517 Name - Symbol file name
1518 BufferSize - Symbol file buffer size
1519 Buffer - Symbol file buffer
1520 CodeBufferSize - Code buffer size
1521 FuncOffset - Code funcion offset
1534 EDB_EBC_COD_PARSE_STATE CodParseState
;
1535 CHAR8 Char
[2] = {9, 0};
1540 LineBuffer
= AsciiStrGetNewTokenLine (Buffer
, "\n\r");
1544 CodParseState
= EdbEbcCodParseStateUninitialized
;
1549 while (LineBuffer
!= NULL
) {
1550 switch (CodParseState
) {
1551 case EdbEbcCodParseStateUninitialized
:
1553 // check mark_begin, begin to check line after this match
1555 if (AsciiStrCmp (LineBuffer
, "; mark_begin;") == 0) {
1556 CodParseState
= EdbEbcCodParseStateSymbolInitialized
;
1558 LineBuffer
= AsciiStrGetNextTokenLine ("\n\r");
1559 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
1562 case EdbEbcCodParseStateSymbolInitialized
:
1564 // check mark_end, not check line after this match
1566 if (AsciiStrCmp (LineBuffer
, "; mark_end;") == 0) {
1567 CodParseState
= EdbEbcCodParseStateUninitialized
;
1568 LineBuffer
= AsciiStrGetNextTokenLine ("\n\r");
1569 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
1574 // not check this line if the first char is as follows
1576 if ((*LineBuffer
== 0) ||
1577 (*LineBuffer
== '$') ||
1578 (*LineBuffer
== ';') ||
1579 (*LineBuffer
== '_') ||
1580 (*LineBuffer
== ' ')) {
1581 LineBuffer
= AsciiStrGetNextTokenLine ("\n\r");
1582 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
1587 // get function name, function name is followed by char 0x09.
1589 FieldBuffer
= AsciiStrGetNewTokenField (LineBuffer
, Char
);
1590 if (AsciiStriCmp (FieldBuffer
, Name
) == 0) {
1591 BufferStart
= FieldBuffer
;
1592 CodParseState
= EdbEbcCodParseStateSymbolStart
;
1594 PatchForAsciiStrTokenAfter (FieldBuffer
, 0x9);
1599 LineBuffer
= AsciiStrGetNextTokenLine ("\n\r");
1600 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
1603 case EdbEbcCodParseStateSymbolStart
:
1605 // check mark_end, if this match, means the function is found successfully.
1607 if (AsciiStrCmp (LineBuffer
, "; mark_end;") == 0) {
1608 CodParseState
= EdbEbcCodParseStateSymbolEnd
;
1610 // prepare CodeBufferSize, FuncOffset, and FuncStart to return
1612 BufferEnd
= LineBuffer
+ sizeof("; mark_end;") - 1;
1613 *CodeBufferSize
= (UINTN
)BufferEnd
- (UINTN
)BufferStart
;
1614 *FuncOffset
= Offset
;
1615 PatchForAsciiStrTokenAfter (LineBuffer
, '\n');
1620 // Get function offset
1622 if ((Offset
== (UINTN
)-1) &&
1623 (*LineBuffer
== ' ')) {
1624 FieldBuffer
= AsciiStrGetNewTokenField (LineBuffer
+ 2, " ");
1625 Offset
= AsciiXtoi (FieldBuffer
);
1626 PatchForAsciiStrTokenAfter (FieldBuffer
, ' ');
1632 LineBuffer
= AsciiStrGetNextTokenLine ("\n\r");
1633 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
1636 case EdbEbcCodParseStateSymbolEnd
:
1645 // no function found
1651 EdbLoadCodBySymbol (
1654 IN UINTN BufferSize
,
1655 OUT UINTN
*CodeBufferSize
,
1656 OUT UINTN
*FuncOffset
1660 Routine Description:
1666 Name - Symbol file name
1667 BufferSize - Symbol file buffer size
1668 Buffer - Symbol file buffer
1669 CodeBufferSize - Code buffer size
1670 FuncOffset - Code funcion offset
1679 // COD file format depends on the compiler.
1681 // It is possible to check the different COD file format in this routine.
1682 // Now only IEC is supported.
1684 return EdbLoadCodBySymbolByIec (Name
, Buffer
, BufferSize
, CodeBufferSize
, FuncOffset
);
1688 EdbFindCodeFromObject (
1689 IN EFI_DEBUGGER_PRIVATE_DATA
*DebuggerPrivate
,
1690 IN EFI_DEBUGGER_SYMBOL_OBJECT
*Object
,
1695 Routine Description:
1697 Find code from object
1701 Object - Symbol object
1702 FileName - File name
1713 // Go througn each Entry in this Object
1715 for (EntryIndex
= 0; EntryIndex
< Object
->EntryCount
; EntryIndex
++) {
1717 // This check is for Function only
1719 if ((Object
->Entry
[EntryIndex
].Type
!= EfiDebuggerSymbolFunction
) &&
1720 (Object
->Entry
[EntryIndex
].Type
!= EfiDebuggerSymbolStaticFunction
)) {
1724 // Skip match varbss_init function, because they has no source code
1726 if (AsciiStrnCmp (Object
->Entry
[EntryIndex
].Name
, "varbss_init", sizeof("varbss_init") - 1) == 0) {
1732 if (!MatchObjAndCod (Object
->Entry
[EntryIndex
].ObjName
, FileName
)) {
1736 // found it, return source buffer
1738 if (Object
->Entry
[EntryIndex
].CodBuffer
!= NULL
) {
1739 return Object
->Entry
[EntryIndex
].SourceBuffer
;
1751 IN EFI_DEBUGGER_PRIVATE_DATA
*DebuggerPrivate
,
1752 IN CHAR16
*MapFileName
,
1753 IN CHAR16
*FileName
,
1754 IN UINTN BufferSize
,
1759 Routine Description:
1765 DebuggerPrivate - EBC Debugger private data structure
1766 MapFileName - Symbol file name
1767 FileName - Code file name
1768 BufferSize - Code file buffer size
1769 Buffer - Code file buffer
1773 EFI_SUCCESS - Code loaded successfully
1777 EFI_DEBUGGER_SYMBOL_OBJECT
*Object
;
1786 Object
= EdbFindSymbolFile (DebuggerPrivate
, MapFileName
, &ObjectIndex
);
1787 if (Object
== NULL
) {
1788 EDBPrint (L
"SymbolFile is not loaded!\n");
1789 return EFI_NOT_FOUND
;
1792 // Check duplicated File
1794 SourceBuffer
= EdbFindCodeFromObject (DebuggerPrivate
, Object
, FileName
);
1795 if (SourceBuffer
!= NULL
) {
1797 // unnload duplicated code
1799 Status
= EdbUnloadCode (DebuggerPrivate
, MapFileName
, FileName
, &SourceBuffer
);
1800 if (EFI_ERROR(Status
)) {
1801 DEBUG ((DEBUG_ERROR
, "Unload Duplicated Code File Error!\n"));
1804 Status
= EdbDeleteCodeBuffer (DebuggerPrivate
, MapFileName
, FileName
, SourceBuffer
);
1805 if (EFI_ERROR(Status
)) {
1806 DEBUG ((DEBUG_ERROR
, "Delete Duplicated Code File Error!\n"));
1813 // Go through each SymbolEntry
1815 for (EntryIndex
= 0; EntryIndex
< Object
->EntryCount
; EntryIndex
++) {
1817 // load symbol for function only
1819 if ((Object
->Entry
[EntryIndex
].Type
!= EfiDebuggerSymbolFunction
) &&
1820 (Object
->Entry
[EntryIndex
].Type
!= EfiDebuggerSymbolStaticFunction
)) {
1826 if (AsciiStrnCmp (Object
->Entry
[EntryIndex
].Name
, "varbss_init", sizeof("varbss_init") - 1) == 0) {
1832 if (!MatchObjAndCod (Object
->Entry
[EntryIndex
].ObjName
, FileName
)) {
1836 // load code for this symbol
1838 Object
->Entry
[EntryIndex
].CodBuffer
= EdbLoadCodBySymbol (
1839 Object
->Entry
[EntryIndex
].Name
,
1842 &Object
->Entry
[EntryIndex
].CodBufferSize
,
1843 &Object
->Entry
[EntryIndex
].FuncOffsetBase
1845 if (Object
->Entry
[EntryIndex
].CodBuffer
!= NULL
) {
1846 Object
->Entry
[EntryIndex
].SourceBuffer
= Buffer
;
1851 // patch end '\0' for each code buffer
1853 for (EntryIndex
= 0; EntryIndex
< Object
->EntryCount
; EntryIndex
++) {
1854 if (Object
->Entry
[EntryIndex
].CodBuffer
!= NULL
) {
1855 *((UINT8
*)Object
->Entry
[EntryIndex
].CodBuffer
+ Object
->Entry
[EntryIndex
].CodBufferSize
) = 0;
1856 DEBUG ((DEBUG_ERROR
, " CodeSymbol: %a, FuncOffset: 0x05%x\n", Object
->Entry
[EntryIndex
].Name
, Object
->Entry
[EntryIndex
].FuncOffsetBase
));
1857 // DEBUG ((DEBUG_ERROR, " [CODE]:\n%a\n", Object->Entry[EntryIndex].CodBuffer));
1869 IN EFI_DEBUGGER_PRIVATE_DATA
*DebuggerPrivate
,
1870 IN CHAR16
*MapFileName
,
1871 IN CHAR16
*FileName
,
1876 Routine Description:
1882 DebuggerPrivate - EBC Debugger private data structure
1883 MapFileName - Symbol file name
1884 FileName - Code file name
1885 Buffer - Code file buffer
1889 EFI_SUCCESS - Code unloaded successfully
1893 EFI_DEBUGGER_SYMBOL_OBJECT
*Object
;
1900 Object
= EdbFindSymbolFile (DebuggerPrivate
, MapFileName
, &ObjectIndex
);
1901 if (Object
== NULL
) {
1902 EDBPrint (L
"SymbolFile is not loaded!\n");
1903 return EFI_NOT_FOUND
;
1909 *Buffer
= EdbFindCodeFromObject (DebuggerPrivate
, Object
, FileName
);
1910 if (*Buffer
== NULL
) {
1911 EDBPrint (L
"CodeFile is not loaded!\n");
1912 return EFI_NOT_FOUND
;
1916 // go through each entry
1918 for (EntryIndex
= 0; EntryIndex
< Object
->EntryCount
; EntryIndex
++) {
1919 if ((Object
->Entry
[EntryIndex
].Type
!= EfiDebuggerSymbolFunction
) &&
1920 (Object
->Entry
[EntryIndex
].Type
!= EfiDebuggerSymbolStaticFunction
)) {
1923 if (AsciiStrnCmp (Object
->Entry
[EntryIndex
].Name
, "varbss_init", sizeof("varbss_init") - 1) == 0) {
1926 if (!MatchObjAndCod (Object
->Entry
[EntryIndex
].ObjName
, FileName
)) {
1930 // clean up the buffer
1932 Object
->Entry
[EntryIndex
].CodBuffer
= NULL
;
1933 Object
->Entry
[EntryIndex
].CodBufferSize
= 0;
1934 Object
->Entry
[EntryIndex
].FuncOffsetBase
= 0;
1935 Object
->Entry
[EntryIndex
].SourceBuffer
= NULL
;
1946 IN EFI_DEBUGGER_PRIVATE_DATA
*DebuggerPrivate
,
1947 IN CHAR16
*MapFileName
,
1948 IN CHAR16
*CodeFileName
,
1949 IN UINTN SourceBufferSize
,
1950 IN VOID
*SourceBuffer
1954 Routine Description:
1960 DebuggerPrivate - EBC Debugger private data structure
1961 MapFileName - Symbol file name
1962 CodeFileName - Code file name
1963 SourceBufferSize- Code buffer size
1964 SourceBuffer - Code buffer
1968 EFI_SUCCESS - CodeBuffer added successfully
1973 EFI_DEBUGGER_SYMBOL_OBJECT
*Object
;
1978 Object
= EdbFindSymbolFile (DebuggerPrivate
, MapFileName
, NULL
);
1979 if (Object
== NULL
) {
1980 EDBPrint (L
"SymbolFile is not loaded!\n");
1981 return EFI_NOT_FOUND
;
1985 // Add it to last entry
1987 for (Index
= 0; Object
->SourceBuffer
[Index
] != NULL
; Index
++) {
1990 Object
->SourceBuffer
[Index
] = SourceBuffer
;
1996 EdbDeleteCodeBuffer (
1997 IN EFI_DEBUGGER_PRIVATE_DATA
*DebuggerPrivate
,
1998 IN CHAR16
*MapFileName
,
1999 IN CHAR16
*CodeFileName
,
2000 IN VOID
*SourceBuffer
2004 Routine Description:
2010 DebuggerPrivate - EBC Debugger private data structure
2011 MapFileName - Symbol file name
2012 CodeFileName - Code file name
2013 SourceBuffer - Code buffer
2017 EFI_SUCCESS - CodeBuffer deleted successfully
2022 EFI_DEBUGGER_SYMBOL_OBJECT
*Object
;
2027 Object
= EdbFindSymbolFile (DebuggerPrivate
, MapFileName
, NULL
);
2028 if (Object
== NULL
) {
2029 EDBPrint (L
"SymbolFile is not loaded!\n");
2030 return EFI_NOT_FOUND
;
2033 for (Index
= 0; Object
->SourceBuffer
[Index
] != NULL
; Index
++) {
2035 // free the buffer if match
2037 if (Object
->SourceBuffer
[Index
] == SourceBuffer
) {
2038 gBS
->FreePool (SourceBuffer
);
2043 if (Object
->SourceBuffer
[Index
] == NULL
) {
2045 // not return NOT_FOUND
2053 Object
->SourceBuffer
[Index
] = NULL
;
2054 for (Index
= Index
+ 1; Object
->SourceBuffer
[Index
] != NULL
; Index
++) {
2055 Object
->SourceBuffer
[Index
- 1] = Object
->SourceBuffer
[Index
];
2057 Object
->SourceBuffer
[Index
- 1] = NULL
;
2068 Routine Description:
2070 Find the symbol string according to address
2074 Address - Symbol address
2083 EFI_DEBUGGER_SYMBOL_OBJECT
*Object
;
2085 EFI_DEBUGGER_SYMBOL_ENTRY
*Entry
;
2088 // need we display symbol
2090 if (!mDebuggerPrivate
.DebuggerSymbolContext
.DisplaySymbol
) {
2095 // Go through each object and entry
2097 Object
= mDebuggerPrivate
.DebuggerSymbolContext
.Object
;
2098 for (ObjectIndex
= 0; ObjectIndex
< mDebuggerPrivate
.DebuggerSymbolContext
.ObjectCount
; ObjectIndex
++) {
2099 Entry
= Object
[ObjectIndex
].Entry
;
2100 for (EntryIndex
= 0; EntryIndex
< Object
[ObjectIndex
].EntryCount
; EntryIndex
++) {
2102 // if Address match, return Name
2104 if (Address
== (Entry
[EntryIndex
].RVA
+ Object
[ObjectIndex
].BaseAddress
)) {
2105 return Entry
[EntryIndex
].Name
;
2117 EdbGetLineNumberAndOffsetFromThisLine (
2123 Routine Description:
2125 Get line number and offset from this line in code file
2129 Line - Line buffer in code file
2130 Offset - Offset to functin entry
2142 LineNumber
= (UINTN
)-1;
2144 *Offset
= (UINTN
)-1;
2146 while (LineBuffer
!= NULL
) {
2150 if (*LineBuffer
!= ' ') {
2157 if (*(LineBuffer
+ 2) != ' ') {
2158 if (*Offset
== (UINTN
)-1) {
2159 FieldBuffer
= AsciiStrGetNewTokenField (LineBuffer
+ 2, " ");
2160 *Offset
= AsciiXtoi (FieldBuffer
);
2161 PatchForAsciiStrTokenAfter (FieldBuffer
, ' ');
2166 // 1. assembly instruction
2168 FieldBuffer
= AsciiStrGetNewTokenField (LineBuffer
, ":");
2172 FieldBuffer
= AsciiStrGetNextTokenField (":");
2173 PatchForAsciiStrTokenBefore (FieldBuffer
, ':');
2174 if (FieldBuffer
== NULL
) {
2179 LineBuffer
= AsciiStrGetNextTokenLine ("\n");
2180 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
2186 FieldBuffer
= AsciiStrGetNextTokenField (":");
2187 PatchForAsciiStrTokenBefore (FieldBuffer
, ':');
2188 if (FieldBuffer
== NULL
) {
2192 LineBuffer
= AsciiStrGetNextTokenLine ("\n");
2193 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
2197 LineNumber
= AsciiAtoi (FieldBuffer
);
2209 EdbEbcLineSearchTypeAny
,
2210 EdbEbcLineSearchTypeFirst
,
2211 EdbEbcLineSearchTypeLast
,
2212 EdbEbcLineSearchTypeMax
,
2213 } EDB_EBC_LINE_SEARCH_TYPE
;
2216 EdbGetLineNumberFromCode (
2217 IN EFI_DEBUGGER_SYMBOL_ENTRY
*Entry
,
2218 IN UINTN FuncOffset
,
2219 IN EDB_EBC_LINE_SEARCH_TYPE SearchType
2223 Routine Description:
2225 Get line number from this code file
2229 Entry - Symbol entry
2230 FuncOffset - Offset to functin entry
2231 SearchType - Search type for the code
2242 UINTN CandidateLineNumber
;
2243 UINTN CandidateOffset
;
2245 if (SearchType
< 0 || SearchType
>= EdbEbcLineSearchTypeMax
) {
2249 LineNumber
= (UINTN
)-1;
2250 CandidateLineNumber
= (UINTN
)-1;
2251 CandidateOffset
= (UINTN
)-1;
2252 LineBuffer
= AsciiStrGetNewTokenLine (Entry
->CodBuffer
, "\n");
2253 while (LineBuffer
!= NULL
) {
2254 if (*LineBuffer
!= ' ') {
2255 LineBuffer
= AsciiStrGetNextTokenLine ("\n");
2256 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
2263 LineNumber
= EdbGetLineNumberAndOffsetFromThisLine (LineBuffer
, &Offset
);
2268 if (Offset
!= FuncOffset
) {
2270 // Check last offset match
2272 if (CandidateOffset
== FuncOffset
) {
2273 if (SearchType
== EdbEbcLineSearchTypeLast
) {
2274 PatchForAsciiStrTokenAfter (LineBuffer
, '\n');
2275 if (CandidateLineNumber
!= LineNumber
) {
2276 return CandidateLineNumber
;
2287 LineBuffer
= AsciiStrGetNextTokenLine ("\n");
2288 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
2289 CandidateLineNumber
= LineNumber
;
2294 // Offset match, more check
2296 if (SearchType
== EdbEbcLineSearchTypeAny
) {
2297 PatchForAsciiStrTokenAfter (LineBuffer
, '\n');
2301 if (SearchType
== EdbEbcLineSearchTypeFirst
) {
2305 PatchForAsciiStrTokenAfter (LineBuffer
, '\n');
2306 if (CandidateLineNumber
!= LineNumber
) {
2313 CandidateLineNumber
= LineNumber
;
2314 CandidateOffset
= Offset
;
2316 LineBuffer
= AsciiStrGetNextTokenLine ("\n");
2317 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
2321 // Check last offset match
2323 if (CandidateOffset
== FuncOffset
) {
2324 if (SearchType
== EdbEbcLineSearchTypeLast
) {
2325 return CandidateLineNumber
;
2333 EdbGetSourceStrFromCodeByLine (
2334 IN EFI_DEBUGGER_SYMBOL_ENTRY
*Entry
,
2335 IN UINTN LineNumber
,
2340 Routine Description:
2342 Get the source string from this code file by line
2346 Entry - Symbol entry
2347 LineNumber - line number
2348 FuncEnd - Function end
2362 LineBuffer
= AsciiStrGetNewTokenLine (Entry
->CodBuffer
, "\n");
2363 while (LineBuffer
!= NULL
) {
2364 if (*LineBuffer
!= ';') {
2365 if (FuncStart
!= NULL
) {
2369 *FuncEnd
= LineBuffer
- 1;
2370 PatchForAsciiStrTokenAfter (LineBuffer
, '\n');
2373 LineBuffer
= AsciiStrGetNextTokenLine ("\n");
2374 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
2381 FieldBuffer
= AsciiStrGetNewTokenField (LineBuffer
+ 1, " ");
2382 Number
= AsciiAtoi (FieldBuffer
);
2383 PatchForAsciiStrTokenAfter (FieldBuffer
, ' ');
2384 if (Number
!= LineNumber
) {
2385 LineBuffer
= AsciiStrGetNextTokenLine ("\n");
2386 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
2391 // Line match, get line number
2393 if (FuncStart
== NULL
) {
2394 FuncStart
= LineBuffer
;
2397 LineBuffer
= AsciiStrGetNextTokenLine ("\n");
2398 PatchForAsciiStrTokenBefore (LineBuffer
, '\n');
2405 EdbGetSourceStrFromCode (
2406 IN EFI_DEBUGGER_SYMBOL_ENTRY
*Entry
,
2407 IN UINTN FuncOffset
,
2412 Routine Description:
2414 Get source string from this code file
2418 Entry - Symbol entry
2419 FuncOffset - Offset to functin entry
2420 FuncEnd - Function end
2431 // Only search the last line, then display
2433 LineNumber
= EdbGetLineNumberFromCode (Entry
, FuncOffset
, EdbEbcLineSearchTypeLast
);
2434 if (LineNumber
== (UINTN
)-1) {
2438 return EdbGetSourceStrFromCodeByLine (Entry
, LineNumber
, FuncEnd
);
2448 Routine Description:
2454 Address - Instruction address
2455 IsPrint - Whether need to print
2460 0 - not find the source
2464 UINTN SymbolAddress
;
2465 EFI_DEBUGGER_SYMBOL_OBJECT
*RetObject
;
2466 EFI_DEBUGGER_SYMBOL_ENTRY
*RetEntry
;
2471 CHAR8 Buffer
[EFI_DEBUG_MAX_PRINT_BUFFER
];
2475 // need we display symbol
2477 if (!mDebuggerPrivate
.DebuggerSymbolContext
.DisplaySymbol
) {
2482 // find the symbol address
2484 SymbolAddress
= EbdFindSymbolAddress (
2486 EdbMatchSymbolTypeLowerAddress
,
2490 if (SymbolAddress
== 0) {
2494 FuncOffset
= Address
- SymbolAddress
+ RetEntry
->FuncOffsetBase
;
2499 FuncStart
= EdbGetSourceStrFromCode (RetEntry
, FuncOffset
, (VOID
**) &FuncEnd
);
2500 if (FuncStart
== NULL
) {
2505 // check whether need to real print
2511 *(UINT8
*)FuncEnd
= 0;
2514 // seperate buffer by \n, so that \r can be added.
2516 FuncIndex
= FuncStart
;
2517 while (*FuncIndex
!= 0) {
2518 if (*FuncIndex
== '\n') {
2519 if ((FuncIndex
- FuncStart
) < (EFI_DEBUG_MAX_PRINT_BUFFER
- 3)) {
2520 BufferSize
= FuncIndex
- FuncStart
;
2522 BufferSize
= EFI_DEBUG_MAX_PRINT_BUFFER
- 3;
2524 if (BufferSize
!= 0) {
2525 CopyMem (Buffer
, FuncStart
, BufferSize
);
2527 Buffer
[BufferSize
] = 0;
2528 EDBPrint (L
"%a\n", Buffer
);
2529 FuncStart
= FuncIndex
+ 1;
2530 FuncIndex
= FuncStart
;
2539 *(UINT8
*)FuncEnd
= '\n';
2545 GetMapfileAndSymbol (
2547 OUT CHAR16
**MapfileName
,
2548 OUT CHAR16
**SymbolName
2552 Routine Description:
2554 Get Mapfile and SymbolName from one symbol format: [MapFileName:]SymbolName
2558 Symbol - whole Symbol name
2559 MapfileName - the mapfile name in the symbol
2560 SymbolName - the symbol name in the symbol
2570 *MapfileName
= NULL
;
2571 *SymbolName
= Symbol
;
2573 for (Ch
= Symbol
; *Ch
!= 0; Ch
++) {
2578 *MapfileName
= Symbol
;
2580 *SymbolName
= Ch
+ 1;
2595 Routine Description:
2597 Convert a symbol to an address
2601 Symbol - Symbol name
2602 Address - Symbol address
2606 EFI_SUCCESS - symbol found and address returned.
2607 EFI_NOT_FOUND - symbol not found
2608 EFI_NO_MAPPING - duplicated symbol not found
2613 EFI_DEBUGGER_SYMBOL_OBJECT
*Object
;
2615 EFI_DEBUGGER_SYMBOL_ENTRY
*Entry
;
2617 CHAR16
*MapfileName
;
2620 // Split one symbol to mapfile name and symbol name
2622 GetMapfileAndSymbol (Symbol
, &MapfileName
, &SymbolName
);
2626 // Go through each object
2628 Object
= mDebuggerPrivate
.DebuggerSymbolContext
.Object
;
2629 for (ObjectIndex
= 0; ObjectIndex
< mDebuggerPrivate
.DebuggerSymbolContext
.ObjectCount
; ObjectIndex
++) {
2631 // Check MapfileName
2633 if ((MapfileName
!= NULL
) && (StriCmp (Object
[ObjectIndex
].Name
, MapfileName
) != 0)) {
2637 // Go through each entry
2639 Entry
= Object
[ObjectIndex
].Entry
;
2640 for (EntryIndex
= 0; EntryIndex
< Object
[ObjectIndex
].EntryCount
; EntryIndex
++) {
2642 // Check SymbolName (case sensitive)
2644 if (StrCmpUnicodeAndAscii (SymbolName
, Entry
[EntryIndex
].Name
) == 0) {
2645 if ((*Address
!= 0) && (MapfileName
== NULL
)) {
2647 // Find the duplicated symbol
2649 EDBPrint (L
"Duplicated Symbol found!\n");
2650 return EFI_NO_MAPPING
;
2655 *Address
= (Entry
[EntryIndex
].RVA
+ Object
[ObjectIndex
].BaseAddress
);
2661 if (*Address
== 0) {
2665 return EFI_NOT_FOUND
;