xref: /netbsd-src/sys/external/bsd/acpica/dist/tools/acpiexec/aeexception.c (revision 046a29855e04359424fd074e8313af6b6be8cfb6)
1 /******************************************************************************
2  *
3  * Module Name: aeexception - Exception and signal handlers
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2023, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "aecommon.h"
45 
46 #define _COMPONENT          ACPI_TOOLS
47         ACPI_MODULE_NAME    ("aeexception")
48 
49 
50 /* Local prototypes */
51 
52 static void
53 AeDisplayMethodCallStack (
54     void);
55 
56 
57 UINT32                      SigintCount = 0;
58 #define ACPI_MAX_CONTROL_C  5
59 
60 
61 /******************************************************************************
62  *
63  * FUNCTION:    AeExceptionHandler
64  *
65  * PARAMETERS:  Standard exception handler parameters
66  *
67  * RETURN:      Status
68  *
69  * DESCRIPTION: System exception handler for AcpiExec utility. Called from
70  *              the core ACPICA code after any exception during method
71  *              execution.
72  *
73  *****************************************************************************/
74 
75 ACPI_STATUS
AeExceptionHandler(ACPI_STATUS AmlStatus,ACPI_NAME Name,UINT16 Opcode,UINT32 AmlOffset,void * Context)76 AeExceptionHandler (
77     ACPI_STATUS             AmlStatus,
78     ACPI_NAME               Name,
79     UINT16                  Opcode,
80     UINT32                  AmlOffset,
81     void                    *Context)
82 {
83     ACPI_STATUS             NewAmlStatus = AmlStatus;
84     ACPI_STATUS             Status;
85     ACPI_BUFFER             ReturnObj;
86     ACPI_OBJECT_LIST        ArgList;
87     ACPI_OBJECT             Arg[3];
88     const char              *Exception;
89     ACPI_HANDLE             ErrHandle;
90 
91 
92     Exception = AcpiFormatException (AmlStatus);
93 
94     if (AcpiGbl_VerboseHandlers)
95     {
96         AcpiOsPrintf (AE_PREFIX
97             "Exception %s during execution\n", Exception);
98 
99         if (Name)
100         {
101             if (ACPI_COMPARE_NAMESEG (&Name, ACPI_ROOT_PATHNAME))
102             {
103                 AcpiOsPrintf (AE_PREFIX
104                     "Evaluating executable code at [%s]\n", ACPI_NAMESPACE_ROOT);
105             }
106             else
107             {
108                 AcpiOsPrintf (AE_PREFIX
109                     "Evaluating Method or Node: [%4.4s]\n", (char *) &Name);
110             }
111         }
112 
113         /* Be terse about loop timeouts */
114 
115         if ((AmlStatus == AE_AML_LOOP_TIMEOUT) && AcpiGbl_AbortLoopOnTimeout)
116         {
117             AcpiOsPrintf (AE_PREFIX "Aborting loop after timeout\n");
118             return (AE_OK);
119         }
120 
121         AcpiOsPrintf ("\n" AE_PREFIX
122             "AML Opcode [%s], Method Offset ~%5.5X\n",
123             AcpiPsGetOpcodeName (Opcode), AmlOffset);
124     }
125 
126     /* Invoke the _ERR method if present */
127 
128     Status = AcpiGetHandle (NULL, "\\_ERR", &ErrHandle);
129     if (ACPI_FAILURE (Status))
130     {
131         goto Cleanup;
132     }
133 
134     /* Setup parameter object */
135 
136     ArgList.Count = 3;
137     ArgList.Pointer = Arg;
138 
139     Arg[0].Type = ACPI_TYPE_INTEGER;
140     Arg[0].Integer.Value = AmlStatus;
141 
142     Arg[1].Type = ACPI_TYPE_STRING;
143     Arg[1].String.Pointer = ACPI_CAST_PTR (char, Exception);
144     Arg[1].String.Length = strlen (Exception);
145 
146     Arg[2].Type = ACPI_TYPE_INTEGER;
147     Arg[2].Integer.Value = AcpiOsGetThreadId();
148 
149     /* Setup return buffer */
150 
151     ReturnObj.Pointer = NULL;
152     ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
153 
154     Status = AcpiEvaluateObject (ErrHandle, NULL, &ArgList, &ReturnObj);
155     if (ACPI_SUCCESS (Status))
156     {
157         if (ReturnObj.Pointer)
158         {
159             /* Override original status */
160 
161             NewAmlStatus = (ACPI_STATUS)
162                 ((ACPI_OBJECT *) ReturnObj.Pointer)->Integer.Value;
163 
164             /* Free a buffer created via ACPI_ALLOCATE_BUFFER */
165 
166             AcpiOsFree (ReturnObj.Pointer);
167         }
168     }
169     else if (Status != AE_NOT_FOUND)
170     {
171         AcpiOsPrintf (AE_PREFIX
172             "Could not execute _ERR method, %s\n",
173             AcpiFormatException (Status));
174     }
175 
176 Cleanup:
177 
178     if (AcpiGbl_IgnoreErrors)
179     {
180         /* Global option to ignore all method errors, just return OK */
181 
182         NewAmlStatus = AE_OK;
183     }
184     if (NewAmlStatus != AmlStatus)
185     {
186         /* Request to override actual status with a different status */
187 
188         AcpiOsPrintf (AE_PREFIX
189             "Exception override, new status %s\n\n",
190             AcpiFormatException (NewAmlStatus));
191     }
192 
193     return (NewAmlStatus);
194 }
195 
196 
197 /******************************************************************************
198  *
199  * FUNCTION:    AeSignalHandler
200  *
201  * PARAMETERS:  Sig
202  *
203  * RETURN:      none
204  *
205  * DESCRIPTION: Master signal handler. Currently handles SIGINT (ctrl-c),
206  *              and SIGSEGV (Segment violation).
207  *
208  *****************************************************************************/
209 
210 void ACPI_SYSTEM_XFACE
AeSignalHandler(int Sig)211 AeSignalHandler (
212     int                     Sig)
213 {
214 
215     fflush(stdout);
216     AcpiOsPrintf ("\n" AE_PREFIX);
217 
218     switch (Sig)
219     {
220     case SIGINT:
221         signal(Sig, SIG_IGN);
222         AcpiOsPrintf ("<Control-C>\n");
223 
224         /* Force exit on multiple control-c */
225 
226         SigintCount++;
227         if (SigintCount >= ACPI_MAX_CONTROL_C)
228         {
229             _exit (0);
230         }
231 
232         /* Abort the application if there are no methods executing */
233 
234         if (!AcpiGbl_MethodExecuting)
235         {
236             break;
237         }
238 
239         /*
240          * Abort the method(s). This will also dump the method call
241          * stack so there is no need to do it here. The application
242          * will then drop back into the debugger interface.
243          */
244         AcpiGbl_AbortMethod = TRUE;
245         AcpiOsPrintf (AE_PREFIX "Control Method Call Stack:\n");
246         signal (SIGINT, AeSignalHandler);
247         return;
248 
249     case SIGSEGV:
250         AcpiOsPrintf ("Segmentation Fault\n");
251         AeDisplayMethodCallStack ();
252         break;
253 
254     default:
255         AcpiOsPrintf ("Unknown Signal, %X\n", Sig);
256         break;
257     }
258 
259     /* Terminate application -- cleanup then exit */
260 
261     AcpiOsPrintf (AE_PREFIX "Terminating\n");
262     (void) AcpiOsTerminate ();
263     _exit (0);
264 }
265 
266 
267 /******************************************************************************
268  *
269  * FUNCTION:    AeDisplayMethodCallStack
270  *
271  * PARAMETERS:  None
272  *
273  * RETURN:      None
274  *
275  * DESCRIPTION: Display current method call stack, if possible.
276  *
277  * NOTE:        Currently only called from a SIGSEGV, so AcpiExec is about
278  *              to terminate.
279  *
280  *****************************************************************************/
281 
282 static void
AeDisplayMethodCallStack(void)283 AeDisplayMethodCallStack (
284     void)
285 {
286     ACPI_WALK_STATE         *WalkState;
287     ACPI_THREAD_STATE       *ThreadList = AcpiGbl_CurrentWalkList;
288     char                    *FullPathname = NULL;
289 
290 
291     if (!AcpiGbl_MethodExecuting)
292     {
293         AcpiOsPrintf (AE_PREFIX "No method is executing\n");
294         return;
295     }
296 
297     /*
298      * Try to find the currently executing control method(s)
299      *
300      * Note: The following code may fault if the data structures are
301      * in an indeterminate state when the interrupt occurs. However,
302      * in practice, this works quite well and can provide very
303      * valuable information.
304      *
305      * 1) Walk the global thread list
306      */
307     while (ThreadList &&
308         (ThreadList->DescriptorType == ACPI_DESC_TYPE_STATE_THREAD))
309     {
310         /* 2) Walk the walk state list for this thread */
311 
312         WalkState = ThreadList->WalkStateList;
313         while (WalkState &&
314             (WalkState->DescriptorType == ACPI_DESC_TYPE_WALK))
315         {
316             /* An executing control method */
317 
318             if (WalkState->MethodNode)
319             {
320                 FullPathname = AcpiNsGetExternalPathname (
321                     WalkState->MethodNode);
322 
323                 AcpiOsPrintf (AE_PREFIX
324                     "Executing Method: %s\n", FullPathname);
325             }
326 
327             /* Execution of a deferred opcode/node */
328 
329             if (WalkState->DeferredNode)
330             {
331                 FullPathname = AcpiNsGetExternalPathname (
332                     WalkState->DeferredNode);
333 
334                 AcpiOsPrintf (AE_PREFIX
335                     "Evaluating deferred node: %s\n", FullPathname);
336             }
337 
338             /* Get the currently executing AML opcode */
339 
340             if ((WalkState->Opcode != AML_INT_METHODCALL_OP) &&
341                 FullPathname)
342             {
343                 AcpiOsPrintf (AE_PREFIX
344                     "Current AML Opcode in %s: [%s]-0x%4.4X at %p\n",
345                     FullPathname, AcpiPsGetOpcodeName (WalkState->Opcode),
346                     WalkState->Opcode, WalkState->Aml);
347             }
348 
349             if (FullPathname)
350             {
351                 ACPI_FREE (FullPathname);
352                 FullPathname = NULL;
353             }
354 
355             WalkState = WalkState->Next;
356         }
357 
358         ThreadList = ThreadList->Next;
359     }
360 }
361