xref: /linux/drivers/acpi/acpica/extrace.c (revision 3702a515edec515fcc7e085053da636fefac88d6)
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 - 2025, 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 
acpi_ex_interpreter_trace_enabled(char * name)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 
acpi_ex_get_trace_event_name(acpi_trace_event_type type)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
acpi_ex_trace_point(acpi_trace_event_type type,u8 begin,u8 * aml,char * pathname)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_trace_args
153  *
154  * PARAMETERS:  params            - AML method arguments
155  *              count             - numer of method arguments
156  *
157  * RETURN:      None
158  *
159  * DESCRIPTION: Trace any arguments
160  *
161  ******************************************************************************/
162 
163 void
acpi_ex_trace_args(union acpi_operand_object ** params,u32 count)164 acpi_ex_trace_args(union acpi_operand_object **params, u32 count)
165 {
166 	u32 i;
167 
168 	ACPI_FUNCTION_NAME(ex_trace_args);
169 
170 	for (i = 0; i < count; i++) {
171 		union acpi_operand_object *obj_desc = params[i];
172 
173 		if (!i) {
174 			ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, " "));
175 		}
176 
177 		switch (obj_desc->common.type) {
178 		case ACPI_TYPE_INTEGER:
179 			ACPI_DEBUG_PRINT_RAW((ACPI_DB_TRACE_POINT, "%llx", obj_desc->integer.value));
180 			break;
181 		case ACPI_TYPE_STRING:
182 			if (!obj_desc->string.length) {
183 				ACPI_DEBUG_PRINT_RAW((ACPI_DB_TRACE_POINT, "NULL"));
184 				continue;
185 			}
186 			if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_TRACE_POINT, _COMPONENT))
187 				acpi_ut_print_string(obj_desc->string.pointer, ACPI_UINT8_MAX);
188 			break;
189 		default:
190 			ACPI_DEBUG_PRINT_RAW((ACPI_DB_TRACE_POINT, "Unknown"));
191 			break;
192 		}
193 		if (i+1 == count) {
194 			ACPI_DEBUG_PRINT_RAW((ACPI_DB_TRACE_POINT, "\n"));
195 		} else {
196 			ACPI_DEBUG_PRINT_RAW((ACPI_DB_TRACE_POINT, ", "));
197 		}
198 	}
199 }
200 
201 /*******************************************************************************
202  *
203  * FUNCTION:    acpi_ex_start_trace_method
204  *
205  * PARAMETERS:  method_node         - Node of the method
206  *              obj_desc            - The method object
207  *              walk_state          - current state, NULL if not yet executing
208  *                                    a method.
209  *
210  * RETURN:      None
211  *
212  * DESCRIPTION: Start control method execution trace
213  *
214  ******************************************************************************/
215 
216 void
acpi_ex_start_trace_method(struct acpi_namespace_node * method_node,union acpi_operand_object * obj_desc,struct acpi_walk_state * walk_state)217 acpi_ex_start_trace_method(struct acpi_namespace_node *method_node,
218 			   union acpi_operand_object *obj_desc,
219 			   struct acpi_walk_state *walk_state)
220 {
221 	char *pathname = NULL;
222 	u8 enabled = FALSE;
223 
224 	ACPI_FUNCTION_NAME(ex_start_trace_method);
225 
226 	if (method_node) {
227 		pathname = acpi_ns_get_normalized_pathname(method_node, TRUE);
228 	}
229 
230 	enabled = acpi_ex_interpreter_trace_enabled(pathname);
231 	if (enabled && !acpi_gbl_trace_method_object) {
232 		acpi_gbl_trace_method_object = obj_desc;
233 		acpi_gbl_original_dbg_level = acpi_dbg_level;
234 		acpi_gbl_original_dbg_layer = acpi_dbg_layer;
235 		acpi_dbg_level = ACPI_TRACE_LEVEL_ALL;
236 		acpi_dbg_layer = ACPI_TRACE_LAYER_ALL;
237 
238 		if (acpi_gbl_trace_dbg_level) {
239 			acpi_dbg_level = acpi_gbl_trace_dbg_level;
240 		}
241 
242 		if (acpi_gbl_trace_dbg_layer) {
243 			acpi_dbg_layer = acpi_gbl_trace_dbg_layer;
244 		}
245 	}
246 
247 	if (enabled) {
248 		ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, TRUE,
249 				 obj_desc ? obj_desc->method.aml_start : NULL,
250 				 pathname);
251 	}
252 
253 	if (pathname) {
254 		ACPI_FREE(pathname);
255 	}
256 }
257 
258 /*******************************************************************************
259  *
260  * FUNCTION:    acpi_ex_stop_trace_method
261  *
262  * PARAMETERS:  method_node         - Node of the method
263  *              obj_desc            - The method object
264  *              walk_state          - current state, NULL if not yet executing
265  *                                    a method.
266  *
267  * RETURN:      None
268  *
269  * DESCRIPTION: Stop control method execution trace
270  *
271  ******************************************************************************/
272 
273 void
acpi_ex_stop_trace_method(struct acpi_namespace_node * method_node,union acpi_operand_object * obj_desc,struct acpi_walk_state * walk_state)274 acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node,
275 			  union acpi_operand_object *obj_desc,
276 			  struct acpi_walk_state *walk_state)
277 {
278 	char *pathname = NULL;
279 	u8 enabled;
280 
281 	ACPI_FUNCTION_NAME(ex_stop_trace_method);
282 
283 	if (method_node) {
284 		pathname = acpi_ns_get_normalized_pathname(method_node, TRUE);
285 	}
286 
287 	enabled = acpi_ex_interpreter_trace_enabled(NULL);
288 
289 	if (enabled) {
290 		ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, FALSE,
291 				 obj_desc ? obj_desc->method.aml_start : NULL,
292 				 pathname);
293 	}
294 
295 	/* Check whether the tracer should be stopped */
296 
297 	if (acpi_gbl_trace_method_object == obj_desc) {
298 
299 		/* Disable further tracing if type is one-shot */
300 
301 		if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) {
302 			acpi_gbl_trace_method_name = NULL;
303 		}
304 
305 		acpi_dbg_level = acpi_gbl_original_dbg_level;
306 		acpi_dbg_layer = acpi_gbl_original_dbg_layer;
307 		acpi_gbl_trace_method_object = NULL;
308 	}
309 
310 	if (pathname) {
311 		ACPI_FREE(pathname);
312 	}
313 }
314 
315 /*******************************************************************************
316  *
317  * FUNCTION:    acpi_ex_start_trace_opcode
318  *
319  * PARAMETERS:  op                  - The parser opcode object
320  *              walk_state          - current state, NULL if not yet executing
321  *                                    a method.
322  *
323  * RETURN:      None
324  *
325  * DESCRIPTION: Start opcode execution trace
326  *
327  ******************************************************************************/
328 
329 void
acpi_ex_start_trace_opcode(union acpi_parse_object * op,struct acpi_walk_state * walk_state)330 acpi_ex_start_trace_opcode(union acpi_parse_object *op,
331 			   struct acpi_walk_state *walk_state)
332 {
333 
334 	ACPI_FUNCTION_NAME(ex_start_trace_opcode);
335 
336 	if (acpi_ex_interpreter_trace_enabled(NULL) &&
337 	    (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) {
338 		ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, TRUE,
339 				 op->common.aml, op->common.aml_op_name);
340 	}
341 }
342 
343 /*******************************************************************************
344  *
345  * FUNCTION:    acpi_ex_stop_trace_opcode
346  *
347  * PARAMETERS:  op                  - The parser opcode object
348  *              walk_state          - current state, NULL if not yet executing
349  *                                    a method.
350  *
351  * RETURN:      None
352  *
353  * DESCRIPTION: Stop opcode execution trace
354  *
355  ******************************************************************************/
356 
357 void
acpi_ex_stop_trace_opcode(union acpi_parse_object * op,struct acpi_walk_state * walk_state)358 acpi_ex_stop_trace_opcode(union acpi_parse_object *op,
359 			  struct acpi_walk_state *walk_state)
360 {
361 
362 	ACPI_FUNCTION_NAME(ex_stop_trace_opcode);
363 
364 	if (acpi_ex_interpreter_trace_enabled(NULL) &&
365 	    (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) {
366 		ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, FALSE,
367 				 op->common.aml, op->common.aml_op_name);
368 	}
369 }
370