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