1 /******************************************************************************* 2 * 3 * Module Name: dbxface - AML Debugger external interfaces 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2013, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 45 #include <contrib/dev/acpica/include/acpi.h> 46 #include <contrib/dev/acpica/include/accommon.h> 47 #include <contrib/dev/acpica/include/amlcode.h> 48 #include <contrib/dev/acpica/include/acdebug.h> 49 #include <contrib/dev/acpica/include/acdisasm.h> 50 51 52 #ifdef ACPI_DEBUGGER 53 54 #define _COMPONENT ACPI_CA_DEBUGGER 55 ACPI_MODULE_NAME ("dbxface") 56 57 58 /* Local prototypes */ 59 60 static ACPI_STATUS 61 AcpiDbStartCommand ( 62 ACPI_WALK_STATE *WalkState, 63 ACPI_PARSE_OBJECT *Op); 64 65 #ifdef ACPI_OBSOLETE_FUNCTIONS 66 void 67 AcpiDbMethodEnd ( 68 ACPI_WALK_STATE *WalkState); 69 #endif 70 71 72 /******************************************************************************* 73 * 74 * FUNCTION: AcpiDbStartCommand 75 * 76 * PARAMETERS: WalkState - Current walk 77 * Op - Current executing Op, from AML interpreter 78 * 79 * RETURN: Status 80 * 81 * DESCRIPTION: Enter debugger command loop 82 * 83 ******************************************************************************/ 84 85 static ACPI_STATUS 86 AcpiDbStartCommand ( 87 ACPI_WALK_STATE *WalkState, 88 ACPI_PARSE_OBJECT *Op) 89 { 90 ACPI_STATUS Status; 91 92 93 /* TBD: [Investigate] are there namespace locking issues here? */ 94 95 /* AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); */ 96 97 /* Go into the command loop and await next user command */ 98 99 100 AcpiGbl_MethodExecuting = TRUE; 101 Status = AE_CTRL_TRUE; 102 while (Status == AE_CTRL_TRUE) 103 { 104 if (AcpiGbl_DebuggerConfiguration == DEBUGGER_MULTI_THREADED) 105 { 106 /* Handshake with the front-end that gets user command lines */ 107 108 Status = AcpiUtReleaseMutex (ACPI_MTX_DEBUG_CMD_COMPLETE); 109 if (ACPI_FAILURE (Status)) 110 { 111 return (Status); 112 } 113 Status = AcpiUtAcquireMutex (ACPI_MTX_DEBUG_CMD_READY); 114 if (ACPI_FAILURE (Status)) 115 { 116 return (Status); 117 } 118 } 119 else 120 { 121 /* Single threaded, we must get a command line ourselves */ 122 123 /* Force output to console until a command is entered */ 124 125 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); 126 127 /* Different prompt if method is executing */ 128 129 if (!AcpiGbl_MethodExecuting) 130 { 131 AcpiOsPrintf ("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); 132 } 133 else 134 { 135 AcpiOsPrintf ("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); 136 } 137 138 /* Get the user input line */ 139 140 Status = AcpiOsGetLine (AcpiGbl_DbLineBuf, 141 ACPI_DB_LINE_BUFFER_SIZE, NULL); 142 if (ACPI_FAILURE (Status)) 143 { 144 ACPI_EXCEPTION ((AE_INFO, Status, "While parsing command line")); 145 return (Status); 146 } 147 } 148 149 Status = AcpiDbCommandDispatch (AcpiGbl_DbLineBuf, WalkState, Op); 150 } 151 152 /* AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); */ 153 154 return (Status); 155 } 156 157 158 /******************************************************************************* 159 * 160 * FUNCTION: AcpiDbSingleStep 161 * 162 * PARAMETERS: WalkState - Current walk 163 * Op - Current executing op (from aml interpreter) 164 * OpcodeClass - Class of the current AML Opcode 165 * 166 * RETURN: Status 167 * 168 * DESCRIPTION: Called just before execution of an AML opcode. 169 * 170 ******************************************************************************/ 171 172 ACPI_STATUS 173 AcpiDbSingleStep ( 174 ACPI_WALK_STATE *WalkState, 175 ACPI_PARSE_OBJECT *Op, 176 UINT32 OpcodeClass) 177 { 178 ACPI_PARSE_OBJECT *Next; 179 ACPI_STATUS Status = AE_OK; 180 UINT32 OriginalDebugLevel; 181 ACPI_PARSE_OBJECT *DisplayOp; 182 ACPI_PARSE_OBJECT *ParentOp; 183 184 185 ACPI_FUNCTION_ENTRY (); 186 187 188 /* Check the abort flag */ 189 190 if (AcpiGbl_AbortMethod) 191 { 192 AcpiGbl_AbortMethod = FALSE; 193 return (AE_ABORT_METHOD); 194 } 195 196 /* Check for single-step breakpoint */ 197 198 if (WalkState->MethodBreakpoint && 199 (WalkState->MethodBreakpoint <= Op->Common.AmlOffset)) 200 { 201 /* Check if the breakpoint has been reached or passed */ 202 /* Hit the breakpoint, resume single step, reset breakpoint */ 203 204 AcpiOsPrintf ("***Break*** at AML offset %X\n", Op->Common.AmlOffset); 205 AcpiGbl_CmSingleStep = TRUE; 206 AcpiGbl_StepToNextCall = FALSE; 207 WalkState->MethodBreakpoint = 0; 208 } 209 210 /* Check for user breakpoint (Must be on exact Aml offset) */ 211 212 else if (WalkState->UserBreakpoint && 213 (WalkState->UserBreakpoint == Op->Common.AmlOffset)) 214 { 215 AcpiOsPrintf ("***UserBreakpoint*** at AML offset %X\n", 216 Op->Common.AmlOffset); 217 AcpiGbl_CmSingleStep = TRUE; 218 AcpiGbl_StepToNextCall = FALSE; 219 WalkState->MethodBreakpoint = 0; 220 } 221 222 /* 223 * Check if this is an opcode that we are interested in -- 224 * namely, opcodes that have arguments 225 */ 226 if (Op->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP) 227 { 228 return (AE_OK); 229 } 230 231 switch (OpcodeClass) 232 { 233 case AML_CLASS_UNKNOWN: 234 case AML_CLASS_ARGUMENT: /* constants, literals, etc. do nothing */ 235 236 return (AE_OK); 237 238 default: 239 240 /* All other opcodes -- continue */ 241 break; 242 } 243 244 /* 245 * Under certain debug conditions, display this opcode and its operands 246 */ 247 if ((AcpiGbl_DbOutputToFile) || 248 (AcpiGbl_CmSingleStep) || 249 (AcpiDbgLevel & ACPI_LV_PARSE)) 250 { 251 if ((AcpiGbl_DbOutputToFile) || 252 (AcpiDbgLevel & ACPI_LV_PARSE)) 253 { 254 AcpiOsPrintf ("\n[AmlDebug] Next AML Opcode to execute:\n"); 255 } 256 257 /* 258 * Display this op (and only this op - zero out the NEXT field 259 * temporarily, and disable parser trace output for the duration of 260 * the display because we don't want the extraneous debug output) 261 */ 262 OriginalDebugLevel = AcpiDbgLevel; 263 AcpiDbgLevel &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS); 264 Next = Op->Common.Next; 265 Op->Common.Next = NULL; 266 267 268 DisplayOp = Op; 269 ParentOp = Op->Common.Parent; 270 if (ParentOp) 271 { 272 if ((WalkState->ControlState) && 273 (WalkState->ControlState->Common.State == 274 ACPI_CONTROL_PREDICATE_EXECUTING)) 275 { 276 /* 277 * We are executing the predicate of an IF or WHILE statement 278 * Search upwards for the containing IF or WHILE so that the 279 * entire predicate can be displayed. 280 */ 281 while (ParentOp) 282 { 283 if ((ParentOp->Common.AmlOpcode == AML_IF_OP) || 284 (ParentOp->Common.AmlOpcode == AML_WHILE_OP)) 285 { 286 DisplayOp = ParentOp; 287 break; 288 } 289 ParentOp = ParentOp->Common.Parent; 290 } 291 } 292 else 293 { 294 while (ParentOp) 295 { 296 if ((ParentOp->Common.AmlOpcode == AML_IF_OP) || 297 (ParentOp->Common.AmlOpcode == AML_ELSE_OP) || 298 (ParentOp->Common.AmlOpcode == AML_SCOPE_OP) || 299 (ParentOp->Common.AmlOpcode == AML_METHOD_OP) || 300 (ParentOp->Common.AmlOpcode == AML_WHILE_OP)) 301 { 302 break; 303 } 304 DisplayOp = ParentOp; 305 ParentOp = ParentOp->Common.Parent; 306 } 307 } 308 } 309 310 /* Now we can display it */ 311 312 #ifdef ACPI_DISASSEMBLER 313 AcpiDmDisassemble (WalkState, DisplayOp, ACPI_UINT32_MAX); 314 #endif 315 316 if ((Op->Common.AmlOpcode == AML_IF_OP) || 317 (Op->Common.AmlOpcode == AML_WHILE_OP)) 318 { 319 if (WalkState->ControlState->Common.Value) 320 { 321 AcpiOsPrintf ("Predicate = [True], IF block was executed\n"); 322 } 323 else 324 { 325 AcpiOsPrintf ("Predicate = [False], Skipping IF block\n"); 326 } 327 } 328 else if (Op->Common.AmlOpcode == AML_ELSE_OP) 329 { 330 AcpiOsPrintf ("Predicate = [False], ELSE block was executed\n"); 331 } 332 333 /* Restore everything */ 334 335 Op->Common.Next = Next; 336 AcpiOsPrintf ("\n"); 337 if ((AcpiGbl_DbOutputToFile) || 338 (AcpiDbgLevel & ACPI_LV_PARSE)) 339 { 340 AcpiOsPrintf ("\n"); 341 } 342 AcpiDbgLevel = OriginalDebugLevel; 343 } 344 345 /* If we are not single stepping, just continue executing the method */ 346 347 if (!AcpiGbl_CmSingleStep) 348 { 349 return (AE_OK); 350 } 351 352 /* 353 * If we are executing a step-to-call command, 354 * Check if this is a method call. 355 */ 356 if (AcpiGbl_StepToNextCall) 357 { 358 if (Op->Common.AmlOpcode != AML_INT_METHODCALL_OP) 359 { 360 /* Not a method call, just keep executing */ 361 362 return (AE_OK); 363 } 364 365 /* Found a method call, stop executing */ 366 367 AcpiGbl_StepToNextCall = FALSE; 368 } 369 370 /* 371 * If the next opcode is a method call, we will "step over" it 372 * by default. 373 */ 374 if (Op->Common.AmlOpcode == AML_INT_METHODCALL_OP) 375 { 376 /* Force no more single stepping while executing called method */ 377 378 AcpiGbl_CmSingleStep = FALSE; 379 380 /* 381 * Set the breakpoint on/before the call, it will stop execution 382 * as soon as we return 383 */ 384 WalkState->MethodBreakpoint = 1; /* Must be non-zero! */ 385 } 386 387 388 Status = AcpiDbStartCommand (WalkState, Op); 389 390 /* User commands complete, continue execution of the interrupted method */ 391 392 return (Status); 393 } 394 395 396 /******************************************************************************* 397 * 398 * FUNCTION: AcpiDbInitialize 399 * 400 * PARAMETERS: None 401 * 402 * RETURN: Status 403 * 404 * DESCRIPTION: Init and start debugger 405 * 406 ******************************************************************************/ 407 408 ACPI_STATUS 409 AcpiDbInitialize ( 410 void) 411 { 412 ACPI_STATUS Status; 413 414 415 ACPI_FUNCTION_TRACE (DbInitialize); 416 417 418 /* Init globals */ 419 420 AcpiGbl_DbBuffer = NULL; 421 AcpiGbl_DbFilename = NULL; 422 AcpiGbl_DbOutputToFile = FALSE; 423 424 AcpiGbl_DbDebugLevel = ACPI_LV_VERBOSITY2; 425 AcpiGbl_DbConsoleDebugLevel = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES; 426 AcpiGbl_DbOutputFlags = ACPI_DB_CONSOLE_OUTPUT; 427 428 AcpiGbl_DbOpt_tables = FALSE; 429 AcpiGbl_DbOpt_disasm = FALSE; 430 AcpiGbl_DbOpt_stats = FALSE; 431 #ifdef ACPI_DISASSEMBLER 432 AcpiGbl_DbOpt_verbose = TRUE; 433 #endif 434 AcpiGbl_DbOpt_ini_methods = TRUE; 435 436 AcpiGbl_DbBuffer = AcpiOsAllocate (ACPI_DEBUG_BUFFER_SIZE); 437 if (!AcpiGbl_DbBuffer) 438 { 439 return_ACPI_STATUS (AE_NO_MEMORY); 440 } 441 ACPI_MEMSET (AcpiGbl_DbBuffer, 0, ACPI_DEBUG_BUFFER_SIZE); 442 443 /* Initial scope is the root */ 444 445 AcpiGbl_DbScopeBuf [0] = AML_ROOT_PREFIX; 446 AcpiGbl_DbScopeBuf [1] = 0; 447 AcpiGbl_DbScopeNode = AcpiGbl_RootNode; 448 449 /* 450 * If configured for multi-thread support, the debug executor runs in 451 * a separate thread so that the front end can be in another address 452 * space, environment, or even another machine. 453 */ 454 if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED) 455 { 456 /* These were created with one unit, grab it */ 457 458 Status = AcpiUtAcquireMutex (ACPI_MTX_DEBUG_CMD_COMPLETE); 459 if (ACPI_FAILURE (Status)) 460 { 461 AcpiOsPrintf ("Could not get debugger mutex\n"); 462 return_ACPI_STATUS (Status); 463 } 464 465 Status = AcpiUtAcquireMutex (ACPI_MTX_DEBUG_CMD_READY); 466 if (ACPI_FAILURE (Status)) 467 { 468 AcpiOsPrintf ("Could not get debugger mutex\n"); 469 return_ACPI_STATUS (Status); 470 } 471 472 /* Create the debug execution thread to execute commands */ 473 474 Status = AcpiOsExecute (OSL_DEBUGGER_THREAD, AcpiDbExecuteThread, NULL); 475 if (ACPI_FAILURE (Status)) 476 { 477 ACPI_EXCEPTION ((AE_INFO, Status, "Could not start debugger thread")); 478 return_ACPI_STATUS (Status); 479 } 480 } 481 482 #ifdef ACPI_DISASSEMBLER 483 if (!AcpiGbl_DbOpt_verbose) 484 { 485 AcpiGbl_DbOpt_disasm = TRUE; 486 AcpiGbl_DbOpt_stats = FALSE; 487 } 488 #endif 489 490 return_ACPI_STATUS (AE_OK); 491 } 492 493 494 /******************************************************************************* 495 * 496 * FUNCTION: AcpiDbTerminate 497 * 498 * PARAMETERS: None 499 * 500 * RETURN: None 501 * 502 * DESCRIPTION: Stop debugger 503 * 504 ******************************************************************************/ 505 506 void 507 AcpiDbTerminate ( 508 void) 509 { 510 511 if (AcpiGbl_DbBuffer) 512 { 513 AcpiOsFree (AcpiGbl_DbBuffer); 514 AcpiGbl_DbBuffer = NULL; 515 } 516 } 517 518 519 #ifdef ACPI_OBSOLETE_FUNCTIONS 520 /******************************************************************************* 521 * 522 * FUNCTION: AcpiDbMethodEnd 523 * 524 * PARAMETERS: WalkState - Current walk 525 * 526 * RETURN: Status 527 * 528 * DESCRIPTION: Called at method termination 529 * 530 ******************************************************************************/ 531 532 void 533 AcpiDbMethodEnd ( 534 ACPI_WALK_STATE *WalkState) 535 { 536 537 if (!AcpiGbl_CmSingleStep) 538 { 539 return; 540 } 541 542 AcpiOsPrintf ("<Method Terminating>\n"); 543 544 AcpiDbStartCommand (WalkState, NULL); 545 } 546 #endif 547 548 #endif /* ACPI_DEBUGGER */ 549