root/drivers/acpi/acpica/dbxface.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ACPI_MODULE_NAME
  2. acpi_db_signal_break_point
  3. acpi_db_get_display_op
  4. acpi_db_single_step
  5. acpi_initialize_debugger
  6. ACPI_EXPORT_SYMBOL
  7. ACPI_EXPORT_SYMBOL

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

/* [<][>][^][v][top][bottom][index][help] */