1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /*******************************************************************************
4 * Module Name: dbxface - AML Debugger external interfaces
6 ******************************************************************************/
14 #define _COMPONENT ACPI_CA_DEBUGGER
15 ACPI_MODULE_NAME("dbxface")
17 /* Local prototypes */
19 acpi_db_start_command(struct acpi_walk_state *walk_state,
20 union acpi_parse_object *op);
22 #ifdef ACPI_OBSOLETE_FUNCTIONS
23 void acpi_db_method_end(struct acpi_walk_state *walk_state);
26 /*******************************************************************************
28 * FUNCTION: acpi_db_start_command
30 * PARAMETERS: walk_state - Current walk
31 * op - Current executing Op, from AML interpreter
35 * DESCRIPTION: Enter debugger command loop
37 ******************************************************************************/
40 acpi_db_start_command(struct acpi_walk_state *walk_state,
41 union acpi_parse_object *op)
45 /* TBD: [Investigate] are there namespace locking issues here? */
47 /* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */
49 /* Go into the command loop and await next user command */
51 acpi_gbl_method_executing = TRUE;
52 status = AE_CTRL_TRUE;
54 while (status == AE_CTRL_TRUE) {
56 /* Notify the completion of the command */
58 status = acpi_os_notify_command_complete();
59 if (ACPI_FAILURE(status)) {
63 /* Wait the readiness of the command */
65 status = acpi_os_wait_command_ready();
66 if (ACPI_FAILURE(status)) {
71 acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state,
75 /* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
78 if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
79 ACPI_EXCEPTION((AE_INFO, status,
80 "While parsing/handling command line"));
85 /*******************************************************************************
87 * FUNCTION: acpi_db_signal_break_point
89 * PARAMETERS: walk_state - Current walk
93 * DESCRIPTION: Called for AML_BREAKPOINT_OP
95 ******************************************************************************/
97 void acpi_db_signal_break_point(struct acpi_walk_state *walk_state)
100 #ifndef ACPI_APPLICATION
101 if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
107 * Set the single-step flag. This will cause the debugger (if present)
108 * to break to the console within the AML debugger at the start of the
109 * next AML instruction.
111 acpi_gbl_cm_single_step = TRUE;
112 acpi_os_printf("**break** Executed AML BreakPoint opcode\n");
115 /*******************************************************************************
117 * FUNCTION: acpi_db_single_step
119 * PARAMETERS: walk_state - Current walk
120 * op - Current executing op (from aml interpreter)
121 * opcode_class - Class of the current AML Opcode
125 * DESCRIPTION: Called just before execution of an AML opcode.
127 ******************************************************************************/
130 acpi_db_single_step(struct acpi_walk_state *walk_state,
131 union acpi_parse_object *op, u32 opcode_class)
133 union acpi_parse_object *next;
134 acpi_status status = AE_OK;
135 u32 original_debug_level;
136 union acpi_parse_object *display_op;
137 union acpi_parse_object *parent_op;
140 ACPI_FUNCTION_ENTRY();
142 #ifndef ACPI_APPLICATION
143 if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
148 /* Check the abort flag */
150 if (acpi_gbl_abort_method) {
151 acpi_gbl_abort_method = FALSE;
152 return (AE_ABORT_METHOD);
155 aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
156 walk_state->parser_state.aml_start);
158 /* Check for single-step breakpoint */
160 if (walk_state->method_breakpoint &&
161 (walk_state->method_breakpoint <= aml_offset)) {
163 /* Check if the breakpoint has been reached or passed */
164 /* Hit the breakpoint, resume single step, reset breakpoint */
166 acpi_os_printf("***Break*** at AML offset %X\n", aml_offset);
167 acpi_gbl_cm_single_step = TRUE;
168 acpi_gbl_step_to_next_call = FALSE;
169 walk_state->method_breakpoint = 0;
172 /* Check for user breakpoint (Must be on exact Aml offset) */
174 else if (walk_state->user_breakpoint &&
175 (walk_state->user_breakpoint == aml_offset)) {
176 acpi_os_printf("***UserBreakpoint*** at AML offset %X\n",
178 acpi_gbl_cm_single_step = TRUE;
179 acpi_gbl_step_to_next_call = FALSE;
180 walk_state->method_breakpoint = 0;
184 * Check if this is an opcode that we are interested in --
185 * namely, opcodes that have arguments
187 if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
191 switch (opcode_class) {
192 case AML_CLASS_UNKNOWN:
193 case AML_CLASS_ARGUMENT: /* constants, literals, etc. do nothing */
199 /* All other opcodes -- continue */
204 * Under certain debug conditions, display this opcode and its operands
206 if ((acpi_gbl_db_output_to_file) ||
207 (acpi_gbl_cm_single_step) || (acpi_dbg_level & ACPI_LV_PARSE)) {
208 if ((acpi_gbl_db_output_to_file) ||
209 (acpi_dbg_level & ACPI_LV_PARSE)) {
211 ("\nAML Debug: Next AML Opcode to execute:\n");
215 * Display this op (and only this op - zero out the NEXT field
216 * temporarily, and disable parser trace output for the duration of
217 * the display because we don't want the extraneous debug output)
219 original_debug_level = acpi_dbg_level;
220 acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);
221 next = op->common.next;
222 op->common.next = NULL;
225 parent_op = op->common.parent;
227 if ((walk_state->control_state) &&
228 (walk_state->control_state->common.state ==
229 ACPI_CONTROL_PREDICATE_EXECUTING)) {
231 * We are executing the predicate of an IF or WHILE statement
232 * Search upwards for the containing IF or WHILE so that the
233 * entire predicate can be displayed.
236 if ((parent_op->common.aml_opcode ==
238 || (parent_op->common.aml_opcode ==
240 display_op = parent_op;
243 parent_op = parent_op->common.parent;
247 if ((parent_op->common.aml_opcode ==
249 || (parent_op->common.aml_opcode ==
251 || (parent_op->common.aml_opcode ==
253 || (parent_op->common.aml_opcode ==
255 || (parent_op->common.aml_opcode ==
259 display_op = parent_op;
260 parent_op = parent_op->common.parent;
265 /* Now we can display it */
267 #ifdef ACPI_DISASSEMBLER
268 acpi_dm_disassemble(walk_state, display_op, ACPI_UINT32_MAX);
271 if ((op->common.aml_opcode == AML_IF_OP) ||
272 (op->common.aml_opcode == AML_WHILE_OP)) {
273 if (walk_state->control_state->common.value) {
275 ("Predicate = [True], IF block was executed\n");
278 ("Predicate = [False], Skipping IF block\n");
280 } else if (op->common.aml_opcode == AML_ELSE_OP) {
282 ("Predicate = [False], ELSE block was executed\n");
285 /* Restore everything */
287 op->common.next = next;
288 acpi_os_printf("\n");
289 if ((acpi_gbl_db_output_to_file) ||
290 (acpi_dbg_level & ACPI_LV_PARSE)) {
291 acpi_os_printf("\n");
293 acpi_dbg_level = original_debug_level;
296 /* If we are not single stepping, just continue executing the method */
298 if (!acpi_gbl_cm_single_step) {
303 * If we are executing a step-to-call command,
304 * Check if this is a method call.
306 if (acpi_gbl_step_to_next_call) {
307 if (op->common.aml_opcode != AML_INT_METHODCALL_OP) {
309 /* Not a method call, just keep executing */
314 /* Found a method call, stop executing */
316 acpi_gbl_step_to_next_call = FALSE;
320 * If the next opcode is a method call, we will "step over" it
323 if (op->common.aml_opcode == AML_INT_METHODCALL_OP) {
325 /* Force no more single stepping while executing called method */
327 acpi_gbl_cm_single_step = FALSE;
330 * Set the breakpoint on/before the call, it will stop execution
331 * as soon as we return
333 walk_state->method_breakpoint = 1; /* Must be non-zero! */
336 acpi_ex_exit_interpreter();
337 status = acpi_db_start_command(walk_state, op);
338 acpi_ex_enter_interpreter();
340 /* User commands complete, continue execution of the interrupted method */
345 /*******************************************************************************
347 * FUNCTION: acpi_initialize_debugger
353 * DESCRIPTION: Init and start debugger
355 ******************************************************************************/
357 acpi_status acpi_initialize_debugger(void)
361 ACPI_FUNCTION_TRACE(acpi_initialize_debugger);
365 acpi_gbl_db_buffer = NULL;
366 acpi_gbl_db_filename = NULL;
367 acpi_gbl_db_output_to_file = FALSE;
369 acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2;
370 acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
371 acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
373 acpi_gbl_db_opt_no_ini_methods = FALSE;
375 acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE);
376 if (!acpi_gbl_db_buffer) {
377 return_ACPI_STATUS(AE_NO_MEMORY);
379 memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);
381 /* Initial scope is the root */
383 acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX;
384 acpi_gbl_db_scope_buf[1] = 0;
385 acpi_gbl_db_scope_node = acpi_gbl_root_node;
387 /* Initialize user commands loop */
389 acpi_gbl_db_terminate_loop = FALSE;
392 * If configured for multi-thread support, the debug executor runs in
393 * a separate thread so that the front end can be in another address
394 * space, environment, or even another machine.
396 if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
398 /* These were created with one unit, grab it */
400 status = acpi_os_initialize_debugger();
401 if (ACPI_FAILURE(status)) {
402 acpi_os_printf("Could not get debugger mutex\n");
403 return_ACPI_STATUS(status);
406 /* Create the debug execution thread to execute commands */
408 acpi_gbl_db_threads_terminated = FALSE;
409 status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD,
410 acpi_db_execute_thread, NULL);
411 if (ACPI_FAILURE(status)) {
412 ACPI_EXCEPTION((AE_INFO, status,
413 "Could not start debugger thread"));
414 acpi_gbl_db_threads_terminated = TRUE;
415 return_ACPI_STATUS(status);
418 acpi_gbl_db_thread_id = acpi_os_get_thread_id();
421 return_ACPI_STATUS(AE_OK);
424 ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)
426 /*******************************************************************************
428 * FUNCTION: acpi_terminate_debugger
434 * DESCRIPTION: Stop debugger
436 ******************************************************************************/
437 void acpi_terminate_debugger(void)
440 /* Terminate the AML Debugger */
442 acpi_gbl_db_terminate_loop = TRUE;
444 if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
446 /* Wait the AML Debugger threads */
448 while (!acpi_gbl_db_threads_terminated) {
452 acpi_os_terminate_debugger();
455 if (acpi_gbl_db_buffer) {
456 acpi_os_free(acpi_gbl_db_buffer);
457 acpi_gbl_db_buffer = NULL;
460 /* Ensure that debug output is now disabled */
462 acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT;
465 ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)
467 /*******************************************************************************
469 * FUNCTION: acpi_set_debugger_thread_id
471 * PARAMETERS: thread_id - Debugger thread ID
475 * DESCRIPTION: Set debugger thread ID
477 ******************************************************************************/
478 void acpi_set_debugger_thread_id(acpi_thread_id thread_id)
480 acpi_gbl_db_thread_id = thread_id;
483 ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id)