]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c
322dd258d0ecc946a1feffa67fa99c40ca964e76
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / EbcDebugger / EdbHook.c
1 /** @file
2
3 Copyright (c) 2007, 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
15 #include "Edb.h"
16
17 /**
18
19 Check the Hook flag, and trigger exception if match.
20
21 @param VmPtr - EbcDebuggerCheckHookFlag
22 @param Flag - Feature flag
23
24 **/
25 VOID
26 EbcDebuggerCheckHookFlag (
27 IN VM_CONTEXT *VmPtr,
28 IN UINT32 Flag
29 )
30 {
31 if ((mDebuggerPrivate.FeatureFlags & Flag) == Flag) {
32 mDebuggerPrivate.StatusFlags = Flag;
33 EbcDebugSignalException (
34 EXCEPT_EBC_BREAKPOINT,
35 EXCEPTION_FLAG_NONE,
36 VmPtr
37 );
38 }
39 return ;
40 }
41
42 /**
43
44 It will record soruce address for Callstack entry.
45
46 @param SourceEntry - Source address
47 @param Type - Branch type
48
49 **/
50 VOID
51 EbcDebuggerPushCallstackSource (
52 IN UINT64 SourceEntry,
53 IN EFI_DEBUGGER_BRANCH_TYPE Type
54 )
55 {
56 if (mDebuggerPrivate.CallStackEntryCount > EFI_DEBUGGER_CALLSTACK_MAX) {
57 ASSERT (FALSE);
58 mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
59 }
60 //
61 // Record the new callstack entry
62 //
63 mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].SourceAddress = SourceEntry;
64 mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Type = Type;
65
66 //
67 // Do not change CallStackEntryCount
68 //
69
70 return ;
71 }
72
73 /**
74
75 It will record parameter for Callstack entry.
76
77 @param ParameterAddress - The address for the parameter
78 @param Type - Branch type
79
80 **/
81 VOID
82 EbcDebuggerPushCallstackParameter (
83 IN UINT64 ParameterAddress,
84 IN EFI_DEBUGGER_BRANCH_TYPE Type
85 )
86 {
87 if (mDebuggerPrivate.CallStackEntryCount > EFI_DEBUGGER_CALLSTACK_MAX) {
88 ASSERT (FALSE);
89 mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
90 }
91 //
92 // Record the new callstack parameter
93 //
94 mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].ParameterAddr = (UINTN)ParameterAddress;
95 CopyMem (
96 mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Parameter,
97 (VOID *)(UINTN)ParameterAddress,
98 sizeof(mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Parameter)
99 );
100
101 //
102 // Do not change CallStackEntryCount
103 //
104
105 return ;
106 }
107
108 /**
109
110 It will record source address for callstack entry.
111
112 @param DestEntry - Source address
113 @param Type - Branch type
114
115 **/
116 VOID
117 EbcDebuggerPushCallstackDest (
118 IN UINT64 DestEntry,
119 IN EFI_DEBUGGER_BRANCH_TYPE Type
120 )
121 {
122 UINTN Index;
123
124 if (mDebuggerPrivate.CallStackEntryCount < EFI_DEBUGGER_CALLSTACK_MAX) {
125 //
126 // If there is empty entry for callstack, add it
127 //
128 ASSERT (mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Type == Type);
129 mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].DestAddress = DestEntry;
130 mDebuggerPrivate.CallStackEntryCount ++;
131 } else {
132 //
133 // If there is no empty entry for callstack, throw the oldest one
134 //
135 ASSERT (mDebuggerPrivate.CallStackEntry[EFI_DEBUGGER_TRACE_MAX].Type == Type);
136 for (Index = 0; Index < EFI_DEBUGGER_CALLSTACK_MAX; Index++) {
137 mDebuggerPrivate.CallStackEntry[Index] = mDebuggerPrivate.CallStackEntry[Index + 1];
138 }
139 mDebuggerPrivate.CallStackEntry[EFI_DEBUGGER_CALLSTACK_MAX - 1].DestAddress = DestEntry;
140 mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
141 }
142
143 return ;
144 }
145
146 /**
147
148 It will throw the newest Callstack entry.
149
150 **/
151 VOID
152 EbcDebuggerPopCallstack (
153 VOID
154 )
155 {
156 if ((mDebuggerPrivate.CallStackEntryCount > 0) &&
157 (mDebuggerPrivate.CallStackEntryCount <= EFI_DEBUGGER_CALLSTACK_MAX)) {
158 //
159 // Throw the newest one
160 //
161 mDebuggerPrivate.CallStackEntryCount --;
162 mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].SourceAddress = 0;
163 mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].DestAddress = 0;
164 } else if (mDebuggerPrivate.CallStackEntryCount == 0) {
165 //
166 // NOT assert here because it is reasonable, because when we start to build
167 // callstack, we do not know how many function already called.
168 //
169 } else {
170 ASSERT (FALSE);
171 }
172
173 return ;
174 }
175
176 /**
177
178 It will record source address for trace entry.
179
180 @param SourceEntry - Source address
181 @param Type - Branch type
182
183 **/
184 VOID
185 EbcDebuggerPushTraceSourceEntry (
186 IN UINT64 SourceEntry,
187 IN EFI_DEBUGGER_BRANCH_TYPE Type
188 )
189 {
190 if (mDebuggerPrivate.TraceEntryCount > EFI_DEBUGGER_TRACE_MAX) {
191 ASSERT (FALSE);
192 mDebuggerPrivate.TraceEntryCount = EFI_DEBUGGER_TRACE_MAX;
193 }
194 //
195 // Record the new trace entry
196 //
197 mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].SourceAddress = SourceEntry;
198 mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].Type = Type;
199
200 //
201 // Do not change TraceEntryCount
202 //
203
204 return ;
205 }
206
207 /**
208
209 It will record destination address for trace entry.
210
211 @param DestEntry - Destination address
212 @param Type - Branch type
213
214 **/
215 VOID
216 EbcDebuggerPushTraceDestEntry (
217 IN UINT64 DestEntry,
218 IN EFI_DEBUGGER_BRANCH_TYPE Type
219 )
220 {
221 UINTN Index;
222
223 if (mDebuggerPrivate.TraceEntryCount < EFI_DEBUGGER_TRACE_MAX) {
224 //
225 // If there is empty entry for trace, add it
226 //
227 ASSERT (mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].Type == Type);
228 mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].DestAddress = DestEntry;
229 mDebuggerPrivate.TraceEntryCount ++;
230 } else {
231 //
232 // If there is no empty entry for trace, throw the oldest one
233 //
234 ASSERT (mDebuggerPrivate.TraceEntry[EFI_DEBUGGER_TRACE_MAX].Type == Type);
235 for (Index = 0; Index < EFI_DEBUGGER_TRACE_MAX; Index++) {
236 mDebuggerPrivate.TraceEntry[Index] = mDebuggerPrivate.TraceEntry[Index + 1];
237 }
238 mDebuggerPrivate.TraceEntry[EFI_DEBUGGER_CALLSTACK_MAX - 1].DestAddress = DestEntry;
239 mDebuggerPrivate.TraceEntryCount = EFI_DEBUGGER_TRACE_MAX;
240 }
241
242 return ;
243 }
244
245 /**
246
247 It will record address for StepEntry, if STEPOVER or STEPOUT is enabled.
248
249 @param Entry - Break Address
250 @param FramePtr - Break Frame pointer
251 @param Flag - for STEPOVER or STEPOUT
252
253 **/
254 VOID
255 EbcDebuggerPushStepEntry (
256 IN UINT64 Entry,
257 IN UINT64 FramePtr,
258 IN UINT32 Flag
259 )
260 {
261 //
262 // Check StepOver
263 //
264 if ((Flag == EFI_DEBUG_FLAG_EBC_STEPOVER) &&
265 ((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_STEPOVER) == EFI_DEBUG_FLAG_EBC_STEPOVER)) {
266 mDebuggerPrivate.StepContext.BreakAddress = Entry;
267 mDebuggerPrivate.StepContext.FramePointer = FramePtr;
268 mDebuggerPrivate.FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOVER;
269 }
270 //
271 // Check StepOut
272 //
273 if ((Flag == EFI_DEBUG_FLAG_EBC_STEPOUT) &&
274 ((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_STEPOUT) == EFI_DEBUG_FLAG_EBC_STEPOUT)) {
275 mDebuggerPrivate.StepContext.BreakAddress = Entry;
276 mDebuggerPrivate.StepContext.FramePointer = FramePtr;
277 mDebuggerPrivate.FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOUT;
278 }
279 }
280
281 VOID
282 EFIAPI
283 EbcDebuggerBreakEventFunc (
284 IN EFI_EVENT Event,
285 IN VOID *Context
286 )
287 {
288 EFI_STATUS Status;
289
290 if ((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_BOK) != EFI_DEBUG_FLAG_EBC_BOK) {
291 return ;
292 }
293
294 Status = gBS->CheckEvent (gST->ConIn->WaitForKey);
295 if (Status == EFI_SUCCESS) {
296 mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_BOK;
297 }
298 }
299
300 /**
301
302 The hook in InitializeEbcDriver.
303 It will init the EbcDebuggerPrivate data structure.
304
305 @param Handle - The EbcDebugProtocol handle.
306 @param EbcDebugProtocol - The EbcDebugProtocol interface.
307
308 **/
309 VOID
310 EbcDebuggerHookInit (
311 IN EFI_HANDLE Handle,
312 IN EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol
313 )
314 {
315 EFI_STATUS Status;
316 UINTN Index;
317 EFI_DEBUGGER_SYMBOL_OBJECT *Object;
318 EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
319
320
321 //
322 // Register all exception handler
323 //
324 for (Index = EXCEPT_EBC_UNDEFINED; Index <= EXCEPT_EBC_STEP; Index++) {
325 EbcDebugProtocol->RegisterExceptionCallback (
326 EbcDebugProtocol,
327 0,
328 NULL,
329 Index
330 );
331 EbcDebugProtocol->RegisterExceptionCallback (
332 EbcDebugProtocol,
333 0,
334 EdbExceptionHandler,
335 Index
336 );
337 }
338
339 //
340 // Init Symbol
341 //
342 Object = AllocateZeroPool (sizeof(EFI_DEBUGGER_SYMBOL_OBJECT) * EFI_DEBUGGER_SYMBOL_OBJECT_MAX);
343 ASSERT (Object != NULL);
344 mDebuggerPrivate.DebuggerSymbolContext.Object = Object;
345 mDebuggerPrivate.DebuggerSymbolContext.ObjectCount = 0;
346 mDebuggerPrivate.DebuggerSymbolContext.MaxObjectCount = EFI_DEBUGGER_SYMBOL_OBJECT_MAX;
347 for (Index = 0; Index < EFI_DEBUGGER_SYMBOL_OBJECT_MAX; Index++) {
348 Entry = AllocateZeroPool (sizeof(EFI_DEBUGGER_SYMBOL_ENTRY) * EFI_DEBUGGER_SYMBOL_ENTRY_MAX);
349 ASSERT (Entry != NULL);
350 Object[Index].Entry = Entry;
351 Object[Index].MaxEntryCount = EFI_DEBUGGER_SYMBOL_ENTRY_MAX;
352 Object[Index].SourceBuffer = AllocateZeroPool (sizeof(VOID *) * (EFI_DEBUGGER_SYMBOL_ENTRY_MAX + 1));
353 ASSERT (Object[Index].SourceBuffer != NULL);
354 }
355
356 //
357 // locate PciRootBridgeIo
358 //
359 Status = gBS->LocateProtocol (
360 &gEfiPciRootBridgeIoProtocolGuid,
361 NULL,
362 (VOID**) &mDebuggerPrivate.PciRootBridgeIo
363 );
364
365 //
366 // locate DebugImageInfoTable
367 //
368 Status = EfiGetSystemConfigurationTable (
369 &gEfiDebugImageInfoTableGuid,
370 (VOID**) &mDebuggerPrivate.DebugImageInfoTableHeader
371 );
372
373 //
374 // Register Debugger Configuration Protocol, for config in shell
375 //
376 Status = gBS->InstallProtocolInterface (
377 &Handle,
378 &gEfiDebuggerConfigurationProtocolGuid,
379 EFI_NATIVE_INTERFACE,
380 &mDebuggerPrivate.DebuggerConfiguration
381 );
382
383 //
384 //
385 // Create break event
386 //
387 Status = gBS->CreateEvent (
388 EVT_TIMER | EVT_NOTIFY_SIGNAL,
389 TPL_CALLBACK,
390 EbcDebuggerBreakEventFunc,
391 NULL,
392 &mDebuggerPrivate.BreakEvent
393 );
394 if (!EFI_ERROR (Status)) {
395 Status = gBS->SetTimer (
396 mDebuggerPrivate.BreakEvent,
397 TimerPeriodic,
398 EFI_DEBUG_BREAK_TIMER_INTERVAL
399 );
400 }
401
402 return ;
403 }
404
405 /**
406
407 The hook in UnloadImage for EBC Interpreter.
408 It clean up the environment.
409
410 **/
411 VOID
412 EbcDebuggerHookUnload (
413 VOID
414 )
415 {
416 UINTN Index;
417 UINTN SubIndex;
418 EFI_DEBUGGER_SYMBOL_OBJECT *Object;
419
420 //
421 // Close the break event
422 //
423 if (mDebuggerPrivate.BreakEvent != NULL) {
424 gBS->CloseEvent (mDebuggerPrivate.BreakEvent);
425 }
426
427 //
428 // Clean up the symbol
429 //
430 Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
431 for (Index = 0; Index < EFI_DEBUGGER_SYMBOL_OBJECT_MAX; Index++) {
432 //
433 // Clean up Entry
434 //
435 gBS->FreePool (Object[Index].Entry);
436 Object[Index].Entry = NULL;
437 Object[Index].EntryCount = 0;
438 //
439 // Clean up source buffer
440 //
441 for (SubIndex = 0; Object[Index].SourceBuffer[SubIndex] != NULL; SubIndex++) {
442 gBS->FreePool (Object[Index].SourceBuffer[SubIndex]);
443 Object[Index].SourceBuffer[SubIndex] = NULL;
444 }
445 gBS->FreePool (Object[Index].SourceBuffer);
446 Object[Index].SourceBuffer = NULL;
447 }
448
449 //
450 // Clean up Object
451 //
452 gBS->FreePool (Object);
453 mDebuggerPrivate.DebuggerSymbolContext.Object = NULL;
454 mDebuggerPrivate.DebuggerSymbolContext.ObjectCount = 0;
455
456 //
457 // Done
458 //
459 return ;
460 }
461
462 /**
463
464 The hook in EbcUnloadImage.
465 Currently do nothing here.
466
467 @param Handle - The EbcImage handle.
468
469 **/
470
471 VOID
472 EbcDebuggerHookEbcUnloadImage (
473 IN EFI_HANDLE Handle
474 )
475 {
476 return ;
477 }
478
479 /**
480
481 The hook in ExecuteEbcImageEntryPoint.
482 It will record the call-stack entry. (-1 means EbcImageEntryPoint call)
483 and trigger Exception if BOE enabled.
484
485
486 @param VmPtr - pointer to VM context.
487
488 **/
489 VOID
490 EbcDebuggerHookExecuteEbcImageEntryPoint (
491 IN VM_CONTEXT *VmPtr
492 )
493 {
494 EbcDebuggerPushCallstackSource ((UINT64)(UINTN)-1, EfiDebuggerBranchTypeEbcCall);
495 EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
496 EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
497 EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOE);
498 return ;
499 }
500
501 /**
502
503 The hook in ExecuteEbcImageEntryPoint.
504 It will record the call-stack entry. (-2 means EbcInterpret call)
505 and trigger Exception if BOT enabled.
506
507 @param VmPtr - pointer to VM context.
508
509 **/
510 VOID
511 EbcDebuggerHookEbcInterpret (
512 IN VM_CONTEXT *VmPtr
513 )
514 {
515 EbcDebuggerPushCallstackSource ((UINT64)(UINTN)-2, EfiDebuggerBranchTypeEbcCall);
516 EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
517 EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
518 EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOT);
519 return ;
520 }
521
522 /**
523
524 The hook in EbcExecute, before ExecuteFunction.
525 It will trigger Exception if GoTil, StepOver, or StepOut hit.
526
527 @param VmPtr - pointer to VM context.
528
529 **/
530 VOID
531 EbcDebuggerHookExecuteStart (
532 IN VM_CONTEXT *VmPtr
533 )
534 {
535 EFI_TPL CurrentTpl;
536
537 //
538 // Check Ip for GoTil
539 //
540 if (mDebuggerPrivate.GoTilContext.BreakAddress == (UINT64)(UINTN)VmPtr->Ip) {
541 mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_GT;
542 mDebuggerPrivate.GoTilContext.BreakAddress = 0;
543 EbcDebugSignalException (
544 EXCEPT_EBC_BREAKPOINT,
545 EXCEPTION_FLAG_NONE,
546 VmPtr
547 );
548 mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_GT;
549 return ;
550 }
551 //
552 // Check ReturnAddress for StepOver
553 //
554 if ((mDebuggerPrivate.StepContext.BreakAddress == (UINT64)(UINTN)VmPtr->Ip) &&
555 (mDebuggerPrivate.StepContext.FramePointer == (UINT64)(UINTN)VmPtr->FramePtr)) {
556 mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_STEPOVER;
557 mDebuggerPrivate.StepContext.BreakAddress = 0;
558 mDebuggerPrivate.StepContext.FramePointer = 0;
559 EbcDebugSignalException (
560 EXCEPT_EBC_BREAKPOINT,
561 EXCEPTION_FLAG_NONE,
562 VmPtr
563 );
564 mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOVER;
565 }
566 //
567 // Check FramePtr for StepOut
568 //
569 if (mDebuggerPrivate.StepContext.BreakAddress == (UINT64)(UINTN)VmPtr->FramePtr) {
570 mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_STEPOUT;
571 mDebuggerPrivate.StepContext.BreakAddress = 0;
572 mDebuggerPrivate.StepContext.FramePointer = 0;
573 EbcDebugSignalException (
574 EXCEPT_EBC_BREAKPOINT,
575 EXCEPTION_FLAG_NONE,
576 VmPtr
577 );
578 mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOUT;
579 }
580 //
581 // Check Flags for BreakOnKey
582 //
583 if (mDebuggerPrivate.StatusFlags == EFI_DEBUG_FLAG_EBC_BOK) {
584 //
585 // Only break when the current TPL <= TPL_APPLICATION
586 //
587 CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
588 gBS->RestoreTPL (CurrentTpl);
589 if (CurrentTpl <= TPL_APPLICATION) {
590 EbcDebugSignalException (
591 EXCEPT_EBC_BREAKPOINT,
592 EXCEPTION_FLAG_NONE,
593 VmPtr
594 );
595 mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOK;
596 }
597 }
598 return ;
599 }
600
601 /**
602
603 The hook in EbcExecute, after ExecuteFunction.
604 It will record StepOut Entry if need.
605
606 @param VmPtr - pointer to VM context.
607
608 **/
609 VOID
610 EbcDebuggerHookExecuteEnd (
611 IN VM_CONTEXT *VmPtr
612 )
613 {
614 UINTN Address;
615
616 //
617 // Use FramePtr as checkpoint for StepOut
618 //
619 CopyMem (&Address, (VOID *)((UINTN)VmPtr->FramePtr), sizeof(Address));
620 EbcDebuggerPushStepEntry (Address, (UINT64)(UINTN)VmPtr->FramePtr, EFI_DEBUG_FLAG_EBC_STEPOUT);
621
622 return ;
623 }
624
625 /**
626
627 The hook in ExecuteCALL, before move IP.
628 It will trigger Exception if BOC enabled,
629 and record Callstack, and trace information.
630
631 @param VmPtr - pointer to VM context.
632
633 **/
634 VOID
635 EbcDebuggerHookCALLStart (
636 IN VM_CONTEXT *VmPtr
637 )
638 {
639 EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOC);
640 EbcDebuggerPushCallstackSource ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
641 EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
642 EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
643 return ;
644 }
645
646 /**
647
648 The hook in ExecuteCALL, after move IP.
649 It will record Callstack, trace information
650 and record StepOver/StepOut Entry if need.
651
652 @param VmPtr - pointer to VM context.
653
654 **/
655 VOID
656 EbcDebuggerHookCALLEnd (
657 IN VM_CONTEXT *VmPtr
658 )
659 {
660 UINT64 Address;
661 UINTN FramePtr;
662
663 EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
664 EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
665
666 //
667 // Get Old FramePtr
668 //
669 CopyMem (&FramePtr, (VOID *)((UINTN)VmPtr->FramePtr), sizeof(FramePtr));
670
671 //
672 // Use ReturnAddress as checkpoint for StepOver
673 //
674 CopyMem (&Address, (VOID *)(UINTN)VmPtr->Gpr[0], sizeof(Address));
675 EbcDebuggerPushStepEntry (Address, FramePtr, EFI_DEBUG_FLAG_EBC_STEPOVER);
676
677 //
678 // Use FramePtr as checkpoint for StepOut
679 //
680 Address = 0;
681 CopyMem (&Address, (VOID *)(FramePtr), sizeof(UINTN));
682 EbcDebuggerPushStepEntry (Address, FramePtr, EFI_DEBUG_FLAG_EBC_STEPOUT);
683
684 return ;
685 }
686
687 /**
688
689 The hook in ExecuteCALL, before call EbcLLCALLEX.
690 It will trigger Exception if BOCX enabled,
691 and record Callstack information.
692
693 @param VmPtr - pointer to VM context.
694
695 **/
696 VOID
697 EbcDebuggerHookCALLEXStart (
698 IN VM_CONTEXT *VmPtr
699 )
700 {
701 EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOCX);
702 // EbcDebuggerPushCallstackSource ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
703 // EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->R[0], EfiDebuggerBranchTypeEbcCallEx);
704 EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
705 return ;
706 }
707
708 /**
709
710 The hook in ExecuteCALL, after call EbcLLCALLEX.
711 It will record trace information.
712
713 @param VmPtr - pointer to VM context.
714
715 **/
716 VOID
717 EbcDebuggerHookCALLEXEnd (
718 IN VM_CONTEXT *VmPtr
719 )
720 {
721 // EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
722 EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
723 return ;
724 }
725
726 /**
727
728 The hook in ExecuteRET, before move IP.
729 It will trigger Exception if BOR enabled,
730 and record Callstack, and trace information.
731
732 @param VmPtr - pointer to VM context.
733
734 **/
735 VOID
736 EbcDebuggerHookRETStart (
737 IN VM_CONTEXT *VmPtr
738 )
739 {
740 EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOR);
741 EbcDebuggerPopCallstack ();
742 EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcRet);
743 return ;
744 }
745
746 /**
747
748 The hook in ExecuteRET, after move IP.
749 It will record trace information.
750
751 @param VmPtr - pointer to VM context.
752
753 **/
754 VOID
755 EbcDebuggerHookRETEnd (
756 IN VM_CONTEXT *VmPtr
757 )
758 {
759 EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcRet);
760 return ;
761 }
762
763 /**
764
765 The hook in ExecuteJMP, before move IP.
766 It will record trace information.
767
768 @param VmPtr - pointer to VM context.
769
770 **/
771 VOID
772 EbcDebuggerHookJMPStart (
773 IN VM_CONTEXT *VmPtr
774 )
775 {
776 EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp);
777 return ;
778 }
779
780 /**
781
782 The hook in ExecuteJMP, after move IP.
783 It will record trace information.
784
785 @param VmPtr - pointer to VM context.
786
787 **/
788 VOID
789 EbcDebuggerHookJMPEnd (
790 IN VM_CONTEXT *VmPtr
791 )
792 {
793 EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp);
794 return ;
795 }
796
797 /**
798
799 The hook in ExecuteJMP8, before move IP.
800 It will record trace information.
801
802 @param VmPtr - pointer to VM context.
803
804 **/
805 VOID
806 EbcDebuggerHookJMP8Start (
807 IN VM_CONTEXT *VmPtr
808 )
809 {
810 EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp8);
811 return ;
812 }
813
814 /**
815
816 The hook in ExecuteJMP8, after move IP.
817 It will record trace information.
818
819 @param VmPtr - pointer to VM context.
820
821 **/
822 VOID
823 EbcDebuggerHookJMP8End (
824 IN VM_CONTEXT *VmPtr
825 )
826 {
827 EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp8);
828 return ;
829 }