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