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