xref: /netbsd-src/sys/external/bsd/acpica/dist/tools/acpiexec/aeexception.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /******************************************************************************
2  *
3  * Module Name: aeexception - Exception and signal handlers
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2018, 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 MERCHANTIBILITY 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 /******************************************************************************
58  *
59  * FUNCTION:    AeExceptionHandler
60  *
61  * PARAMETERS:  Standard exception handler parameters
62  *
63  * RETURN:      Status
64  *
65  * DESCRIPTION: System exception handler for AcpiExec utility. Called from
66  *              the core ACPICA code after any exception during method
67  *              execution.
68  *
69  *****************************************************************************/
70 
71 ACPI_STATUS
72 AeExceptionHandler (
73     ACPI_STATUS             AmlStatus,
74     ACPI_NAME               Name,
75     UINT16                  Opcode,
76     UINT32                  AmlOffset,
77     void                    *Context)
78 {
79     ACPI_STATUS             NewAmlStatus = AmlStatus;
80     ACPI_STATUS             Status;
81     ACPI_BUFFER             ReturnObj;
82     ACPI_OBJECT_LIST        ArgList;
83     ACPI_OBJECT             Arg[3];
84     const char              *Exception;
85     ACPI_HANDLE             ErrHandle;
86 
87 
88     Exception = AcpiFormatException (AmlStatus);
89     AcpiOsPrintf (AE_PREFIX
90         "Exception %s during execution\n", Exception);
91 
92     if (Name)
93     {
94         if (ACPI_COMPARE_NAME (&Name, ACPI_ROOT_PATHNAME))
95         {
96             AcpiOsPrintf (AE_PREFIX
97                 "Evaluating executable code at [%s]\n", ACPI_NAMESPACE_ROOT);
98         }
99         else
100         {
101             AcpiOsPrintf (AE_PREFIX
102                 "Evaluating Method or Node: [%4.4s]\n", (char *) &Name);
103         }
104     }
105 
106     /* Be terse about loop timeouts */
107 
108     if ((AmlStatus == AE_AML_LOOP_TIMEOUT) && AcpiGbl_AbortLoopOnTimeout)
109     {
110         AcpiOsPrintf (AE_PREFIX "Aborting loop after timeout\n");
111         return (AE_OK);
112     }
113 
114     AcpiOsPrintf ("\n" AE_PREFIX
115         "AML Opcode [%s], Method Offset ~%5.5X\n",
116         AcpiPsGetOpcodeName (Opcode), AmlOffset);
117 
118     /* Invoke the _ERR method if present */
119 
120     Status = AcpiGetHandle (NULL, "\\_ERR", &ErrHandle);
121     if (ACPI_FAILURE (Status))
122     {
123         goto Cleanup;
124     }
125 
126     /* Setup parameter object */
127 
128     ArgList.Count = 3;
129     ArgList.Pointer = Arg;
130 
131     Arg[0].Type = ACPI_TYPE_INTEGER;
132     Arg[0].Integer.Value = AmlStatus;
133 
134     Arg[1].Type = ACPI_TYPE_STRING;
135     Arg[1].String.Pointer = ACPI_CAST_PTR (char, Exception);
136     Arg[1].String.Length = strlen (Exception);
137 
138     Arg[2].Type = ACPI_TYPE_INTEGER;
139     Arg[2].Integer.Value = AcpiOsGetThreadId();
140 
141     /* Setup return buffer */
142 
143     ReturnObj.Pointer = NULL;
144     ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
145 
146     Status = AcpiEvaluateObject (ErrHandle, NULL, &ArgList, &ReturnObj);
147     if (ACPI_SUCCESS (Status))
148     {
149         if (ReturnObj.Pointer)
150         {
151             /* Override original status */
152 
153             NewAmlStatus = (ACPI_STATUS)
154                 ((ACPI_OBJECT *) ReturnObj.Pointer)->Integer.Value;
155 
156             /* Free a buffer created via ACPI_ALLOCATE_BUFFER */
157 
158             AcpiOsFree (ReturnObj.Pointer);
159         }
160     }
161     else if (Status != AE_NOT_FOUND)
162     {
163         AcpiOsPrintf (AE_PREFIX
164             "Could not execute _ERR method, %s\n",
165             AcpiFormatException (Status));
166     }
167 
168 Cleanup:
169 
170     if (AcpiGbl_IgnoreErrors)
171     {
172         /* Global option to ignore all method errors, just return OK */
173 
174         NewAmlStatus = AE_OK;
175     }
176     if (NewAmlStatus != AmlStatus)
177     {
178         /* Request to override actual status with a different status */
179 
180         AcpiOsPrintf (AE_PREFIX
181             "Exception override, new status %s\n\n",
182             AcpiFormatException (NewAmlStatus));
183     }
184 
185     return (NewAmlStatus);
186 }
187 
188 
189 /******************************************************************************
190  *
191  * FUNCTION:    AeSignalHandler
192  *
193  * PARAMETERS:  Sig
194  *
195  * RETURN:      none
196  *
197  * DESCRIPTION: Master signal handler. Currently handles SIGINT (ctrl-c),
198  *              and SIGSEGV (Segment violation).
199  *
200  *****************************************************************************/
201 
202 void ACPI_SYSTEM_XFACE
203 AeSignalHandler (
204     int                     Sig)
205 {
206 
207     fflush(stdout);
208     AcpiOsPrintf ("\n" AE_PREFIX);
209 
210     switch (Sig)
211     {
212     case SIGINT:
213         signal(Sig, SIG_IGN);
214         AcpiOsPrintf ("<Control-C>\n");
215 
216         /* Abort the application if there are no methods executing */
217 
218         if (!AcpiGbl_MethodExecuting)
219         {
220             break;
221         }
222 
223         /*
224          * Abort the method(s). This will also dump the method call
225          * stack so there is no need to do it here. The application
226          * will then drop back into the debugger interface.
227          */
228         AcpiGbl_AbortMethod = TRUE;
229         AcpiOsPrintf (AE_PREFIX "Control Method Call Stack:\n");
230         signal (SIGINT, AeSignalHandler);
231         return;
232 
233     case SIGSEGV:
234         AcpiOsPrintf ("Segmentation Fault\n");
235         AeDisplayMethodCallStack ();
236         break;
237 
238     default:
239         AcpiOsPrintf ("Unknown Signal, %X\n", Sig);
240         break;
241     }
242 
243     /* Terminate application -- cleanup then exit */
244 
245     AcpiOsPrintf (AE_PREFIX "Terminating\n");
246     (void) AcpiOsTerminate ();
247     exit (0);
248 }
249 
250 
251 /******************************************************************************
252  *
253  * FUNCTION:    AeDisplayMethodCallStack
254  *
255  * PARAMETERS:  None
256  *
257  * RETURN:      None
258  *
259  * DESCRIPTION: Display current method call stack, if possible.
260  *
261  * NOTE:        Currently only called from a SIGSEGV, so AcpiExec is about
262  *              to terminate.
263  *
264  *****************************************************************************/
265 
266 static void
267 AeDisplayMethodCallStack (
268     void)
269 {
270     ACPI_WALK_STATE         *WalkState;
271     ACPI_THREAD_STATE       *ThreadList = AcpiGbl_CurrentWalkList;
272     char                    *FullPathname = NULL;
273 
274 
275     if (!AcpiGbl_MethodExecuting)
276     {
277         AcpiOsPrintf (AE_PREFIX "No method is executing\n");
278         return;
279     }
280 
281     /*
282      * Try to find the currently executing control method(s)
283      *
284      * Note: The following code may fault if the data structures are
285      * in an indeterminate state when the interrupt occurs. However,
286      * in practice, this works quite well and can provide very
287      * valuable information.
288      *
289      * 1) Walk the global thread list
290      */
291     while (ThreadList &&
292         (ThreadList->DescriptorType == ACPI_DESC_TYPE_STATE_THREAD))
293     {
294         /* 2) Walk the walk state list for this thread */
295 
296         WalkState = ThreadList->WalkStateList;
297         while (WalkState &&
298             (WalkState->DescriptorType == ACPI_DESC_TYPE_WALK))
299         {
300             /* An executing control method */
301 
302             if (WalkState->MethodNode)
303             {
304                 FullPathname = AcpiNsGetExternalPathname (
305                     WalkState->MethodNode);
306 
307                 AcpiOsPrintf (AE_PREFIX
308                     "Executing Method: %s\n", FullPathname);
309             }
310 
311             /* Execution of a deferred opcode/node */
312 
313             if (WalkState->DeferredNode)
314             {
315                 FullPathname = AcpiNsGetExternalPathname (
316                     WalkState->DeferredNode);
317 
318                 AcpiOsPrintf (AE_PREFIX
319                     "Evaluating deferred node: %s\n", FullPathname);
320             }
321 
322             /* Get the currently executing AML opcode */
323 
324             if ((WalkState->Opcode != AML_INT_METHODCALL_OP) &&
325                 FullPathname)
326             {
327                 AcpiOsPrintf (AE_PREFIX
328                     "Current AML Opcode in %s: [%s]-0x%4.4X at %p\n",
329                     FullPathname, AcpiPsGetOpcodeName (WalkState->Opcode),
330                     WalkState->Opcode, WalkState->Aml);
331             }
332 
333             if (FullPathname)
334             {
335                 ACPI_FREE (FullPathname);
336                 FullPathname = NULL;
337             }
338 
339             WalkState = WalkState->Next;
340         }
341 
342         ThreadList = ThreadList->Next;
343     }
344 }
345