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  
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