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