1 /******************************************************************************* 2 * 3 * Module Name: dbxface - AML Debugger external interfaces 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2018, 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 #include <acpi/acpi.h> 45 #include "accommon.h" 46 #include "amlcode.h" 47 #include "acdebug.h" 48 #include "acinterp.h" 49 50 #define _COMPONENT ACPI_CA_DEBUGGER 51 ACPI_MODULE_NAME("dbxface") 52 53 /* Local prototypes */ 54 static acpi_status 55 acpi_db_start_command(struct acpi_walk_state *walk_state, 56 union acpi_parse_object *op); 57 58 #ifdef ACPI_OBSOLETE_FUNCTIONS 59 void acpi_db_method_end(struct acpi_walk_state *walk_state); 60 #endif 61 62 /******************************************************************************* 63 * 64 * FUNCTION: acpi_db_start_command 65 * 66 * PARAMETERS: walk_state - Current walk 67 * op - Current executing Op, from AML interpreter 68 * 69 * RETURN: Status 70 * 71 * DESCRIPTION: Enter debugger command loop 72 * 73 ******************************************************************************/ 74 75 static acpi_status 76 acpi_db_start_command(struct acpi_walk_state *walk_state, 77 union acpi_parse_object *op) 78 { 79 acpi_status status; 80 81 /* TBD: [Investigate] are there namespace locking issues here? */ 82 83 /* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */ 84 85 /* Go into the command loop and await next user command */ 86 87 acpi_gbl_method_executing = TRUE; 88 status = AE_CTRL_TRUE; 89 90 while (status == AE_CTRL_TRUE) { 91 92 /* Notify the completion of the command */ 93 94 status = acpi_os_notify_command_complete(); 95 if (ACPI_FAILURE(status)) { 96 goto error_exit; 97 } 98 99 /* Wait the readiness of the command */ 100 101 status = acpi_os_wait_command_ready(); 102 if (ACPI_FAILURE(status)) { 103 goto error_exit; 104 } 105 106 status = 107 acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state, 108 op); 109 } 110 111 /* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */ 112 113 error_exit: 114 if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) { 115 ACPI_EXCEPTION((AE_INFO, status, 116 "While parsing/handling command line")); 117 } 118 return (status); 119 } 120 121 /******************************************************************************* 122 * 123 * FUNCTION: acpi_db_signal_break_point 124 * 125 * PARAMETERS: walk_state - Current walk 126 * 127 * RETURN: Status 128 * 129 * DESCRIPTION: Called for AML_BREAKPOINT_OP 130 * 131 ******************************************************************************/ 132 133 void acpi_db_signal_break_point(struct acpi_walk_state *walk_state) 134 { 135 136 #ifndef ACPI_APPLICATION 137 if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) { 138 return; 139 } 140 #endif 141 142 /* 143 * Set the single-step flag. This will cause the debugger (if present) 144 * to break to the console within the AML debugger at the start of the 145 * next AML instruction. 146 */ 147 acpi_gbl_cm_single_step = TRUE; 148 acpi_os_printf("**break** Executed AML BreakPoint opcode\n"); 149 } 150 151 /******************************************************************************* 152 * 153 * FUNCTION: acpi_db_single_step 154 * 155 * PARAMETERS: walk_state - Current walk 156 * op - Current executing op (from aml interpreter) 157 * opcode_class - Class of the current AML Opcode 158 * 159 * RETURN: Status 160 * 161 * DESCRIPTION: Called just before execution of an AML opcode. 162 * 163 ******************************************************************************/ 164 165 acpi_status 166 acpi_db_single_step(struct acpi_walk_state *walk_state, 167 union acpi_parse_object *op, u32 opcode_class) 168 { 169 union acpi_parse_object *next; 170 acpi_status status = AE_OK; 171 u32 original_debug_level; 172 union acpi_parse_object *display_op; 173 union acpi_parse_object *parent_op; 174 u32 aml_offset; 175 176 ACPI_FUNCTION_ENTRY(); 177 178 #ifndef ACPI_APPLICATION 179 if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) { 180 return (AE_OK); 181 } 182 #endif 183 184 /* Check the abort flag */ 185 186 if (acpi_gbl_abort_method) { 187 acpi_gbl_abort_method = FALSE; 188 return (AE_ABORT_METHOD); 189 } 190 191 aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml, 192 walk_state->parser_state.aml_start); 193 194 /* Check for single-step breakpoint */ 195 196 if (walk_state->method_breakpoint && 197 (walk_state->method_breakpoint <= aml_offset)) { 198 199 /* Check if the breakpoint has been reached or passed */ 200 /* Hit the breakpoint, resume single step, reset breakpoint */ 201 202 acpi_os_printf("***Break*** at AML offset %X\n", aml_offset); 203 acpi_gbl_cm_single_step = TRUE; 204 acpi_gbl_step_to_next_call = FALSE; 205 walk_state->method_breakpoint = 0; 206 } 207 208 /* Check for user breakpoint (Must be on exact Aml offset) */ 209 210 else if (walk_state->user_breakpoint && 211 (walk_state->user_breakpoint == aml_offset)) { 212 acpi_os_printf("***UserBreakpoint*** at AML offset %X\n", 213 aml_offset); 214 acpi_gbl_cm_single_step = TRUE; 215 acpi_gbl_step_to_next_call = FALSE; 216 walk_state->method_breakpoint = 0; 217 } 218 219 /* 220 * Check if this is an opcode that we are interested in -- 221 * namely, opcodes that have arguments 222 */ 223 if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { 224 return (AE_OK); 225 } 226 227 switch (opcode_class) { 228 case AML_CLASS_UNKNOWN: 229 case AML_CLASS_ARGUMENT: /* constants, literals, etc. do nothing */ 230 231 return (AE_OK); 232 233 default: 234 235 /* All other opcodes -- continue */ 236 break; 237 } 238 239 /* 240 * Under certain debug conditions, display this opcode and its operands 241 */ 242 if ((acpi_gbl_db_output_to_file) || 243 (acpi_gbl_cm_single_step) || (acpi_dbg_level & ACPI_LV_PARSE)) { 244 if ((acpi_gbl_db_output_to_file) || 245 (acpi_dbg_level & ACPI_LV_PARSE)) { 246 acpi_os_printf 247 ("\nAML Debug: Next AML Opcode to execute:\n"); 248 } 249 250 /* 251 * Display this op (and only this op - zero out the NEXT field 252 * temporarily, and disable parser trace output for the duration of 253 * the display because we don't want the extraneous debug output) 254 */ 255 original_debug_level = acpi_dbg_level; 256 acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS); 257 next = op->common.next; 258 op->common.next = NULL; 259 260 display_op = op; 261 parent_op = op->common.parent; 262 if (parent_op) { 263 if ((walk_state->control_state) && 264 (walk_state->control_state->common.state == 265 ACPI_CONTROL_PREDICATE_EXECUTING)) { 266 /* 267 * We are executing the predicate of an IF or WHILE statement 268 * Search upwards for the containing IF or WHILE so that the 269 * entire predicate can be displayed. 270 */ 271 while (parent_op) { 272 if ((parent_op->common.aml_opcode == 273 AML_IF_OP) 274 || (parent_op->common.aml_opcode == 275 AML_WHILE_OP)) { 276 display_op = parent_op; 277 break; 278 } 279 parent_op = parent_op->common.parent; 280 } 281 } else { 282 while (parent_op) { 283 if ((parent_op->common.aml_opcode == 284 AML_IF_OP) 285 || (parent_op->common.aml_opcode == 286 AML_ELSE_OP) 287 || (parent_op->common.aml_opcode == 288 AML_SCOPE_OP) 289 || (parent_op->common.aml_opcode == 290 AML_METHOD_OP) 291 || (parent_op->common.aml_opcode == 292 AML_WHILE_OP)) { 293 break; 294 } 295 display_op = parent_op; 296 parent_op = parent_op->common.parent; 297 } 298 } 299 } 300 301 /* Now we can display it */ 302 303 #ifdef ACPI_DISASSEMBLER 304 acpi_dm_disassemble(walk_state, display_op, ACPI_UINT32_MAX); 305 #endif 306 307 if ((op->common.aml_opcode == AML_IF_OP) || 308 (op->common.aml_opcode == AML_WHILE_OP)) { 309 if (walk_state->control_state->common.value) { 310 acpi_os_printf 311 ("Predicate = [True], IF block was executed\n"); 312 } else { 313 acpi_os_printf 314 ("Predicate = [False], Skipping IF block\n"); 315 } 316 } else if (op->common.aml_opcode == AML_ELSE_OP) { 317 acpi_os_printf 318 ("Predicate = [False], ELSE block was executed\n"); 319 } 320 321 /* Restore everything */ 322 323 op->common.next = next; 324 acpi_os_printf("\n"); 325 if ((acpi_gbl_db_output_to_file) || 326 (acpi_dbg_level & ACPI_LV_PARSE)) { 327 acpi_os_printf("\n"); 328 } 329 acpi_dbg_level = original_debug_level; 330 } 331 332 /* If we are not single stepping, just continue executing the method */ 333 334 if (!acpi_gbl_cm_single_step) { 335 return (AE_OK); 336 } 337 338 /* 339 * If we are executing a step-to-call command, 340 * Check if this is a method call. 341 */ 342 if (acpi_gbl_step_to_next_call) { 343 if (op->common.aml_opcode != AML_INT_METHODCALL_OP) { 344 345 /* Not a method call, just keep executing */ 346 347 return (AE_OK); 348 } 349 350 /* Found a method call, stop executing */ 351 352 acpi_gbl_step_to_next_call = FALSE; 353 } 354 355 /* 356 * If the next opcode is a method call, we will "step over" it 357 * by default. 358 */ 359 if (op->common.aml_opcode == AML_INT_METHODCALL_OP) { 360 361 /* Force no more single stepping while executing called method */ 362 363 acpi_gbl_cm_single_step = FALSE; 364 365 /* 366 * Set the breakpoint on/before the call, it will stop execution 367 * as soon as we return 368 */ 369 walk_state->method_breakpoint = 1; /* Must be non-zero! */ 370 } 371 372 acpi_ex_exit_interpreter(); 373 status = acpi_db_start_command(walk_state, op); 374 acpi_ex_enter_interpreter(); 375 376 /* User commands complete, continue execution of the interrupted method */ 377 378 return (status); 379 } 380 381 /******************************************************************************* 382 * 383 * FUNCTION: acpi_initialize_debugger 384 * 385 * PARAMETERS: None 386 * 387 * RETURN: Status 388 * 389 * DESCRIPTION: Init and start debugger 390 * 391 ******************************************************************************/ 392 393 acpi_status acpi_initialize_debugger(void) 394 { 395 acpi_status status; 396 397 ACPI_FUNCTION_TRACE(acpi_initialize_debugger); 398 399 /* Init globals */ 400 401 acpi_gbl_db_buffer = NULL; 402 acpi_gbl_db_filename = NULL; 403 acpi_gbl_db_output_to_file = FALSE; 404 405 acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2; 406 acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES; 407 acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT; 408 409 acpi_gbl_db_opt_no_ini_methods = FALSE; 410 411 acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE); 412 if (!acpi_gbl_db_buffer) { 413 return_ACPI_STATUS(AE_NO_MEMORY); 414 } 415 memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE); 416 417 /* Initial scope is the root */ 418 419 acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX; 420 acpi_gbl_db_scope_buf[1] = 0; 421 acpi_gbl_db_scope_node = acpi_gbl_root_node; 422 423 /* Initialize user commands loop */ 424 425 acpi_gbl_db_terminate_loop = FALSE; 426 427 /* 428 * If configured for multi-thread support, the debug executor runs in 429 * a separate thread so that the front end can be in another address 430 * space, environment, or even another machine. 431 */ 432 if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { 433 434 /* These were created with one unit, grab it */ 435 436 status = acpi_os_initialize_debugger(); 437 if (ACPI_FAILURE(status)) { 438 acpi_os_printf("Could not get debugger mutex\n"); 439 return_ACPI_STATUS(status); 440 } 441 442 /* Create the debug execution thread to execute commands */ 443 444 acpi_gbl_db_threads_terminated = FALSE; 445 status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD, 446 acpi_db_execute_thread, NULL); 447 if (ACPI_FAILURE(status)) { 448 ACPI_EXCEPTION((AE_INFO, status, 449 "Could not start debugger thread")); 450 acpi_gbl_db_threads_terminated = TRUE; 451 return_ACPI_STATUS(status); 452 } 453 } else { 454 acpi_gbl_db_thread_id = acpi_os_get_thread_id(); 455 } 456 457 return_ACPI_STATUS(AE_OK); 458 } 459 460 ACPI_EXPORT_SYMBOL(acpi_initialize_debugger) 461 462 /******************************************************************************* 463 * 464 * FUNCTION: acpi_terminate_debugger 465 * 466 * PARAMETERS: None 467 * 468 * RETURN: None 469 * 470 * DESCRIPTION: Stop debugger 471 * 472 ******************************************************************************/ 473 void acpi_terminate_debugger(void) 474 { 475 476 /* Terminate the AML Debugger */ 477 478 acpi_gbl_db_terminate_loop = TRUE; 479 480 if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { 481 482 /* Wait the AML Debugger threads */ 483 484 while (!acpi_gbl_db_threads_terminated) { 485 acpi_os_sleep(100); 486 } 487 488 acpi_os_terminate_debugger(); 489 } 490 491 if (acpi_gbl_db_buffer) { 492 acpi_os_free(acpi_gbl_db_buffer); 493 acpi_gbl_db_buffer = NULL; 494 } 495 496 /* Ensure that debug output is now disabled */ 497 498 acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT; 499 } 500 501 ACPI_EXPORT_SYMBOL(acpi_terminate_debugger) 502 503 /******************************************************************************* 504 * 505 * FUNCTION: acpi_set_debugger_thread_id 506 * 507 * PARAMETERS: thread_id - Debugger thread ID 508 * 509 * RETURN: None 510 * 511 * DESCRIPTION: Set debugger thread ID 512 * 513 ******************************************************************************/ 514 void acpi_set_debugger_thread_id(acpi_thread_id thread_id) 515 { 516 acpi_gbl_db_thread_id = thread_id; 517 } 518 519 ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id) 520