]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / EbcDebugger / Edb.c
1 /** @file
2
3 Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
5
6 **/
7
8 #include <Uefi.h>
9 #include "Edb.h"
10
11 EFI_DEBUGGER_PRIVATE_DATA mDebuggerPrivate = {
12 EFI_DEBUGGER_SIGNATURE, // Signature
13 IsaEbc, // Isa
14 (EBC_DEBUGGER_MAJOR_VERSION << 16) |
15 EBC_DEBUGGER_MINOR_VERSION, // EfiDebuggerRevision
16 (VM_MAJOR_VERSION << 16) |
17 VM_MINOR_VERSION, // EbcVmRevision
18 {
19 EFI_DEBUGGER_CONFIGURATION_VERSION,
20 &mDebuggerPrivate,
21 }, // DebuggerConfiguration
22 NULL, // DebugImageInfoTableHeader
23 NULL, // Vol
24 NULL, // PciRootBridgeIo
25 mDebuggerCommandSet, // DebuggerCommandSet
26 {0}, // DebuggerSymbolContext
27 0, // DebuggerBreakpointCount
28 {{0}}, // DebuggerBreakpointContext
29 0, // CallStackEntryCount
30 {{0}}, // CallStackEntry
31 0, // TraceEntryCount
32 {{0}}, // TraceEntry
33 {0}, // StepContext
34 {0}, // GoTilContext
35 0, // InstructionScope
36 EFI_DEBUG_DEFAULT_INSTRUCTION_NUMBER, // InstructionNumber
37 EFI_DEBUG_FLAG_EBC_BOE | EFI_DEBUG_FLAG_EBC_BOT, // FeatureFlags
38 0, // StatusFlags
39 FALSE, // EnablePageBreak
40 NULL // BreakEvent
41 };
42
43 CHAR16 *mExceptionStr[] = {
44 L"EXCEPT_EBC_UNDEFINED",
45 L"EXCEPT_EBC_DIVIDE_ERROR",
46 L"EXCEPT_EBC_DEBUG",
47 L"EXCEPT_EBC_BREAKPOINT",
48 L"EXCEPT_EBC_OVERFLOW",
49 L"EXCEPT_EBC_INVALID_OPCODE",
50 L"EXCEPT_EBC_STACK_FAULT",
51 L"EXCEPT_EBC_ALIGNMENT_CHECK",
52 L"EXCEPT_EBC_INSTRUCTION_ENCODING",
53 L"EXCEPT_EBC_BAD_BREAK",
54 L"EXCEPT_EBC_SINGLE_STEP",
55 };
56
57 /**
58
59 Clear all the breakpoint.
60
61 @param DebuggerPrivate EBC Debugger private data structure
62 @param NeedRemove Whether need to remove all the breakpoint
63
64 **/
65 VOID
66 EdbClearAllBreakpoint (
67 IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
68 IN BOOLEAN NeedRemove
69 )
70 {
71 UINTN Index;
72
73 //
74 // Patch all the breakpoint
75 //
76 for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
77 if (DebuggerPrivate->DebuggerBreakpointContext[Index].State) {
78 CopyMem (
79 (VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress,
80 &DebuggerPrivate->DebuggerBreakpointContext[Index].OldInstruction,
81 sizeof(UINT16)
82 );
83 }
84 }
85
86 //
87 // Zero Breakpoint context, if need to remove all breakpoint
88 //
89 if (NeedRemove) {
90 DebuggerPrivate->DebuggerBreakpointCount = 0;
91 ZeroMem (DebuggerPrivate->DebuggerBreakpointContext, sizeof(DebuggerPrivate->DebuggerBreakpointContext));
92 }
93
94 //
95 // Done
96 //
97 return ;
98 }
99
100 /**
101
102 Set all the breakpoint.
103
104 @param DebuggerPrivate EBC Debugger private data structure
105
106 **/
107 VOID
108 EdbSetAllBreakpoint (
109 IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
110 )
111 {
112 UINTN Index;
113 UINT16 Data16;
114
115 //
116 // Set all the breakpoint (BREAK(3) : 0x0300)
117 //
118 Data16 = 0x0300;
119 for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
120 if (DebuggerPrivate->DebuggerBreakpointContext[Index].State) {
121 CopyMem (
122 (VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress,
123 &Data16,
124 sizeof(UINT16)
125 );
126 }
127 }
128
129 //
130 // Check if current break is caused by breakpoint set.
131 // If so, we need to patch memory back to let user see the real memory.
132 //
133 if (DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].BreakpointAddress != 0) {
134 CopyMem (
135 (VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].BreakpointAddress,
136 &DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].OldInstruction,
137 sizeof(UINT16)
138 );
139 DebuggerPrivate->StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_BP;
140 }
141
142 //
143 // Done
144 //
145 return ;
146 }
147
148 /**
149
150 Check all the breakpoint, if match, then set status flag, and record current breakpoint.
151 Then clear all breakpoint to let user see a clean memory
152
153 @param DebuggerPrivate EBC Debugger private data structure
154 @param SystemContext EBC system context.
155
156 **/
157 VOID
158 EdbCheckBreakpoint (
159 IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
160 IN EFI_SYSTEM_CONTEXT SystemContext
161 )
162 {
163 UINT64 Address;
164 UINTN Index;
165 BOOLEAN IsHitBreakpoint;
166
167 //
168 // Roll back IP for breakpoint instruction (BREAK(3) : 0x0300)
169 //
170 Address = SystemContext.SystemContextEbc->Ip - sizeof(UINT16);
171
172 //
173 // Check if the breakpoint is hit
174 //
175 IsHitBreakpoint = FALSE;
176 for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
177 if ((DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress == Address) &&
178 (DebuggerPrivate->DebuggerBreakpointContext[Index].State)) {
179 IsHitBreakpoint = TRUE;
180 break;
181 }
182 }
183
184 if (IsHitBreakpoint) {
185 //
186 // If hit, record current breakpoint
187 //
188 DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX] = DebuggerPrivate->DebuggerBreakpointContext[Index];
189 DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].State = TRUE;
190 //
191 // Update: IP and Instruction (NOTE: Since we not allow set breakpoint to BREAK 3, this update is safe)
192 //
193 SystemContext.SystemContextEbc->Ip = Address;
194 //
195 // Set Flags
196 //
197 DebuggerPrivate->StatusFlags |= EFI_DEBUG_FLAG_EBC_BP;
198 } else {
199 //
200 // If not hit, check whether current IP is in breakpoint list,
201 // because STEP will be triggered before execute the instruction.
202 // We should not patch it in de-init.
203 //
204 Address = SystemContext.SystemContextEbc->Ip;
205
206 //
207 // Check if the breakpoint is hit
208 //
209 IsHitBreakpoint = FALSE;
210 for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
211 if ((DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress == Address) &&
212 (DebuggerPrivate->DebuggerBreakpointContext[Index].State)) {
213 IsHitBreakpoint = TRUE;
214 break;
215 }
216 }
217
218 if (IsHitBreakpoint) {
219 //
220 // If hit, record current breakpoint
221 //
222 DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX] = DebuggerPrivate->DebuggerBreakpointContext[Index];
223 DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].State = TRUE;
224 //
225 // Do not set Breakpoint flag. We record the address here just let it not patch breakpoint address when de-init.
226 //
227 } else {
228 //
229 // Zero current breakpoint
230 //
231 ZeroMem (
232 &DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX],
233 sizeof(DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX])
234 );
235 }
236 }
237
238 //
239 // Done
240 //
241 return ;
242 }
243
244 /**
245 clear all the symbol.
246
247 @param DebuggerPrivate EBC Debugger private data structure
248
249 **/
250 VOID
251 EdbClearSymbol (
252 IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
253 )
254 {
255 EFI_DEBUGGER_SYMBOL_CONTEXT *DebuggerSymbolContext;
256 EFI_DEBUGGER_SYMBOL_OBJECT *Object;
257 UINTN ObjectIndex;
258 UINTN Index;
259
260 //
261 // Go throuth each object
262 //
263 DebuggerSymbolContext = &DebuggerPrivate->DebuggerSymbolContext;
264 for (ObjectIndex = 0; ObjectIndex < DebuggerSymbolContext->ObjectCount; ObjectIndex++) {
265 Object = &DebuggerSymbolContext->Object[ObjectIndex];
266 //
267 // Go throuth each entry
268 //
269 for (Index = 0; Index < Object->EntryCount; Index++) {
270 ZeroMem (&Object->Entry[Index], sizeof(Object->Entry[Index]));
271 }
272 ZeroMem (Object->Name, sizeof(Object->Name));
273 Object->EntryCount = 0;
274 Object->BaseAddress = 0;
275 Object->StartEntrypointRVA = 0;
276 Object->MainEntrypointRVA = 0;
277 //
278 // Free source buffer
279 //
280 for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
281 gBS->FreePool (Object->SourceBuffer[Index]);
282 Object->SourceBuffer[Index] = NULL;
283 }
284 }
285 DebuggerSymbolContext->ObjectCount = 0;
286
287 return ;
288 }
289
290 /**
291
292 Initialize Debugger private data structure
293
294 @param DebuggerPrivate EBC Debugger private data structure
295 @param ExceptionType Exception type.
296 @param SystemContext EBC system context.
297 @param Initialized Whether the DebuggerPrivate data is initialized.
298
299 **/
300 EFI_STATUS
301 InitDebuggerPrivateData (
302 IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
303 IN EFI_EXCEPTION_TYPE ExceptionType,
304 IN EFI_SYSTEM_CONTEXT SystemContext,
305 IN BOOLEAN Initialized
306 )
307 {
308 //
309 // clear STEP flag in any condition.
310 //
311 if (SystemContext.SystemContextEbc->Flags & ((UINT64) VMFLAGS_STEP)) {
312 SystemContext.SystemContextEbc->Flags &= ~((UINT64) VMFLAGS_STEP);
313 }
314
315 if (!Initialized) {
316 //
317 // Initialize everything
318 //
319 DebuggerPrivate->InstructionNumber = EFI_DEBUG_DEFAULT_INSTRUCTION_NUMBER;
320
321 DebuggerPrivate->DebuggerBreakpointCount = 0;
322 ZeroMem (DebuggerPrivate->DebuggerBreakpointContext, sizeof(DebuggerPrivate->DebuggerBreakpointContext));
323
324 // DebuggerPrivate->StatusFlags = 0;
325
326 DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = TRUE;
327 DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = FALSE;
328 DebuggerPrivate->DebuggerSymbolContext.ObjectCount = 0;
329 } else {
330 //
331 // Already initialized, just check Breakpoint here.
332 //
333 if (ExceptionType == EXCEPT_EBC_BREAKPOINT) {
334 EdbCheckBreakpoint (DebuggerPrivate, SystemContext);
335 }
336
337 //
338 // Clear all breakpoint
339 //
340 EdbClearAllBreakpoint (DebuggerPrivate, FALSE);
341 }
342
343 //
344 // Set Scope to currentl IP. (Note: Check Breakpoint may change Ip)
345 //
346 DebuggerPrivate->InstructionScope = SystemContext.SystemContextEbc->Ip;
347
348 //
349 // Done
350 //
351 return EFI_SUCCESS;
352 }
353
354 /**
355
356 De-initialize Debugger private data structure.
357
358 @param DebuggerPrivate EBC Debugger private data structure
359 @param ExceptionType Exception type.
360 @param SystemContext EBC system context.
361 @param Initialized Whether the DebuggerPrivate data is initialized.
362
363 **/
364 EFI_STATUS
365 DeinitDebuggerPrivateData (
366 IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
367 IN EFI_EXCEPTION_TYPE ExceptionType,
368 IN EFI_SYSTEM_CONTEXT SystemContext,
369 IN BOOLEAN Initialized
370 )
371 {
372 if (!Initialized) {
373 //
374 // If it does not want initialized state, de-init everything
375 //
376 DebuggerPrivate->FeatureFlags = EFI_DEBUG_FLAG_EBC_BOE | EFI_DEBUG_FLAG_EBC_BOT;
377 DebuggerPrivate->CallStackEntryCount = 0;
378 DebuggerPrivate->TraceEntryCount = 0;
379 ZeroMem (DebuggerPrivate->CallStackEntry, sizeof(DebuggerPrivate->CallStackEntry));
380 ZeroMem (DebuggerPrivate->TraceEntry, sizeof(DebuggerPrivate->TraceEntry));
381
382 //
383 // Clear all breakpoint
384 //
385 EdbClearAllBreakpoint (DebuggerPrivate, TRUE);
386
387 //
388 // Clear symbol
389 //
390 EdbClearSymbol (DebuggerPrivate);
391 } else {
392 //
393 // If it wants to keep initialized state, just set breakpoint.
394 //
395 EdbSetAllBreakpoint (DebuggerPrivate);
396 }
397
398 //
399 // Clear Step context
400 //
401 ZeroMem (&mDebuggerPrivate.StepContext, sizeof(mDebuggerPrivate.StepContext));
402 DebuggerPrivate->StatusFlags = 0;
403
404 //
405 // Done
406 //
407 return EFI_SUCCESS;
408 }
409
410 /**
411
412 Print the reason of current break to EbcDebugger.
413
414 @param DebuggerPrivate EBC Debugger private data structure
415 @param ExceptionType Exception type.
416 @param SystemContext EBC system context.
417 @param Initialized Whether the DebuggerPrivate data is initialized.
418
419 **/
420 VOID
421 PrintExceptionReason (
422 IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
423 IN EFI_EXCEPTION_TYPE ExceptionType,
424 IN EFI_SYSTEM_CONTEXT SystemContext,
425 IN BOOLEAN Initialized
426 )
427 {
428 //
429 // Print break status
430 //
431 if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_GT) == EFI_DEBUG_FLAG_EBC_GT) {
432 EDBPrint (L"Break on GoTil\n");
433 } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOC) == EFI_DEBUG_FLAG_EBC_BOC) {
434 EDBPrint (L"Break on CALL\n");
435 } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOCX) == EFI_DEBUG_FLAG_EBC_BOCX) {
436 EDBPrint (L"Break on CALLEX\n");
437 } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOR) == EFI_DEBUG_FLAG_EBC_BOR) {
438 EDBPrint (L"Break on RET\n");
439 } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOE) == EFI_DEBUG_FLAG_EBC_BOE) {
440 EDBPrint (L"Break on Entrypoint\n");
441 } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOT) == EFI_DEBUG_FLAG_EBC_BOT) {
442 EDBPrint (L"Break on Thunk\n");
443 } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_STEPOVER) == EFI_DEBUG_FLAG_EBC_STEPOVER) {
444 EDBPrint (L"Break on StepOver\n");
445 } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_STEPOUT) == EFI_DEBUG_FLAG_EBC_STEPOUT) {
446 EDBPrint (L"Break on StepOut\n");
447 } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BP) == EFI_DEBUG_FLAG_EBC_BP) {
448 EDBPrint (L"Break on Breakpoint\n");
449 } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOK) == EFI_DEBUG_FLAG_EBC_BOK) {
450 EDBPrint (L"Break on Key\n");
451 } else {
452 EDBPrint (L"Exception Type - %x", (UINTN)ExceptionType);
453 if ((ExceptionType >= EXCEPT_EBC_UNDEFINED) && (ExceptionType <= EXCEPT_EBC_STEP)) {
454 EDBPrint (L" (%s)\n", mExceptionStr[ExceptionType]);
455 } else {
456 EDBPrint (L"\n");
457 }
458 }
459
460 return ;
461 }
462
463 /**
464
465 The default Exception Callback for the VM interpreter.
466 In this function, we report status code, and print debug information
467 about EBC_CONTEXT, then dead loop.
468
469 @param ExceptionType Exception type.
470 @param SystemContext EBC system context.
471
472 **/
473 VOID
474 EFIAPI
475 EdbExceptionHandler (
476 IN EFI_EXCEPTION_TYPE ExceptionType,
477 IN OUT EFI_SYSTEM_CONTEXT SystemContext
478 )
479 {
480 CHAR16 InputBuffer[EFI_DEBUG_INPUS_BUFFER_SIZE];
481 CHAR16 *CommandArg;
482 EFI_DEBUGGER_COMMAND DebuggerCommand;
483 EFI_DEBUG_STATUS DebugStatus;
484 STATIC BOOLEAN mInitialized;
485
486 mInitialized = FALSE;
487
488 DEBUG ((DEBUG_ERROR, "Hello EBC Debugger!\n"));
489
490 if (!mInitialized) {
491 //
492 // Print version
493 //
494 EDBPrint (
495 L"EBC Interpreter Version - %d.%d\n",
496 (UINTN)VM_MAJOR_VERSION,
497 (UINTN)VM_MINOR_VERSION
498 );
499 EDBPrint (
500 L"EBC Debugger Version - %d.%d\n",
501 (UINTN)EBC_DEBUGGER_MAJOR_VERSION,
502 (UINTN)EBC_DEBUGGER_MINOR_VERSION
503 );
504 }
505 //
506 // Init Private Data
507 //
508 InitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
509
510 //
511 // EDBPrint basic info
512 //
513 PrintExceptionReason (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
514
515 EdbShowDisasm (&mDebuggerPrivate, SystemContext);
516 // EFI_BREAKPOINT ();
517
518 if (!mInitialized) {
519 //
520 // Interactive with user
521 //
522 EDBPrint (L"\nPlease enter command now, \'h\' for help.\n");
523 EDBPrint (L"(Using <Command> -b <...> to enable page break.)\n");
524 }
525 mInitialized = TRUE;
526
527 //
528 // Dispatch each command
529 //
530 while (TRUE) {
531 //
532 // Get user input
533 //
534 Input (L"\n\r" EFI_DEBUG_PROMPT_STRING, InputBuffer, EFI_DEBUG_INPUS_BUFFER_SIZE);
535 EDBPrint (L"\n");
536
537 //
538 // Get command
539 //
540 DebuggerCommand = MatchDebuggerCommand (InputBuffer, &CommandArg);
541 if (DebuggerCommand == NULL) {
542 EDBPrint (L"ERROR: Command not found!\n");
543 continue;
544 }
545
546 //
547 // Check PageBreak;
548 //
549 if (CommandArg != NULL) {
550 if (StriCmp (CommandArg, L"-b") == 0) {
551 CommandArg = StrGetNextTokenLine (L" ");
552 mDebuggerPrivate.EnablePageBreak = TRUE;
553 }
554 }
555
556 //
557 // Dispatch command
558 //
559 DebugStatus = DebuggerCommand (CommandArg, &mDebuggerPrivate, ExceptionType, SystemContext);
560 mDebuggerPrivate.EnablePageBreak = FALSE;
561
562 //
563 // Check command return status
564 //
565 if (DebugStatus == EFI_DEBUG_RETURN) {
566 mInitialized = FALSE;
567 break;
568 } else if (DebugStatus == EFI_DEBUG_BREAK) {
569 break;
570 } else if (DebugStatus == EFI_DEBUG_CONTINUE) {
571 continue;
572 } else {
573 ASSERT (FALSE);
574 }
575 }
576
577 //
578 // Deinit Private Data
579 //
580 DeinitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
581
582 DEBUG ((DEBUG_ERROR, "Goodbye EBC Debugger!\n"));
583
584 return;
585 }