1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: extrace - Support for interpreter execution tracing |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acnamesp.h" |
13 | #include "acinterp.h" |
14 | |
15 | #define _COMPONENT ACPI_EXECUTER |
16 | ACPI_MODULE_NAME("extrace" ) |
17 | |
18 | static union acpi_operand_object *acpi_gbl_trace_method_object = NULL; |
19 | |
20 | /* Local prototypes */ |
21 | |
22 | #ifdef ACPI_DEBUG_OUTPUT |
23 | static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type); |
24 | #endif |
25 | |
26 | /******************************************************************************* |
27 | * |
28 | * FUNCTION: acpi_ex_interpreter_trace_enabled |
29 | * |
30 | * PARAMETERS: name - Whether method name should be matched, |
31 | * this should be checked before starting |
32 | * the tracer |
33 | * |
34 | * RETURN: TRUE if interpreter trace is enabled. |
35 | * |
36 | * DESCRIPTION: Check whether interpreter trace is enabled |
37 | * |
38 | ******************************************************************************/ |
39 | |
40 | static u8 acpi_ex_interpreter_trace_enabled(char *name) |
41 | { |
42 | |
43 | /* Check if tracing is enabled */ |
44 | |
45 | if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED)) { |
46 | return (FALSE); |
47 | } |
48 | |
49 | /* |
50 | * Check if tracing is filtered: |
51 | * |
52 | * 1. If the tracer is started, acpi_gbl_trace_method_object should have |
53 | * been filled by the trace starter |
54 | * 2. If the tracer is not started, acpi_gbl_trace_method_name should be |
55 | * matched if it is specified |
56 | * 3. If the tracer is oneshot style, acpi_gbl_trace_method_name should |
57 | * not be cleared by the trace stopper during the first match |
58 | */ |
59 | if (acpi_gbl_trace_method_object) { |
60 | return (TRUE); |
61 | } |
62 | |
63 | if (name && |
64 | (acpi_gbl_trace_method_name && |
65 | strcmp(acpi_gbl_trace_method_name, name))) { |
66 | return (FALSE); |
67 | } |
68 | |
69 | if ((acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) && |
70 | !acpi_gbl_trace_method_name) { |
71 | return (FALSE); |
72 | } |
73 | |
74 | return (TRUE); |
75 | } |
76 | |
77 | /******************************************************************************* |
78 | * |
79 | * FUNCTION: acpi_ex_get_trace_event_name |
80 | * |
81 | * PARAMETERS: type - Trace event type |
82 | * |
83 | * RETURN: Trace event name. |
84 | * |
85 | * DESCRIPTION: Used to obtain the full trace event name. |
86 | * |
87 | ******************************************************************************/ |
88 | |
89 | #ifdef ACPI_DEBUG_OUTPUT |
90 | |
91 | static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type) |
92 | { |
93 | |
94 | switch (type) { |
95 | case ACPI_TRACE_AML_METHOD: |
96 | |
97 | return "Method" ; |
98 | |
99 | case ACPI_TRACE_AML_OPCODE: |
100 | |
101 | return "Opcode" ; |
102 | |
103 | case ACPI_TRACE_AML_REGION: |
104 | |
105 | return "Region" ; |
106 | |
107 | default: |
108 | |
109 | return "" ; |
110 | } |
111 | } |
112 | |
113 | #endif |
114 | |
115 | /******************************************************************************* |
116 | * |
117 | * FUNCTION: acpi_ex_trace_point |
118 | * |
119 | * PARAMETERS: type - Trace event type |
120 | * begin - TRUE if before execution |
121 | * aml - Executed AML address |
122 | * pathname - Object path |
123 | * |
124 | * RETURN: None |
125 | * |
126 | * DESCRIPTION: Internal interpreter execution trace. |
127 | * |
128 | ******************************************************************************/ |
129 | |
130 | void |
131 | acpi_ex_trace_point(acpi_trace_event_type type, |
132 | u8 begin, u8 *aml, char *pathname) |
133 | { |
134 | |
135 | ACPI_FUNCTION_NAME(ex_trace_point); |
136 | |
137 | if (pathname) { |
138 | ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, |
139 | "%s %s [0x%p:%s] execution.\n" , |
140 | acpi_ex_get_trace_event_name(type), |
141 | begin ? "Begin" : "End" , aml, pathname)); |
142 | } else { |
143 | ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, |
144 | "%s %s [0x%p] execution.\n" , |
145 | acpi_ex_get_trace_event_name(type), |
146 | begin ? "Begin" : "End" , aml)); |
147 | } |
148 | } |
149 | |
150 | /******************************************************************************* |
151 | * |
152 | * FUNCTION: acpi_ex_start_trace_method |
153 | * |
154 | * PARAMETERS: method_node - Node of the method |
155 | * obj_desc - The method object |
156 | * walk_state - current state, NULL if not yet executing |
157 | * a method. |
158 | * |
159 | * RETURN: None |
160 | * |
161 | * DESCRIPTION: Start control method execution trace |
162 | * |
163 | ******************************************************************************/ |
164 | |
165 | void |
166 | acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, |
167 | union acpi_operand_object *obj_desc, |
168 | struct acpi_walk_state *walk_state) |
169 | { |
170 | char *pathname = NULL; |
171 | u8 enabled = FALSE; |
172 | |
173 | ACPI_FUNCTION_NAME(ex_start_trace_method); |
174 | |
175 | if (method_node) { |
176 | pathname = acpi_ns_get_normalized_pathname(node: method_node, TRUE); |
177 | } |
178 | |
179 | enabled = acpi_ex_interpreter_trace_enabled(name: pathname); |
180 | if (enabled && !acpi_gbl_trace_method_object) { |
181 | acpi_gbl_trace_method_object = obj_desc; |
182 | acpi_gbl_original_dbg_level = acpi_dbg_level; |
183 | acpi_gbl_original_dbg_layer = acpi_dbg_layer; |
184 | acpi_dbg_level = ACPI_TRACE_LEVEL_ALL; |
185 | acpi_dbg_layer = ACPI_TRACE_LAYER_ALL; |
186 | |
187 | if (acpi_gbl_trace_dbg_level) { |
188 | acpi_dbg_level = acpi_gbl_trace_dbg_level; |
189 | } |
190 | |
191 | if (acpi_gbl_trace_dbg_layer) { |
192 | acpi_dbg_layer = acpi_gbl_trace_dbg_layer; |
193 | } |
194 | } |
195 | |
196 | if (enabled) { |
197 | ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, TRUE, |
198 | obj_desc ? obj_desc->method.aml_start : NULL, |
199 | pathname); |
200 | } |
201 | |
202 | if (pathname) { |
203 | ACPI_FREE(pathname); |
204 | } |
205 | } |
206 | |
207 | /******************************************************************************* |
208 | * |
209 | * FUNCTION: acpi_ex_stop_trace_method |
210 | * |
211 | * PARAMETERS: method_node - Node of the method |
212 | * obj_desc - The method object |
213 | * walk_state - current state, NULL if not yet executing |
214 | * a method. |
215 | * |
216 | * RETURN: None |
217 | * |
218 | * DESCRIPTION: Stop control method execution trace |
219 | * |
220 | ******************************************************************************/ |
221 | |
222 | void |
223 | acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node, |
224 | union acpi_operand_object *obj_desc, |
225 | struct acpi_walk_state *walk_state) |
226 | { |
227 | char *pathname = NULL; |
228 | u8 enabled; |
229 | |
230 | ACPI_FUNCTION_NAME(ex_stop_trace_method); |
231 | |
232 | if (method_node) { |
233 | pathname = acpi_ns_get_normalized_pathname(node: method_node, TRUE); |
234 | } |
235 | |
236 | enabled = acpi_ex_interpreter_trace_enabled(NULL); |
237 | |
238 | if (enabled) { |
239 | ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, FALSE, |
240 | obj_desc ? obj_desc->method.aml_start : NULL, |
241 | pathname); |
242 | } |
243 | |
244 | /* Check whether the tracer should be stopped */ |
245 | |
246 | if (acpi_gbl_trace_method_object == obj_desc) { |
247 | |
248 | /* Disable further tracing if type is one-shot */ |
249 | |
250 | if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) { |
251 | acpi_gbl_trace_method_name = NULL; |
252 | } |
253 | |
254 | acpi_dbg_level = acpi_gbl_original_dbg_level; |
255 | acpi_dbg_layer = acpi_gbl_original_dbg_layer; |
256 | acpi_gbl_trace_method_object = NULL; |
257 | } |
258 | |
259 | if (pathname) { |
260 | ACPI_FREE(pathname); |
261 | } |
262 | } |
263 | |
264 | /******************************************************************************* |
265 | * |
266 | * FUNCTION: acpi_ex_start_trace_opcode |
267 | * |
268 | * PARAMETERS: op - The parser opcode object |
269 | * walk_state - current state, NULL if not yet executing |
270 | * a method. |
271 | * |
272 | * RETURN: None |
273 | * |
274 | * DESCRIPTION: Start opcode execution trace |
275 | * |
276 | ******************************************************************************/ |
277 | |
278 | void |
279 | acpi_ex_start_trace_opcode(union acpi_parse_object *op, |
280 | struct acpi_walk_state *walk_state) |
281 | { |
282 | |
283 | ACPI_FUNCTION_NAME(ex_start_trace_opcode); |
284 | |
285 | if (acpi_ex_interpreter_trace_enabled(NULL) && |
286 | (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { |
287 | ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, TRUE, |
288 | op->common.aml, op->common.aml_op_name); |
289 | } |
290 | } |
291 | |
292 | /******************************************************************************* |
293 | * |
294 | * FUNCTION: acpi_ex_stop_trace_opcode |
295 | * |
296 | * PARAMETERS: op - The parser opcode object |
297 | * walk_state - current state, NULL if not yet executing |
298 | * a method. |
299 | * |
300 | * RETURN: None |
301 | * |
302 | * DESCRIPTION: Stop opcode execution trace |
303 | * |
304 | ******************************************************************************/ |
305 | |
306 | void |
307 | acpi_ex_stop_trace_opcode(union acpi_parse_object *op, |
308 | struct acpi_walk_state *walk_state) |
309 | { |
310 | |
311 | ACPI_FUNCTION_NAME(ex_stop_trace_opcode); |
312 | |
313 | if (acpi_ex_interpreter_trace_enabled(NULL) && |
314 | (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { |
315 | ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, FALSE, |
316 | op->common.aml, op->common.aml_op_name); |
317 | } |
318 | } |
319 | |