Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /*******************************************************************************
0003  *
0004  * Module Name: dbxface - AML Debugger external interfaces
0005  *
0006  ******************************************************************************/
0007 
0008 #include <acpi/acpi.h>
0009 #include "accommon.h"
0010 #include "amlcode.h"
0011 #include "acdebug.h"
0012 #include "acinterp.h"
0013 #include "acparser.h"
0014 
0015 #define _COMPONENT          ACPI_CA_DEBUGGER
0016 ACPI_MODULE_NAME("dbxface")
0017 
0018 /* Local prototypes */
0019 static acpi_status
0020 acpi_db_start_command(struct acpi_walk_state *walk_state,
0021               union acpi_parse_object *op);
0022 
0023 #ifdef ACPI_OBSOLETE_FUNCTIONS
0024 void acpi_db_method_end(struct acpi_walk_state *walk_state);
0025 #endif
0026 
0027 #ifdef ACPI_DISASSEMBLER
0028 static union acpi_parse_object *acpi_db_get_display_op(struct acpi_walk_state
0029                                *walk_state,
0030                                union acpi_parse_object
0031                                *op);
0032 #endif
0033 
0034 /*******************************************************************************
0035  *
0036  * FUNCTION:    acpi_db_start_command
0037  *
0038  * PARAMETERS:  walk_state      - Current walk
0039  *              op              - Current executing Op, from AML interpreter
0040  *
0041  * RETURN:      Status
0042  *
0043  * DESCRIPTION: Enter debugger command loop
0044  *
0045  ******************************************************************************/
0046 
0047 static acpi_status
0048 acpi_db_start_command(struct acpi_walk_state *walk_state,
0049               union acpi_parse_object *op)
0050 {
0051     acpi_status status;
0052 
0053     /* TBD: [Investigate] are there namespace locking issues here? */
0054 
0055     /* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */
0056 
0057     /* Go into the command loop and await next user command */
0058 
0059     acpi_gbl_method_executing = TRUE;
0060     status = AE_CTRL_TRUE;
0061 
0062     while (status == AE_CTRL_TRUE) {
0063 
0064         /* Notify the completion of the command */
0065 
0066         status = acpi_os_notify_command_complete();
0067         if (ACPI_FAILURE(status)) {
0068             goto error_exit;
0069         }
0070 
0071         /* Wait the readiness of the command */
0072 
0073         status = acpi_os_wait_command_ready();
0074         if (ACPI_FAILURE(status)) {
0075             goto error_exit;
0076         }
0077 
0078         status =
0079             acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state,
0080                          op);
0081     }
0082 
0083     /* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
0084 
0085 error_exit:
0086     if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
0087         ACPI_EXCEPTION((AE_INFO, status,
0088                 "While parsing/handling command line"));
0089     }
0090     return (status);
0091 }
0092 
0093 /*******************************************************************************
0094  *
0095  * FUNCTION:    acpi_db_signal_break_point
0096  *
0097  * PARAMETERS:  walk_state      - Current walk
0098  *
0099  * RETURN:      Status
0100  *
0101  * DESCRIPTION: Called for AML_BREAKPOINT_OP
0102  *
0103  ******************************************************************************/
0104 
0105 void acpi_db_signal_break_point(struct acpi_walk_state *walk_state)
0106 {
0107 
0108 #ifndef ACPI_APPLICATION
0109     if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
0110         return;
0111     }
0112 #endif
0113 
0114     /*
0115      * Set the single-step flag. This will cause the debugger (if present)
0116      * to break to the console within the AML debugger at the start of the
0117      * next AML instruction.
0118      */
0119     acpi_gbl_cm_single_step = TRUE;
0120     acpi_os_printf("**break** Executed AML BreakPoint opcode\n");
0121 }
0122 
0123 #ifdef ACPI_DISASSEMBLER
0124 /*******************************************************************************
0125  *
0126  * FUNCTION:    acpi_db_get_display_op
0127  *
0128  * PARAMETERS:  walk_state      - Current walk
0129  *              op              - Current executing op (from aml interpreter)
0130  *
0131  * RETURN:      Opcode to display
0132  *
0133  * DESCRIPTION: Find the opcode to display during single stepping
0134  *
0135  ******************************************************************************/
0136 
0137 static union acpi_parse_object *acpi_db_get_display_op(struct acpi_walk_state
0138                                *walk_state,
0139                                union acpi_parse_object
0140                                *op)
0141 {
0142     union acpi_parse_object *display_op;
0143     union acpi_parse_object *parent_op;
0144 
0145     display_op = op;
0146     parent_op = op->common.parent;
0147     if (parent_op) {
0148         if ((walk_state->control_state) &&
0149             (walk_state->control_state->common.state ==
0150              ACPI_CONTROL_PREDICATE_EXECUTING)) {
0151             /*
0152              * We are executing the predicate of an IF or WHILE statement
0153              * Search upwards for the containing IF or WHILE so that the
0154              * entire predicate can be displayed.
0155              */
0156             while (parent_op) {
0157                 if ((parent_op->common.aml_opcode == AML_IF_OP)
0158                     || (parent_op->common.aml_opcode ==
0159                     AML_WHILE_OP)) {
0160                     display_op = parent_op;
0161                     break;
0162                 }
0163                 parent_op = parent_op->common.parent;
0164             }
0165         } else {
0166             while (parent_op) {
0167                 if ((parent_op->common.aml_opcode == AML_IF_OP)
0168                     || (parent_op->common.aml_opcode ==
0169                     AML_ELSE_OP)
0170                     || (parent_op->common.aml_opcode ==
0171                     AML_SCOPE_OP)
0172                     || (parent_op->common.aml_opcode ==
0173                     AML_METHOD_OP)
0174                     || (parent_op->common.aml_opcode ==
0175                     AML_WHILE_OP)) {
0176                     break;
0177                 }
0178                 display_op = parent_op;
0179                 parent_op = parent_op->common.parent;
0180             }
0181         }
0182     }
0183     return display_op;
0184 }
0185 #endif
0186 
0187 /*******************************************************************************
0188  *
0189  * FUNCTION:    acpi_db_single_step
0190  *
0191  * PARAMETERS:  walk_state      - Current walk
0192  *              op              - Current executing op (from aml interpreter)
0193  *              opcode_class    - Class of the current AML Opcode
0194  *
0195  * RETURN:      Status
0196  *
0197  * DESCRIPTION: Called just before execution of an AML opcode.
0198  *
0199  ******************************************************************************/
0200 
0201 acpi_status
0202 acpi_db_single_step(struct acpi_walk_state *walk_state,
0203             union acpi_parse_object *op, u32 opcode_class)
0204 {
0205     union acpi_parse_object *next;
0206     acpi_status status = AE_OK;
0207     u32 original_debug_level;
0208     u32 aml_offset;
0209 
0210     ACPI_FUNCTION_ENTRY();
0211 
0212 #ifndef ACPI_APPLICATION
0213     if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
0214         return (AE_OK);
0215     }
0216 #endif
0217 
0218     /* Check the abort flag */
0219 
0220     if (acpi_gbl_abort_method) {
0221         acpi_gbl_abort_method = FALSE;
0222         return (AE_ABORT_METHOD);
0223     }
0224 
0225     aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
0226                     walk_state->parser_state.aml_start);
0227 
0228     /* Check for single-step breakpoint */
0229 
0230     if (walk_state->method_breakpoint &&
0231         (walk_state->method_breakpoint <= aml_offset)) {
0232 
0233         /* Check if the breakpoint has been reached or passed */
0234         /* Hit the breakpoint, resume single step, reset breakpoint */
0235 
0236         acpi_os_printf("***Break*** at AML offset %X\n", aml_offset);
0237         acpi_gbl_cm_single_step = TRUE;
0238         acpi_gbl_step_to_next_call = FALSE;
0239         walk_state->method_breakpoint = 0;
0240     }
0241 
0242     /* Check for user breakpoint (Must be on exact Aml offset) */
0243 
0244     else if (walk_state->user_breakpoint &&
0245          (walk_state->user_breakpoint == aml_offset)) {
0246         acpi_os_printf("***UserBreakpoint*** at AML offset %X\n",
0247                    aml_offset);
0248         acpi_gbl_cm_single_step = TRUE;
0249         acpi_gbl_step_to_next_call = FALSE;
0250         walk_state->method_breakpoint = 0;
0251     }
0252 
0253     /*
0254      * Check if this is an opcode that we are interested in --
0255      * namely, opcodes that have arguments
0256      */
0257     if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
0258         return (AE_OK);
0259     }
0260 
0261     switch (opcode_class) {
0262     case AML_CLASS_UNKNOWN:
0263     case AML_CLASS_ARGUMENT:    /* constants, literals, etc. do nothing */
0264 
0265         return (AE_OK);
0266 
0267     default:
0268 
0269         /* All other opcodes -- continue */
0270         break;
0271     }
0272 
0273     /*
0274      * Under certain debug conditions, display this opcode and its operands
0275      */
0276     if ((acpi_gbl_db_output_to_file) ||
0277         (acpi_gbl_cm_single_step) || (acpi_dbg_level & ACPI_LV_PARSE)) {
0278         if ((acpi_gbl_db_output_to_file) ||
0279             (acpi_dbg_level & ACPI_LV_PARSE)) {
0280             acpi_os_printf
0281                 ("\nAML Debug: Next AML Opcode to execute:\n");
0282         }
0283 
0284         /*
0285          * Display this op (and only this op - zero out the NEXT field
0286          * temporarily, and disable parser trace output for the duration of
0287          * the display because we don't want the extraneous debug output)
0288          */
0289         original_debug_level = acpi_dbg_level;
0290         acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);
0291         next = op->common.next;
0292         op->common.next = NULL;
0293 
0294         /* Now we can disassemble and display it */
0295 
0296 #ifdef ACPI_DISASSEMBLER
0297         acpi_dm_disassemble(walk_state,
0298                     acpi_db_get_display_op(walk_state, op),
0299                     ACPI_UINT32_MAX);
0300 #else
0301         /*
0302          * The AML Disassembler is not configured - at least we can
0303          * display the opcode value and name
0304          */
0305         acpi_os_printf("AML Opcode: %4.4X %s\n", op->common.aml_opcode,
0306                    acpi_ps_get_opcode_name(op->common.aml_opcode));
0307 #endif
0308 
0309         if ((op->common.aml_opcode == AML_IF_OP) ||
0310             (op->common.aml_opcode == AML_WHILE_OP)) {
0311             if (walk_state->control_state->common.value) {
0312                 acpi_os_printf
0313                     ("Predicate = [True], IF block was executed\n");
0314             } else {
0315                 acpi_os_printf
0316                     ("Predicate = [False], Skipping IF block\n");
0317             }
0318         } else if (op->common.aml_opcode == AML_ELSE_OP) {
0319             acpi_os_printf
0320                 ("Predicate = [False], ELSE block was executed\n");
0321         }
0322 
0323         /* Restore everything */
0324 
0325         op->common.next = next;
0326         acpi_os_printf("\n");
0327         if ((acpi_gbl_db_output_to_file) ||
0328             (acpi_dbg_level & ACPI_LV_PARSE)) {
0329             acpi_os_printf("\n");
0330         }
0331         acpi_dbg_level = original_debug_level;
0332     }
0333 
0334     /* If we are not single stepping, just continue executing the method */
0335 
0336     if (!acpi_gbl_cm_single_step) {
0337         return (AE_OK);
0338     }
0339 
0340     /*
0341      * If we are executing a step-to-call command,
0342      * Check if this is a method call.
0343      */
0344     if (acpi_gbl_step_to_next_call) {
0345         if (op->common.aml_opcode != AML_INT_METHODCALL_OP) {
0346 
0347             /* Not a method call, just keep executing */
0348 
0349             return (AE_OK);
0350         }
0351 
0352         /* Found a method call, stop executing */
0353 
0354         acpi_gbl_step_to_next_call = FALSE;
0355     }
0356 
0357     /*
0358      * If the next opcode is a method call, we will "step over" it
0359      * by default.
0360      */
0361     if (op->common.aml_opcode == AML_INT_METHODCALL_OP) {
0362 
0363         /* Force no more single stepping while executing called method */
0364 
0365         acpi_gbl_cm_single_step = FALSE;
0366 
0367         /*
0368          * Set the breakpoint on/before the call, it will stop execution
0369          * as soon as we return
0370          */
0371         walk_state->method_breakpoint = 1;  /* Must be non-zero! */
0372     }
0373 
0374     acpi_ex_exit_interpreter();
0375     status = acpi_db_start_command(walk_state, op);
0376     acpi_ex_enter_interpreter();
0377 
0378     /* User commands complete, continue execution of the interrupted method */
0379 
0380     return (status);
0381 }
0382 
0383 /*******************************************************************************
0384  *
0385  * FUNCTION:    acpi_initialize_debugger
0386  *
0387  * PARAMETERS:  None
0388  *
0389  * RETURN:      Status
0390  *
0391  * DESCRIPTION: Init and start debugger
0392  *
0393  ******************************************************************************/
0394 
0395 acpi_status acpi_initialize_debugger(void)
0396 {
0397     acpi_status status;
0398 
0399     ACPI_FUNCTION_TRACE(acpi_initialize_debugger);
0400 
0401     /* Init globals */
0402 
0403     acpi_gbl_db_buffer = NULL;
0404     acpi_gbl_db_filename = NULL;
0405     acpi_gbl_db_output_to_file = FALSE;
0406 
0407     acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2;
0408     acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
0409     acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
0410 
0411     acpi_gbl_db_opt_no_ini_methods = FALSE;
0412     acpi_gbl_db_opt_no_region_support = FALSE;
0413 
0414     acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE);
0415     if (!acpi_gbl_db_buffer) {
0416         return_ACPI_STATUS(AE_NO_MEMORY);
0417     }
0418     memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);
0419 
0420     /* Initial scope is the root */
0421 
0422     acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX;
0423     acpi_gbl_db_scope_buf[1] = 0;
0424     acpi_gbl_db_scope_node = acpi_gbl_root_node;
0425 
0426     /* Initialize user commands loop */
0427 
0428     acpi_gbl_db_terminate_loop = FALSE;
0429 
0430     /*
0431      * If configured for multi-thread support, the debug executor runs in
0432      * a separate thread so that the front end can be in another address
0433      * space, environment, or even another machine.
0434      */
0435     if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
0436 
0437         /* These were created with one unit, grab it */
0438 
0439         status = acpi_os_initialize_debugger();
0440         if (ACPI_FAILURE(status)) {
0441             acpi_os_printf("Could not get debugger mutex\n");
0442             return_ACPI_STATUS(status);
0443         }
0444 
0445         /* Create the debug execution thread to execute commands */
0446 
0447         acpi_gbl_db_threads_terminated = FALSE;
0448         status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD,
0449                      acpi_db_execute_thread, NULL);
0450         if (ACPI_FAILURE(status)) {
0451             ACPI_EXCEPTION((AE_INFO, status,
0452                     "Could not start debugger thread"));
0453             acpi_gbl_db_threads_terminated = TRUE;
0454             return_ACPI_STATUS(status);
0455         }
0456     } else {
0457         acpi_gbl_db_thread_id = acpi_os_get_thread_id();
0458     }
0459 
0460     return_ACPI_STATUS(AE_OK);
0461 }
0462 
0463 ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)
0464 
0465 /*******************************************************************************
0466  *
0467  * FUNCTION:    acpi_terminate_debugger
0468  *
0469  * PARAMETERS:  None
0470  *
0471  * RETURN:      None
0472  *
0473  * DESCRIPTION: Stop debugger
0474  *
0475  ******************************************************************************/
0476 void acpi_terminate_debugger(void)
0477 {
0478 
0479     /* Terminate the AML Debugger */
0480 
0481     acpi_gbl_db_terminate_loop = TRUE;
0482 
0483     if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
0484 
0485         /* Wait the AML Debugger threads */
0486 
0487         while (!acpi_gbl_db_threads_terminated) {
0488             acpi_os_sleep(100);
0489         }
0490 
0491         acpi_os_terminate_debugger();
0492     }
0493 
0494     if (acpi_gbl_db_buffer) {
0495         acpi_os_free(acpi_gbl_db_buffer);
0496         acpi_gbl_db_buffer = NULL;
0497     }
0498 
0499     /* Ensure that debug output is now disabled */
0500 
0501     acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT;
0502 }
0503 
0504 ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)
0505 
0506 /*******************************************************************************
0507  *
0508  * FUNCTION:    acpi_set_debugger_thread_id
0509  *
0510  * PARAMETERS:  thread_id       - Debugger thread ID
0511  *
0512  * RETURN:      None
0513  *
0514  * DESCRIPTION: Set debugger thread ID
0515  *
0516  ******************************************************************************/
0517 void acpi_set_debugger_thread_id(acpi_thread_id thread_id)
0518 {
0519     acpi_gbl_db_thread_id = thread_id;
0520 }
0521 
0522 ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id)