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 - 2022, 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_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
acpi_ex_start_trace_method(struct acpi_namespace_node * method_node,union acpi_operand_object * obj_desc,struct acpi_walk_state * walk_state)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(method_node, TRUE);
177 	}
178 
179 	enabled = acpi_ex_interpreter_trace_enabled(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
acpi_ex_stop_trace_method(struct acpi_namespace_node * method_node,union acpi_operand_object * obj_desc,struct acpi_walk_state * walk_state)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(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
acpi_ex_start_trace_opcode(union acpi_parse_object * op,struct acpi_walk_state * walk_state)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
acpi_ex_stop_trace_opcode(union acpi_parse_object * op,struct acpi_walk_state * walk_state)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