1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: dsdebug - Parser/Interpreter interface - debugging |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acdispat.h" |
13 | #include "acnamesp.h" |
14 | #ifdef ACPI_DISASSEMBLER |
15 | #include "acdisasm.h" |
16 | #endif |
17 | #include "acinterp.h" |
18 | |
19 | #define _COMPONENT ACPI_DISPATCHER |
20 | ACPI_MODULE_NAME("dsdebug" ) |
21 | |
22 | #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) |
23 | /* Local prototypes */ |
24 | static void |
25 | acpi_ds_print_node_pathname(struct acpi_namespace_node *node, |
26 | const char *message); |
27 | |
28 | /******************************************************************************* |
29 | * |
30 | * FUNCTION: acpi_ds_print_node_pathname |
31 | * |
32 | * PARAMETERS: node - Object |
33 | * message - Prefix message |
34 | * |
35 | * DESCRIPTION: Print an object's full namespace pathname |
36 | * Manages allocation/freeing of a pathname buffer |
37 | * |
38 | ******************************************************************************/ |
39 | |
40 | static void |
41 | acpi_ds_print_node_pathname(struct acpi_namespace_node *node, |
42 | const char *message) |
43 | { |
44 | struct acpi_buffer buffer; |
45 | acpi_status status; |
46 | |
47 | ACPI_FUNCTION_TRACE(ds_print_node_pathname); |
48 | |
49 | if (!node) { |
50 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[NULL NAME]" )); |
51 | return_VOID; |
52 | } |
53 | |
54 | /* Convert handle to full pathname and print it (with supplied message) */ |
55 | |
56 | buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
57 | |
58 | status = acpi_ns_handle_to_pathname(target_handle: node, buffer: &buffer, TRUE); |
59 | if (ACPI_SUCCESS(status)) { |
60 | if (message) { |
61 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "%s " , |
62 | message)); |
63 | } |
64 | |
65 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[%s] (Node %p)" , |
66 | (char *)buffer.pointer, node)); |
67 | ACPI_FREE(buffer.pointer); |
68 | } |
69 | |
70 | return_VOID; |
71 | } |
72 | |
73 | /******************************************************************************* |
74 | * |
75 | * FUNCTION: acpi_ds_dump_method_stack |
76 | * |
77 | * PARAMETERS: status - Method execution status |
78 | * walk_state - Current state of the parse tree walk |
79 | * op - Executing parse op |
80 | * |
81 | * RETURN: None |
82 | * |
83 | * DESCRIPTION: Called when a method has been aborted because of an error. |
84 | * Dumps the method execution stack. |
85 | * |
86 | ******************************************************************************/ |
87 | |
88 | void |
89 | acpi_ds_dump_method_stack(acpi_status status, |
90 | struct acpi_walk_state *walk_state, |
91 | union acpi_parse_object *op) |
92 | { |
93 | union acpi_parse_object *next; |
94 | struct acpi_thread_state *thread; |
95 | struct acpi_walk_state *next_walk_state; |
96 | struct acpi_namespace_node *previous_method = NULL; |
97 | union acpi_operand_object *method_desc; |
98 | |
99 | ACPI_FUNCTION_TRACE(ds_dump_method_stack); |
100 | |
101 | /* Ignore control codes, they are not errors */ |
102 | |
103 | if (ACPI_CNTL_EXCEPTION(status)) { |
104 | return_VOID; |
105 | } |
106 | |
107 | /* We may be executing a deferred opcode */ |
108 | |
109 | if (walk_state->deferred_node) { |
110 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
111 | "Executing subtree for Buffer/Package/Region\n" )); |
112 | return_VOID; |
113 | } |
114 | |
115 | /* |
116 | * If there is no Thread, we are not actually executing a method. |
117 | * This can happen when the iASL compiler calls the interpreter |
118 | * to perform constant folding. |
119 | */ |
120 | thread = walk_state->thread; |
121 | if (!thread) { |
122 | return_VOID; |
123 | } |
124 | |
125 | /* Display exception and method name */ |
126 | |
127 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
128 | "\n**** Exception %s during execution of method " , |
129 | acpi_format_exception(status))); |
130 | |
131 | acpi_ds_print_node_pathname(node: walk_state->method_node, NULL); |
132 | |
133 | /* Display stack of executing methods */ |
134 | |
135 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, |
136 | "\n\nMethod Execution Stack:\n" )); |
137 | next_walk_state = thread->walk_state_list; |
138 | |
139 | /* Walk list of linked walk states */ |
140 | |
141 | while (next_walk_state) { |
142 | method_desc = next_walk_state->method_desc; |
143 | if (method_desc) { |
144 | acpi_ex_stop_trace_method(method_node: (struct acpi_namespace_node *) |
145 | method_desc->method.node, |
146 | obj_desc: method_desc, walk_state); |
147 | } |
148 | |
149 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
150 | " Method [%4.4s] executing: " , |
151 | acpi_ut_get_node_name(next_walk_state-> |
152 | method_node))); |
153 | |
154 | /* First method is the currently executing method */ |
155 | |
156 | if (next_walk_state == walk_state) { |
157 | if (op) { |
158 | |
159 | /* Display currently executing ASL statement */ |
160 | |
161 | next = op->common.next; |
162 | op->common.next = NULL; |
163 | |
164 | #ifdef ACPI_DISASSEMBLER |
165 | if (walk_state->method_node != |
166 | acpi_gbl_root_node) { |
167 | |
168 | /* More verbose if not module-level code */ |
169 | |
170 | acpi_os_printf("Failed at " ); |
171 | acpi_dm_disassemble(next_walk_state, op, |
172 | ACPI_UINT32_MAX); |
173 | } |
174 | #endif |
175 | op->common.next = next; |
176 | } |
177 | } else { |
178 | /* |
179 | * This method has called another method |
180 | * NOTE: the method call parse subtree is already deleted at |
181 | * this point, so we cannot disassemble the method invocation. |
182 | */ |
183 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, |
184 | "Call to method " )); |
185 | acpi_ds_print_node_pathname(node: previous_method, NULL); |
186 | } |
187 | |
188 | previous_method = next_walk_state->method_node; |
189 | next_walk_state = next_walk_state->next; |
190 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "\n" )); |
191 | } |
192 | |
193 | return_VOID; |
194 | } |
195 | |
196 | #else |
197 | void |
198 | acpi_ds_dump_method_stack(acpi_status status, |
199 | struct acpi_walk_state *walk_state, |
200 | union acpi_parse_object *op) |
201 | { |
202 | return; |
203 | } |
204 | |
205 | #endif |
206 | |