xref: /netbsd-src/sys/external/bsd/acpica/dist/executer/exdebug.c (revision 63aea4bd5b445e491ff0389fe27ec78b3099dba3)
1 /******************************************************************************
2  *
3  * Module Name: exdebug - Support for stores to the AML Debug Object
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2015, 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 "acpi.h"
45 #include "accommon.h"
46 #include "acnamesp.h"
47 #include "acinterp.h"
48 #include "acparser.h"
49 
50 
51 #define _COMPONENT          ACPI_EXECUTER
52         ACPI_MODULE_NAME    ("exdebug")
53 
54 
55 static ACPI_OPERAND_OBJECT  *AcpiGbl_TraceMethodObject = NULL;
56 
57 /* Local prototypes */
58 
59 #ifdef ACPI_DEBUG_OUTPUT
60 static const char *
61 AcpiExGetTraceEventName (
62     ACPI_TRACE_EVENT_TYPE   Type);
63 #endif
64 
65 
66 #ifndef ACPI_NO_ERROR_MESSAGES
67 /*******************************************************************************
68  *
69  * FUNCTION:    AcpiExDoDebugObject
70  *
71  * PARAMETERS:  SourceDesc          - Object to be output to "Debug Object"
72  *              Level               - Indentation level (used for packages)
73  *              Index               - Current package element, zero if not pkg
74  *
75  * RETURN:      None
76  *
77  * DESCRIPTION: Handles stores to the AML Debug Object. For example:
78  *              Store(INT1, Debug)
79  *
80  * This function is not compiled if ACPI_NO_ERROR_MESSAGES is set.
81  *
82  * This function is only enabled if AcpiGbl_EnableAmlDebugObject is set.
83  * Thus, in the normal operational case, stores to the debug object are
84  * ignored but can be easily enabled if necessary.
85  *
86  ******************************************************************************/
87 
88 void
89 AcpiExDoDebugObject (
90     ACPI_OPERAND_OBJECT     *SourceDesc,
91     UINT32                  Level,
92     UINT32                  Index)
93 {
94     UINT32                  i;
95     UINT32                  Timer;
96     ACPI_OPERAND_OBJECT     *ObjectDesc;
97     UINT32                  Value;
98 
99 
100     ACPI_FUNCTION_TRACE_PTR (ExDoDebugObject, SourceDesc);
101 
102 
103     /* Output must be enabled via the DebugObject global */
104 
105     if (!AcpiGbl_EnableAmlDebugObject)
106     {
107         return_VOID;
108     }
109 
110     /*
111      * We will emit the current timer value (in microseconds) with each
112      * debug output. Only need the lower 26 bits. This allows for 67
113      * million microseconds or 67 seconds before rollover.
114      */
115     Timer = ((UINT32) AcpiOsGetTimer () / 10); /* (100 nanoseconds to microseconds) */
116     Timer &= 0x03FFFFFF;
117 
118     /*
119      * Print line header as long as we are not in the middle of an
120      * object display
121      */
122     if (!((Level > 0) && Index == 0))
123     {
124         AcpiOsPrintf ("[ACPI Debug %.8u] %*s", Timer, Level, " ");
125     }
126 
127     /* Display the index for package output only */
128 
129     if (Index > 0)
130     {
131        AcpiOsPrintf ("(%.2u) ", Index-1);
132     }
133 
134     if (!SourceDesc)
135     {
136         AcpiOsPrintf ("[Null Object]\n");
137         return_VOID;
138     }
139 
140     if (ACPI_GET_DESCRIPTOR_TYPE (SourceDesc) == ACPI_DESC_TYPE_OPERAND)
141     {
142         AcpiOsPrintf ("%s ", AcpiUtGetObjectTypeName (SourceDesc));
143 
144         if (!AcpiUtValidInternalObject (SourceDesc))
145         {
146            AcpiOsPrintf ("%p, Invalid Internal Object!\n", SourceDesc);
147            return_VOID;
148         }
149     }
150     else if (ACPI_GET_DESCRIPTOR_TYPE (SourceDesc) == ACPI_DESC_TYPE_NAMED)
151     {
152         AcpiOsPrintf ("%s: %p\n",
153             AcpiUtGetTypeName (((ACPI_NAMESPACE_NODE *) SourceDesc)->Type),
154             SourceDesc);
155         return_VOID;
156     }
157     else
158     {
159         return_VOID;
160     }
161 
162     /* SourceDesc is of type ACPI_DESC_TYPE_OPERAND */
163 
164     switch (SourceDesc->Common.Type)
165     {
166     case ACPI_TYPE_INTEGER:
167 
168         /* Output correct integer width */
169 
170         if (AcpiGbl_IntegerByteWidth == 4)
171         {
172             AcpiOsPrintf ("0x%8.8X\n",
173                 (UINT32) SourceDesc->Integer.Value);
174         }
175         else
176         {
177             AcpiOsPrintf ("0x%8.8X%8.8X\n",
178                 ACPI_FORMAT_UINT64 (SourceDesc->Integer.Value));
179         }
180         break;
181 
182     case ACPI_TYPE_BUFFER:
183 
184         AcpiOsPrintf ("[0x%.2X]\n", (UINT32) SourceDesc->Buffer.Length);
185         AcpiUtDumpBuffer (SourceDesc->Buffer.Pointer,
186             (SourceDesc->Buffer.Length < 256) ?
187                 SourceDesc->Buffer.Length : 256, DB_BYTE_DISPLAY, 0);
188         break;
189 
190     case ACPI_TYPE_STRING:
191 
192         AcpiOsPrintf ("[0x%.2X] \"%s\"\n",
193             SourceDesc->String.Length, SourceDesc->String.Pointer);
194         break;
195 
196     case ACPI_TYPE_PACKAGE:
197 
198         AcpiOsPrintf ("[Contains 0x%.2X Elements]\n",
199             SourceDesc->Package.Count);
200 
201         /* Output the entire contents of the package */
202 
203         for (i = 0; i < SourceDesc->Package.Count; i++)
204         {
205             AcpiExDoDebugObject (SourceDesc->Package.Elements[i],
206                 Level+4, i+1);
207         }
208         break;
209 
210     case ACPI_TYPE_LOCAL_REFERENCE:
211 
212         AcpiOsPrintf ("[%s] ", AcpiUtGetReferenceName (SourceDesc));
213 
214         /* Decode the reference */
215 
216         switch (SourceDesc->Reference.Class)
217         {
218         case ACPI_REFCLASS_INDEX:
219 
220             AcpiOsPrintf ("0x%X\n", SourceDesc->Reference.Value);
221             break;
222 
223         case ACPI_REFCLASS_TABLE:
224 
225             /* Case for DdbHandle */
226 
227             AcpiOsPrintf ("Table Index 0x%X\n", SourceDesc->Reference.Value);
228             return_VOID;
229 
230         default:
231 
232             break;
233         }
234 
235         AcpiOsPrintf ("  ");
236 
237         /* Check for valid node first, then valid object */
238 
239         if (SourceDesc->Reference.Node)
240         {
241             if (ACPI_GET_DESCRIPTOR_TYPE (SourceDesc->Reference.Node) !=
242                     ACPI_DESC_TYPE_NAMED)
243             {
244                 AcpiOsPrintf (" %p - Not a valid namespace node\n",
245                     SourceDesc->Reference.Node);
246             }
247             else
248             {
249                 AcpiOsPrintf ("Node %p [%4.4s] ", SourceDesc->Reference.Node,
250                     (SourceDesc->Reference.Node)->Name.Ascii);
251 
252                 switch ((SourceDesc->Reference.Node)->Type)
253                 {
254                 /* These types have no attached object */
255 
256                 case ACPI_TYPE_DEVICE:
257                     AcpiOsPrintf ("Device\n");
258                     break;
259 
260                 case ACPI_TYPE_THERMAL:
261                     AcpiOsPrintf ("Thermal Zone\n");
262                     break;
263 
264                 default:
265 
266                     AcpiExDoDebugObject ((SourceDesc->Reference.Node)->Object,
267                         Level+4, 0);
268                     break;
269                 }
270             }
271         }
272         else if (SourceDesc->Reference.Object)
273         {
274             if (ACPI_GET_DESCRIPTOR_TYPE (SourceDesc->Reference.Object) ==
275                     ACPI_DESC_TYPE_NAMED)
276             {
277                 AcpiExDoDebugObject (((ACPI_NAMESPACE_NODE *)
278                     SourceDesc->Reference.Object)->Object,
279                     Level+4, 0);
280             }
281             else
282             {
283                 ObjectDesc = SourceDesc->Reference.Object;
284                 Value = SourceDesc->Reference.Value;
285 
286                 switch (ObjectDesc->Common.Type)
287                 {
288                 case ACPI_TYPE_BUFFER:
289 
290                     AcpiOsPrintf ("Buffer[%u] = 0x%2.2X\n",
291                         Value, *SourceDesc->Reference.IndexPointer);
292                     break;
293 
294                 case ACPI_TYPE_STRING:
295 
296                     AcpiOsPrintf ("String[%u] = \"%c\" (0x%2.2X)\n",
297                         Value, *SourceDesc->Reference.IndexPointer,
298                         *SourceDesc->Reference.IndexPointer);
299                     break;
300 
301                 case ACPI_TYPE_PACKAGE:
302 
303                     AcpiOsPrintf ("Package[%u] = ", Value);
304                     AcpiExDoDebugObject (*SourceDesc->Reference.Where,
305                         Level+4, 0);
306                     break;
307 
308                 default:
309 
310                     AcpiOsPrintf ("Unknown Reference object type %X\n",
311                         ObjectDesc->Common.Type);
312                     break;
313                 }
314             }
315         }
316         break;
317 
318     default:
319 
320         AcpiOsPrintf ("%p\n", SourceDesc);
321         break;
322     }
323 
324     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n"));
325     return_VOID;
326 }
327 #endif
328 
329 
330 /*******************************************************************************
331  *
332  * FUNCTION:    AcpiExInterpreterTraceEnabled
333  *
334  * PARAMETERS:  Name                - Whether method name should be matched,
335  *                                    this should be checked before starting
336  *                                    the tracer
337  *
338  * RETURN:      TRUE if interpreter trace is enabled.
339  *
340  * DESCRIPTION: Check whether interpreter trace is enabled
341  *
342  ******************************************************************************/
343 
344 static BOOLEAN
345 AcpiExInterpreterTraceEnabled (
346     char                    *Name)
347 {
348 
349     /* Check if tracing is enabled */
350 
351     if (!(AcpiGbl_TraceFlags & ACPI_TRACE_ENABLED))
352     {
353         return (FALSE);
354     }
355 
356     /*
357      * Check if tracing is filtered:
358      *
359      * 1. If the tracer is started, AcpiGbl_TraceMethodObject should have
360      *    been filled by the trace starter
361      * 2. If the tracer is not started, AcpiGbl_TraceMethodName should be
362      *    matched if it is specified
363      * 3. If the tracer is oneshot style, AcpiGbl_TraceMethodName should
364      *    not be cleared by the trace stopper during the first match
365      */
366     if (AcpiGbl_TraceMethodObject)
367     {
368         return (TRUE);
369     }
370     if (Name &&
371         (AcpiGbl_TraceMethodName &&
372          strcmp (AcpiGbl_TraceMethodName, Name)))
373     {
374         return (FALSE);
375     }
376     if ((AcpiGbl_TraceFlags & ACPI_TRACE_ONESHOT) &&
377         !AcpiGbl_TraceMethodName)
378     {
379         return (FALSE);
380     }
381 
382     return (TRUE);
383 }
384 
385 
386 /*******************************************************************************
387  *
388  * FUNCTION:    AcpiExGetTraceEventName
389  *
390  * PARAMETERS:  Type            - Trace event type
391  *
392  * RETURN:      Trace event name.
393  *
394  * DESCRIPTION: Used to obtain the full trace event name.
395  *
396  ******************************************************************************/
397 
398 #ifdef ACPI_DEBUG_OUTPUT
399 
400 static const char *
401 AcpiExGetTraceEventName (
402     ACPI_TRACE_EVENT_TYPE   Type)
403 {
404     switch (Type)
405     {
406     case ACPI_TRACE_AML_METHOD:
407 
408         return "Method";
409 
410     case ACPI_TRACE_AML_OPCODE:
411 
412         return "Opcode";
413 
414     case ACPI_TRACE_AML_REGION:
415 
416         return "Region";
417 
418     default:
419 
420         return "";
421     }
422 }
423 
424 #endif
425 
426 
427 /*******************************************************************************
428  *
429  * FUNCTION:    AcpiExTracePoint
430  *
431  * PARAMETERS:  Type                - Trace event type
432  *              Begin               - TRUE if before execution
433  *              Aml                 - Executed AML address
434  *              Pathname            - Object path
435  *
436  * RETURN:      None
437  *
438  * DESCRIPTION: Internal interpreter execution trace.
439  *
440  ******************************************************************************/
441 
442 void
443 AcpiExTracePoint (
444     ACPI_TRACE_EVENT_TYPE   Type,
445     BOOLEAN                 Begin,
446     UINT8                   *Aml,
447     char                    *Pathname)
448 {
449 
450     ACPI_FUNCTION_NAME (ExTracePoint);
451 
452 
453     if (Pathname)
454     {
455         ACPI_DEBUG_PRINT ((ACPI_DB_TRACE_POINT,
456                 "%s %s [0x%p:%s] execution.\n",
457                 AcpiExGetTraceEventName (Type), Begin ? "Begin" : "End",
458                 Aml, Pathname));
459     }
460     else
461     {
462         ACPI_DEBUG_PRINT ((ACPI_DB_TRACE_POINT,
463                 "%s %s [0x%p] execution.\n",
464                 AcpiExGetTraceEventName (Type), Begin ? "Begin" : "End",
465                 Aml));
466     }
467 }
468 
469 
470 /*******************************************************************************
471  *
472  * FUNCTION:    AcpiExStartTraceMethod
473  *
474  * PARAMETERS:  MethodNode          - Node of the method
475  *              ObjDesc             - The method object
476  *              WalkState           - current state, NULL if not yet executing
477  *                                    a method.
478  *
479  * RETURN:      None
480  *
481  * DESCRIPTION: Start control method execution trace
482  *
483  ******************************************************************************/
484 
485 void
486 AcpiExStartTraceMethod (
487     ACPI_NAMESPACE_NODE     *MethodNode,
488     ACPI_OPERAND_OBJECT     *ObjDesc,
489     ACPI_WALK_STATE         *WalkState)
490 {
491     ACPI_STATUS             Status;
492     char                    *Pathname = NULL;
493     BOOLEAN                 Enabled = FALSE;
494 
495 
496     ACPI_FUNCTION_NAME (ExStartTraceMethod);
497 
498 
499     if (MethodNode)
500     {
501         Pathname = AcpiNsGetNormalizedPathname (MethodNode, TRUE);
502     }
503 
504     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
505     if (ACPI_FAILURE (Status))
506     {
507         goto Exit;
508     }
509 
510     Enabled = AcpiExInterpreterTraceEnabled (Pathname);
511     if (Enabled && !AcpiGbl_TraceMethodObject)
512     {
513         AcpiGbl_TraceMethodObject = ObjDesc;
514         AcpiGbl_OriginalDbgLevel = AcpiDbgLevel;
515         AcpiGbl_OriginalDbgLayer = AcpiDbgLayer;
516         AcpiDbgLevel = ACPI_TRACE_LEVEL_ALL;
517         AcpiDbgLayer = ACPI_TRACE_LAYER_ALL;
518 
519         if (AcpiGbl_TraceDbgLevel)
520         {
521             AcpiDbgLevel = AcpiGbl_TraceDbgLevel;
522         }
523         if (AcpiGbl_TraceDbgLayer)
524         {
525             AcpiDbgLayer = AcpiGbl_TraceDbgLayer;
526         }
527     }
528     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
529 
530 Exit:
531     if (Enabled)
532     {
533         ACPI_TRACE_POINT (ACPI_TRACE_AML_METHOD, TRUE,
534                 ObjDesc ? ObjDesc->Method.AmlStart : NULL, Pathname);
535     }
536     if (Pathname)
537     {
538         ACPI_FREE (Pathname);
539     }
540 }
541 
542 
543 /*******************************************************************************
544  *
545  * FUNCTION:    AcpiExStopTraceMethod
546  *
547  * PARAMETERS:  MethodNode          - Node of the method
548  *              ObjDesc             - The method object
549  *              WalkState           - current state, NULL if not yet executing
550  *                                    a method.
551  *
552  * RETURN:      None
553  *
554  * DESCRIPTION: Stop control method execution trace
555  *
556  ******************************************************************************/
557 
558 void
559 AcpiExStopTraceMethod (
560     ACPI_NAMESPACE_NODE     *MethodNode,
561     ACPI_OPERAND_OBJECT     *ObjDesc,
562     ACPI_WALK_STATE         *WalkState)
563 {
564     ACPI_STATUS             Status;
565     char                    *Pathname = NULL;
566     BOOLEAN                 Enabled;
567 
568 
569     ACPI_FUNCTION_NAME (ExStopTraceMethod);
570 
571 
572     if (MethodNode)
573     {
574         Pathname = AcpiNsGetNormalizedPathname (MethodNode, TRUE);
575     }
576 
577     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
578     if (ACPI_FAILURE (Status))
579     {
580         goto ExitPath;
581     }
582 
583     Enabled = AcpiExInterpreterTraceEnabled (NULL);
584 
585     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
586 
587     if (Enabled)
588     {
589         ACPI_TRACE_POINT (ACPI_TRACE_AML_METHOD, FALSE,
590                 ObjDesc ? ObjDesc->Method.AmlStart : NULL, Pathname);
591     }
592 
593     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
594     if (ACPI_FAILURE (Status))
595     {
596         goto ExitPath;
597     }
598 
599     /* Check whether the tracer should be stopped */
600 
601     if (AcpiGbl_TraceMethodObject == ObjDesc)
602     {
603         /* Disable further tracing if type is one-shot */
604 
605         if (AcpiGbl_TraceFlags & ACPI_TRACE_ONESHOT)
606         {
607             AcpiGbl_TraceMethodName = NULL;
608         }
609 
610         AcpiDbgLevel = AcpiGbl_OriginalDbgLevel;
611         AcpiDbgLayer = AcpiGbl_OriginalDbgLayer;
612         AcpiGbl_TraceMethodObject = NULL;
613     }
614 
615     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
616 
617 ExitPath:
618     if (Pathname)
619     {
620         ACPI_FREE (Pathname);
621     }
622 }
623 
624 
625 /*******************************************************************************
626  *
627  * FUNCTION:    AcpiExStartTraceOpcode
628  *
629  * PARAMETERS:  Op                  - The parser opcode object
630  *              WalkState           - current state, NULL if not yet executing
631  *                                    a method.
632  *
633  * RETURN:      None
634  *
635  * DESCRIPTION: Start opcode execution trace
636  *
637  ******************************************************************************/
638 
639 void
640 AcpiExStartTraceOpcode (
641     ACPI_PARSE_OBJECT       *Op,
642     ACPI_WALK_STATE         *WalkState)
643 {
644 
645     ACPI_FUNCTION_NAME (ExStartTraceOpcode);
646 
647 
648     if (AcpiExInterpreterTraceEnabled (NULL) &&
649         (AcpiGbl_TraceFlags & ACPI_TRACE_OPCODE))
650     {
651         ACPI_TRACE_POINT (ACPI_TRACE_AML_OPCODE, TRUE,
652                 Op->Common.Aml, Op->Common.AmlOpName);
653     }
654 }
655 
656 
657 /*******************************************************************************
658  *
659  * FUNCTION:    AcpiExStopTraceOpcode
660  *
661  * PARAMETERS:  Op                  - The parser opcode object
662  *              WalkState           - current state, NULL if not yet executing
663  *                                    a method.
664  *
665  * RETURN:      None
666  *
667  * DESCRIPTION: Stop opcode execution trace
668  *
669  ******************************************************************************/
670 
671 void
672 AcpiExStopTraceOpcode (
673     ACPI_PARSE_OBJECT       *Op,
674     ACPI_WALK_STATE         *WalkState)
675 {
676 
677     ACPI_FUNCTION_NAME (ExStopTraceOpcode);
678 
679 
680     if (AcpiExInterpreterTraceEnabled (NULL) &&
681         (AcpiGbl_TraceFlags & ACPI_TRACE_OPCODE))
682     {
683         ACPI_TRACE_POINT (ACPI_TRACE_AML_OPCODE, FALSE,
684                 Op->Common.Aml, Op->Common.AmlOpName);
685     }
686 }
687