xref: /netbsd-src/sys/external/bsd/acpica/dist/debugger/dbmethod.c (revision 2c7d7e3ca2e4f0b675c6c58e614f6aede66c678e)
1 /*******************************************************************************
2  *
3  * Module Name: dbmethod - Debug commands for control methods
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 "acpi.h"
45 #include "accommon.h"
46 #include "acdispat.h"
47 #include "acnamesp.h"
48 #include "acdebug.h"
49 #include "acparser.h"
50 #include "acpredef.h"
51 
52 
53 #define _COMPONENT          ACPI_CA_DEBUGGER
54         ACPI_MODULE_NAME    ("dbmethod")
55 
56 /* Local prototypes */
57 
58 static ACPI_STATUS
59 AcpiDbWalkForExecute (
60     ACPI_HANDLE             ObjHandle,
61     UINT32                  NestingLevel,
62     void                    *Context,
63     void                    **ReturnValue);
64 
65 static ACPI_STATUS
66 AcpiDbEvaluateObject (
67     ACPI_NAMESPACE_NODE     *Node);
68 
69 
70 /*******************************************************************************
71  *
72  * FUNCTION:    AcpiDbSetMethodBreakpoint
73  *
74  * PARAMETERS:  Location            - AML offset of breakpoint
75  *              WalkState           - Current walk info
76  *              Op                  - Current Op (from parse walk)
77  *
78  * RETURN:      None
79  *
80  * DESCRIPTION: Set a breakpoint in a control method at the specified
81  *              AML offset
82  *
83  ******************************************************************************/
84 
85 void
AcpiDbSetMethodBreakpoint(char * Location,ACPI_WALK_STATE * WalkState,ACPI_PARSE_OBJECT * Op)86 AcpiDbSetMethodBreakpoint (
87     char                    *Location,
88     ACPI_WALK_STATE         *WalkState,
89     ACPI_PARSE_OBJECT       *Op)
90 {
91     UINT32                  Address;
92     UINT32                  AmlOffset;
93 
94 
95     if (!Op)
96     {
97         AcpiOsPrintf ("There is no method currently executing\n");
98         return;
99     }
100 
101     /* Get and verify the breakpoint address */
102 
103     Address = strtoul (Location, NULL, 16);
104     AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml,
105         WalkState->ParserState.AmlStart);
106     if (Address <= AmlOffset)
107     {
108         AcpiOsPrintf ("Breakpoint %X is beyond current address %X\n",
109             Address, AmlOffset);
110     }
111 
112     /* Save breakpoint in current walk */
113 
114     WalkState->UserBreakpoint = Address;
115     AcpiOsPrintf ("Breakpoint set at AML offset %X\n", Address);
116 }
117 
118 
119 /*******************************************************************************
120  *
121  * FUNCTION:    AcpiDbSetMethodCallBreakpoint
122  *
123  * PARAMETERS:  Op                  - Current Op (from parse walk)
124  *
125  * RETURN:      None
126  *
127  * DESCRIPTION: Set a breakpoint in a control method at the specified
128  *              AML offset
129  *
130  ******************************************************************************/
131 
132 void
AcpiDbSetMethodCallBreakpoint(ACPI_PARSE_OBJECT * Op)133 AcpiDbSetMethodCallBreakpoint (
134     ACPI_PARSE_OBJECT       *Op)
135 {
136 
137 
138     if (!Op)
139     {
140         AcpiOsPrintf ("There is no method currently executing\n");
141         return;
142     }
143 
144     AcpiGbl_StepToNextCall = TRUE;
145 }
146 
147 
148 /*******************************************************************************
149  *
150  * FUNCTION:    AcpiDbSetMethodData
151  *
152  * PARAMETERS:  TypeArg         - L for local, A for argument
153  *              IndexArg        - which one
154  *              ValueArg        - Value to set.
155  *
156  * RETURN:      None
157  *
158  * DESCRIPTION: Set a local or argument for the running control method.
159  *              NOTE: only object supported is Number.
160  *
161  ******************************************************************************/
162 
163 void
AcpiDbSetMethodData(char * TypeArg,char * IndexArg,char * ValueArg)164 AcpiDbSetMethodData (
165     char                    *TypeArg,
166     char                    *IndexArg,
167     char                    *ValueArg)
168 {
169     char                    Type;
170     UINT32                  Index;
171     UINT32                  Value;
172     ACPI_WALK_STATE         *WalkState;
173     ACPI_OPERAND_OBJECT     *ObjDesc;
174     ACPI_STATUS             Status;
175     ACPI_NAMESPACE_NODE     *Node;
176 
177 
178     /* Validate TypeArg */
179 
180     AcpiUtStrupr (TypeArg);
181     Type = TypeArg[0];
182     if ((Type != 'L') &&
183         (Type != 'A') &&
184         (Type != 'N'))
185     {
186         AcpiOsPrintf ("Invalid SET operand: %s\n", TypeArg);
187         return;
188     }
189 
190     Value = strtoul (ValueArg, NULL, 16);
191 
192     if (Type == 'N')
193     {
194         Node = AcpiDbConvertToNode (IndexArg);
195         if (!Node)
196         {
197             return;
198         }
199 
200         if (Node->Type != ACPI_TYPE_INTEGER)
201         {
202             AcpiOsPrintf ("Can only set Integer nodes\n");
203             return;
204         }
205         ObjDesc = Node->Object;
206         ObjDesc->Integer.Value = Value;
207         return;
208     }
209 
210     /* Get the index and value */
211 
212     Index = strtoul (IndexArg, NULL, 16);
213 
214     WalkState = AcpiDsGetCurrentWalkState (AcpiGbl_CurrentWalkList);
215     if (!WalkState)
216     {
217         AcpiOsPrintf ("There is no method currently executing\n");
218         return;
219     }
220 
221     /* Create and initialize the new object */
222 
223     ObjDesc = AcpiUtCreateIntegerObject ((UINT64) Value);
224     if (!ObjDesc)
225     {
226         AcpiOsPrintf ("Could not create an internal object\n");
227         return;
228     }
229 
230     /* Store the new object into the target */
231 
232     switch (Type)
233     {
234     case 'A':
235 
236         /* Set a method argument */
237 
238         if (Index > ACPI_METHOD_MAX_ARG)
239         {
240             AcpiOsPrintf ("Arg%u - Invalid argument name\n",
241                 Index);
242             goto Cleanup;
243         }
244 
245         Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_ARG,
246             Index, ObjDesc, WalkState);
247         if (ACPI_FAILURE (Status))
248         {
249             goto Cleanup;
250         }
251 
252         ObjDesc = WalkState->Arguments[Index].Object;
253 
254         AcpiOsPrintf ("Arg%u: ", Index);
255         AcpiDbDisplayInternalObject (ObjDesc, WalkState);
256         break;
257 
258     case 'L':
259 
260         /* Set a method local */
261 
262         if (Index > ACPI_METHOD_MAX_LOCAL)
263         {
264             AcpiOsPrintf ("Local%u - Invalid local variable name\n",
265                 Index);
266             goto Cleanup;
267         }
268 
269         Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_LOCAL,
270             Index, ObjDesc, WalkState);
271         if (ACPI_FAILURE (Status))
272         {
273             goto Cleanup;
274         }
275 
276         ObjDesc = WalkState->LocalVariables[Index].Object;
277 
278         AcpiOsPrintf ("Local%u: ", Index);
279         AcpiDbDisplayInternalObject (ObjDesc, WalkState);
280         break;
281 
282     default:
283 
284         break;
285     }
286 
287 Cleanup:
288     AcpiUtRemoveReference (ObjDesc);
289 }
290 
291 
292 #ifdef ACPI_DISASSEMBLER
293 /*******************************************************************************
294  *
295  * FUNCTION:    AcpiDbDisassembleAml
296  *
297  * PARAMETERS:  Statements          - Number of statements to disassemble
298  *              Op                  - Current Op (from parse walk)
299  *
300  * RETURN:      None
301  *
302  * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
303  *              of statements specified.
304  *
305  ******************************************************************************/
306 
307 void
AcpiDbDisassembleAml(char * Statements,ACPI_PARSE_OBJECT * Op)308 AcpiDbDisassembleAml (
309     char                    *Statements,
310     ACPI_PARSE_OBJECT       *Op)
311 {
312     UINT32                  NumStatements = 8;
313 
314 
315     if (!Op)
316     {
317         AcpiOsPrintf ("There is no method currently executing\n");
318         return;
319     }
320 
321     if (Statements)
322     {
323         NumStatements = strtoul (Statements, NULL, 0);
324     }
325 
326     AcpiDmDisassemble (NULL, Op, NumStatements);
327 }
328 
329 
330 /*******************************************************************************
331  *
332  * FUNCTION:    AcpiDbDisassembleMethod
333  *
334  * PARAMETERS:  Name            - Name of control method
335  *
336  * RETURN:      None
337  *
338  * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
339  *              of statements specified.
340  *
341  ******************************************************************************/
342 
343 ACPI_STATUS
AcpiDbDisassembleMethod(char * Name)344 AcpiDbDisassembleMethod (
345     char                    *Name)
346 {
347     ACPI_STATUS             Status;
348     ACPI_PARSE_OBJECT       *Op;
349     ACPI_WALK_STATE         *WalkState;
350     ACPI_OPERAND_OBJECT     *ObjDesc;
351     ACPI_NAMESPACE_NODE     *Method;
352 
353 
354     Method = AcpiDbConvertToNode (Name);
355     if (!Method)
356     {
357         return (AE_BAD_PARAMETER);
358     }
359 
360     if (Method->Type != ACPI_TYPE_METHOD)
361     {
362         ACPI_ERROR ((AE_INFO, "%s (%s): Object must be a control method",
363             Name, AcpiUtGetTypeName (Method->Type)));
364         return (AE_BAD_PARAMETER);
365     }
366 
367     ObjDesc = Method->Object;
368 
369     Op = AcpiPsCreateScopeOp (ObjDesc->Method.AmlStart);
370     if (!Op)
371     {
372         return (AE_NO_MEMORY);
373     }
374 
375     /* Create and initialize a new walk state */
376 
377     WalkState = AcpiDsCreateWalkState (0, Op, NULL, NULL);
378     if (!WalkState)
379     {
380         return (AE_NO_MEMORY);
381     }
382 
383     Status = AcpiDsInitAmlWalk (WalkState, Op, NULL,
384         ObjDesc->Method.AmlStart,
385         ObjDesc->Method.AmlLength, NULL, ACPI_IMODE_LOAD_PASS1);
386     if (ACPI_FAILURE (Status))
387     {
388         return (Status);
389     }
390 
391     Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
392     if (ACPI_FAILURE(Status))
393     {
394         return (Status);
395     }
396 
397     WalkState->OwnerId = ObjDesc->Method.OwnerId;
398 
399     /* Push start scope on scope stack and make it current */
400 
401     Status = AcpiDsScopeStackPush (Method,
402         Method->Type, WalkState);
403     if (ACPI_FAILURE (Status))
404     {
405         return (Status);
406     }
407 
408     /* Parse the entire method AML including deferred operators */
409 
410     WalkState->ParseFlags &= ~ACPI_PARSE_DELETE_TREE;
411     WalkState->ParseFlags |= ACPI_PARSE_DISASSEMBLE;
412 
413     Status = AcpiPsParseAml (WalkState);
414     if (ACPI_FAILURE(Status))
415     {
416         return (Status);
417     }
418 
419     (void) AcpiDmParseDeferredOps (Op);
420 
421     /* Now we can disassemble the method */
422 
423     AcpiGbl_DmOpt_Verbose = FALSE;
424     AcpiDmDisassemble (NULL, Op, 0);
425     AcpiGbl_DmOpt_Verbose = TRUE;
426 
427     AcpiPsDeleteParseTree (Op);
428 
429     /* Method cleanup */
430 
431     AcpiNsDeleteNamespaceSubtree (Method);
432     AcpiNsDeleteNamespaceByOwner (ObjDesc->Method.OwnerId);
433     AcpiUtReleaseOwnerId (&ObjDesc->Method.OwnerId);
434     return (AE_OK);
435 }
436 #endif
437 
438 
439 /*******************************************************************************
440  *
441  * FUNCTION:    AcpiDbEvaluateObject
442  *
443  * PARAMETERS:  Node                - Namespace node for the object
444  *
445  * RETURN:      Status
446  *
447  * DESCRIPTION: Main execution function for the Evaluate/Execute/All debugger
448  *              commands.
449  *
450  ******************************************************************************/
451 
452 static ACPI_STATUS
AcpiDbEvaluateObject(ACPI_NAMESPACE_NODE * Node)453 AcpiDbEvaluateObject (
454     ACPI_NAMESPACE_NODE     *Node)
455 {
456     char                    *Pathname;
457     UINT32                  i;
458     ACPI_DEVICE_INFO        *ObjInfo;
459     ACPI_OBJECT_LIST        ParamObjects;
460     ACPI_OBJECT             Params[ACPI_METHOD_NUM_ARGS];
461     ACPI_BUFFER             ReturnObj;
462     ACPI_STATUS             Status;
463 
464 
465     Pathname = AcpiNsGetExternalPathname (Node);
466     if (!Pathname)
467     {
468         return (AE_OK);
469     }
470 
471     /* Get the object info for number of method parameters */
472 
473     Status = AcpiGetObjectInfo (Node, &ObjInfo);
474     if (ACPI_FAILURE (Status))
475     {
476         ACPI_FREE (Pathname);
477         return (Status);
478     }
479 
480     ParamObjects.Pointer = NULL;
481     ParamObjects.Count   = 0;
482 
483     if (ObjInfo->Type == ACPI_TYPE_METHOD)
484     {
485         /* Setup default parameters */
486 
487         for (i = 0; i < ObjInfo->ParamCount; i++)
488         {
489             Params[i].Type           = ACPI_TYPE_INTEGER;
490             Params[i].Integer.Value  = 1;
491         }
492 
493         ParamObjects.Pointer     = Params;
494         ParamObjects.Count       = ObjInfo->ParamCount;
495     }
496 
497     ACPI_FREE (ObjInfo);
498     ReturnObj.Pointer = NULL;
499     ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
500 
501     /* Do the actual method execution */
502 
503     AcpiGbl_MethodExecuting = TRUE;
504 
505     Status = AcpiEvaluateObject (Node, NULL, &ParamObjects, &ReturnObj);
506     AcpiGbl_MethodExecuting = FALSE;
507 
508     AcpiOsPrintf ("%-32s returned %s\n", Pathname, AcpiFormatException (Status));
509     if (ReturnObj.Length)
510     {
511         AcpiOsPrintf ("Evaluation of %s returned object %p, "
512             "external buffer length %X\n",
513             Pathname, ReturnObj.Pointer, (UINT32) ReturnObj.Length);
514 
515         AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
516         AcpiOsPrintf ("\n");
517     }
518 
519     ACPI_FREE (Pathname);
520 
521     /* Ignore status from method execution */
522 
523     return (AE_OK);
524 
525     /* Update count, check if we have executed enough methods */
526 
527 }
528 
529 /*******************************************************************************
530  *
531  * FUNCTION:    AcpiDbWalkForExecute
532  *
533  * PARAMETERS:  Callback from WalkNamespace
534  *
535  * RETURN:      Status
536  *
537  * DESCRIPTION: Batch execution function. Evaluates all "predefined" objects --
538  *              the nameseg begins with an underscore.
539  *
540  ******************************************************************************/
541 
542 static ACPI_STATUS
AcpiDbWalkForExecute(ACPI_HANDLE ObjHandle,UINT32 NestingLevel,void * Context,void ** ReturnValue)543 AcpiDbWalkForExecute (
544     ACPI_HANDLE             ObjHandle,
545     UINT32                  NestingLevel,
546     void                    *Context,
547     void                    **ReturnValue)
548 {
549     ACPI_NAMESPACE_NODE     *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
550     ACPI_DB_EXECUTE_WALK    *Info = (ACPI_DB_EXECUTE_WALK *) Context;
551     ACPI_STATUS             Status;
552     const ACPI_PREDEFINED_INFO *Predefined;
553 
554 
555     Predefined = AcpiUtMatchPredefinedMethod (Node->Name.Ascii);
556     if (!Predefined)
557     {
558         return (AE_OK);
559     }
560 
561     if (Node->Type == ACPI_TYPE_LOCAL_SCOPE)
562     {
563         return (AE_OK);
564     }
565 
566     AcpiDbEvaluateObject (Node);
567 
568     /* Ignore status from object evaluation */
569 
570     Status = AE_OK;
571 
572     /* Update count, check if we have executed enough methods */
573 
574     Info->Count++;
575     if (Info->Count >= Info->MaxCount)
576     {
577         Status = AE_CTRL_TERMINATE;
578     }
579 
580     return (Status);
581 }
582 
583 
584 /*******************************************************************************
585  *
586  * FUNCTION:    AcpiDbWalkForExecuteAll
587  *
588  * PARAMETERS:  Callback from WalkNamespace
589  *
590  * RETURN:      Status
591  *
592  * DESCRIPTION: Batch execution function. Evaluates all objects whose path ends
593  *              with the nameseg "Info->NameSeg". Used for the "ALL" command.
594  *
595  ******************************************************************************/
596 
597 static ACPI_STATUS
AcpiDbWalkForExecuteAll(ACPI_HANDLE ObjHandle,UINT32 NestingLevel,void * Context,void ** ReturnValue)598 AcpiDbWalkForExecuteAll (
599     ACPI_HANDLE             ObjHandle,
600     UINT32                  NestingLevel,
601     void                    *Context,
602     void                    **ReturnValue)
603 {
604     ACPI_NAMESPACE_NODE     *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
605     ACPI_DB_EXECUTE_WALK    *Info = (ACPI_DB_EXECUTE_WALK *) Context;
606     ACPI_STATUS             Status;
607 
608 
609     if (!ACPI_COMPARE_NAMESEG (Node->Name.Ascii, Info->NameSeg))
610     {
611         return (AE_OK);
612     }
613 
614     if (Node->Type == ACPI_TYPE_LOCAL_SCOPE)
615     {
616         return (AE_OK);
617     }
618 
619     /* Now evaluate the input object (node) */
620 
621     AcpiDbEvaluateObject (Node);
622 
623     /* Ignore status from method execution */
624 
625     Status = AE_OK;
626 
627     /* Update count of executed methods/objects */
628 
629     Info->Count++;
630     return (Status);
631 }
632 
633 
634 /*******************************************************************************
635  *
636  * FUNCTION:    AcpiDbEvaluatePredefinedNames
637  *
638  * PARAMETERS:  None
639  *
640  * RETURN:      None
641  *
642  * DESCRIPTION: Namespace batch execution. Execute predefined names in the
643  *              namespace, up to the max count, if specified.
644  *
645  ******************************************************************************/
646 
647 void
AcpiDbEvaluatePredefinedNames(void)648 AcpiDbEvaluatePredefinedNames (
649     void)
650 {
651     ACPI_DB_EXECUTE_WALK    Info;
652 
653 
654     Info.Count = 0;
655     Info.MaxCount = ACPI_UINT32_MAX;
656 
657     /* Search all nodes in namespace */
658 
659     (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
660                 AcpiDbWalkForExecute, NULL, (void *) &Info, NULL);
661 
662     AcpiOsPrintf ("Evaluated %u predefined names in the namespace\n", Info.Count);
663 }
664 
665 
666 /*******************************************************************************
667  *
668  * FUNCTION:    AcpiDbEvaluateAll
669  *
670  * PARAMETERS:  NoneAcpiGbl_DbMethodInfo
671  *
672  * RETURN:      None
673  *
674  * DESCRIPTION: Namespace batch execution. Implements the "ALL" command.
675  *              Execute all namepaths whose final nameseg matches the
676  *              input nameseg.
677  *
678  ******************************************************************************/
679 
680 void
AcpiDbEvaluateAll(char * NameSeg)681 AcpiDbEvaluateAll (
682     char                    *NameSeg)
683 {
684     ACPI_DB_EXECUTE_WALK    Info;
685 
686 
687     Info.Count = 0;
688     Info.MaxCount = ACPI_UINT32_MAX;
689     ACPI_COPY_NAMESEG (Info.NameSeg, NameSeg);
690     Info.NameSeg[ACPI_NAMESEG_SIZE] = 0;
691 
692     /* Search all nodes in namespace */
693 
694     (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
695                 AcpiDbWalkForExecuteAll, NULL, (void *) &Info, NULL);
696 
697     AcpiOsPrintf ("Evaluated %u names in the namespace\n", Info.Count);
698 }
699