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; 491 492 mInitialized = FALSE; 493 494 DEBUG ((DEBUG_ERROR, "Hello EBC Debugger!\n")); 495 496 if (!mInitialized) { 497 // 498 // Print version 499 // 500 EDBPrint ( 501 L"EBC Interpreter Version - %d.%d\n", 502 (UINTN)VM_MAJOR_VERSION, 503 (UINTN)VM_MINOR_VERSION 504 ); 505 EDBPrint ( 506 L"EBC Debugger Version - %d.%d\n", 507 (UINTN)EBC_DEBUGGER_MAJOR_VERSION, 508 (UINTN)EBC_DEBUGGER_MINOR_VERSION 509 ); 510 } 511 // 512 // Init Private Data 513 // 514 InitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized); 515 516 // 517 // EDBPrint basic info 518 // 519 PrintExceptionReason (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized); 520 521 EdbShowDisasm (&mDebuggerPrivate, SystemContext); 522 // EFI_BREAKPOINT (); 523 524 if (!mInitialized) { 525 // 526 // Interactive with user 527 // 528 EDBPrint (L"\nPlease enter command now, \'h\' for help.\n"); 529 EDBPrint (L"(Using <Command> -b <...> to enable page break.)\n"); 530 } 531 mInitialized = TRUE; 532 533 // 534 // Dispatch each command 535 // 536 while (TRUE) { 537 // 538 // Get user input 539 // 540 Input (L"\n\r" EFI_DEBUG_PROMPT_STRING, InputBuffer, EFI_DEBUG_INPUS_BUFFER_SIZE); 541 EDBPrint (L"\n"); 542 543 // 544 // Get command 545 // 546 DebuggerCommand = MatchDebuggerCommand (InputBuffer, &CommandArg); 547 if (DebuggerCommand == NULL) { 548 EDBPrint (L"ERROR: Command not found!\n"); 549 continue; 550 } 551 552 // 553 // Check PageBreak; 554 // 555 if (CommandArg != NULL) { 556 if (StriCmp (CommandArg, L"-b") == 0) { 557 CommandArg = StrGetNextTokenLine (L" "); 558 mDebuggerPrivate.EnablePageBreak = TRUE; 559 } 560 } 561 562 // 563 // Dispatch command 564 // 565 DebugStatus = DebuggerCommand (CommandArg, &mDebuggerPrivate, ExceptionType, SystemContext); 566 mDebuggerPrivate.EnablePageBreak = FALSE; 567 568 // 569 // Check command return status 570 // 571 if (DebugStatus == EFI_DEBUG_RETURN) { 572 mInitialized = FALSE; 573 break; 574 } else if (DebugStatus == EFI_DEBUG_BREAK) { 575 break; 576 } else if (DebugStatus == EFI_DEBUG_CONTINUE) { 577 continue; 578 } else { 579 ASSERT (FALSE); 580 } 581 } 582 583 // 584 // Deinit Private Data 585 // 586 DeinitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized); 587 588 DEBUG ((DEBUG_ERROR, "Goodbye EBC Debugger!\n")); 589 590 return; 591 } 592