xref: /freebsd/sys/contrib/dev/acpica/components/debugger/dbmethod.c (revision 0b3105a37d7adcadcb720112fed4dc4e8040be99)
1 /*******************************************************************************
2  *
3  * Module Name: dbmethod - Debug commands for control methods
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 <contrib/dev/acpica/include/acpi.h>
45 #include <contrib/dev/acpica/include/accommon.h>
46 #include <contrib/dev/acpica/include/acdispat.h>
47 #include <contrib/dev/acpica/include/acnamesp.h>
48 #include <contrib/dev/acpica/include/acdebug.h>
49 #include <contrib/dev/acpica/include/acparser.h>
50 #include <contrib/dev/acpica/include/acpredef.h>
51 
52 
53 #define _COMPONENT          ACPI_CA_DEBUGGER
54         ACPI_MODULE_NAME    ("dbmethod")
55 
56 
57 /*******************************************************************************
58  *
59  * FUNCTION:    AcpiDbSetMethodBreakpoint
60  *
61  * PARAMETERS:  Location            - AML offset of breakpoint
62  *              WalkState           - Current walk info
63  *              Op                  - Current Op (from parse walk)
64  *
65  * RETURN:      None
66  *
67  * DESCRIPTION: Set a breakpoint in a control method at the specified
68  *              AML offset
69  *
70  ******************************************************************************/
71 
72 void
73 AcpiDbSetMethodBreakpoint (
74     char                    *Location,
75     ACPI_WALK_STATE         *WalkState,
76     ACPI_PARSE_OBJECT       *Op)
77 {
78     UINT32                  Address;
79     UINT32                  AmlOffset;
80 
81 
82     if (!Op)
83     {
84         AcpiOsPrintf ("There is no method currently executing\n");
85         return;
86     }
87 
88     /* Get and verify the breakpoint address */
89 
90     Address = strtoul (Location, NULL, 16);
91     AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml,
92                     WalkState->ParserState.AmlStart);
93     if (Address <= AmlOffset)
94     {
95         AcpiOsPrintf ("Breakpoint %X is beyond current address %X\n",
96             Address, AmlOffset);
97     }
98 
99     /* Save breakpoint in current walk */
100 
101     WalkState->UserBreakpoint = Address;
102     AcpiOsPrintf ("Breakpoint set at AML offset %X\n", Address);
103 }
104 
105 
106 /*******************************************************************************
107  *
108  * FUNCTION:    AcpiDbSetMethodCallBreakpoint
109  *
110  * PARAMETERS:  Op                  - Current Op (from parse walk)
111  *
112  * RETURN:      None
113  *
114  * DESCRIPTION: Set a breakpoint in a control method at the specified
115  *              AML offset
116  *
117  ******************************************************************************/
118 
119 void
120 AcpiDbSetMethodCallBreakpoint (
121     ACPI_PARSE_OBJECT       *Op)
122 {
123 
124 
125     if (!Op)
126     {
127         AcpiOsPrintf ("There is no method currently executing\n");
128         return;
129     }
130 
131     AcpiGbl_StepToNextCall = TRUE;
132 }
133 
134 
135 /*******************************************************************************
136  *
137  * FUNCTION:    AcpiDbSetMethodData
138  *
139  * PARAMETERS:  TypeArg         - L for local, A for argument
140  *              IndexArg        - which one
141  *              ValueArg        - Value to set.
142  *
143  * RETURN:      None
144  *
145  * DESCRIPTION: Set a local or argument for the running control method.
146  *              NOTE: only object supported is Number.
147  *
148  ******************************************************************************/
149 
150 void
151 AcpiDbSetMethodData (
152     char                    *TypeArg,
153     char                    *IndexArg,
154     char                    *ValueArg)
155 {
156     char                    Type;
157     UINT32                  Index;
158     UINT32                  Value;
159     ACPI_WALK_STATE         *WalkState;
160     ACPI_OPERAND_OBJECT     *ObjDesc;
161     ACPI_STATUS             Status;
162     ACPI_NAMESPACE_NODE     *Node;
163 
164 
165     /* Validate TypeArg */
166 
167     AcpiUtStrupr (TypeArg);
168     Type = TypeArg[0];
169     if ((Type != 'L') &&
170         (Type != 'A') &&
171         (Type != 'N'))
172     {
173         AcpiOsPrintf ("Invalid SET operand: %s\n", TypeArg);
174         return;
175     }
176 
177     Value = strtoul (ValueArg, NULL, 16);
178 
179     if (Type == 'N')
180     {
181         Node = AcpiDbConvertToNode (IndexArg);
182         if (!Node)
183         {
184             return;
185         }
186 
187         if (Node->Type != ACPI_TYPE_INTEGER)
188         {
189             AcpiOsPrintf ("Can only set Integer nodes\n");
190             return;
191         }
192         ObjDesc = Node->Object;
193         ObjDesc->Integer.Value = Value;
194         return;
195     }
196 
197     /* Get the index and value */
198 
199     Index = strtoul (IndexArg, NULL, 16);
200 
201     WalkState = AcpiDsGetCurrentWalkState (AcpiGbl_CurrentWalkList);
202     if (!WalkState)
203     {
204         AcpiOsPrintf ("There is no method currently executing\n");
205         return;
206     }
207 
208     /* Create and initialize the new object */
209 
210     ObjDesc = AcpiUtCreateIntegerObject ((UINT64) Value);
211     if (!ObjDesc)
212     {
213         AcpiOsPrintf ("Could not create an internal object\n");
214         return;
215     }
216 
217     /* Store the new object into the target */
218 
219     switch (Type)
220     {
221     case 'A':
222 
223         /* Set a method argument */
224 
225         if (Index > ACPI_METHOD_MAX_ARG)
226         {
227             AcpiOsPrintf ("Arg%u - Invalid argument name\n",
228                 Index);
229             goto Cleanup;
230         }
231 
232         Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_ARG,
233             Index, ObjDesc, WalkState);
234         if (ACPI_FAILURE (Status))
235         {
236             goto Cleanup;
237         }
238 
239         ObjDesc = WalkState->Arguments[Index].Object;
240 
241         AcpiOsPrintf ("Arg%u: ", Index);
242         AcpiDbDisplayInternalObject (ObjDesc, WalkState);
243         break;
244 
245     case 'L':
246 
247         /* Set a method local */
248 
249         if (Index > ACPI_METHOD_MAX_LOCAL)
250         {
251             AcpiOsPrintf ("Local%u - Invalid local variable name\n",
252                 Index);
253             goto Cleanup;
254         }
255 
256         Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_LOCAL,
257             Index, ObjDesc, WalkState);
258         if (ACPI_FAILURE (Status))
259         {
260             goto Cleanup;
261         }
262 
263         ObjDesc = WalkState->LocalVariables[Index].Object;
264 
265         AcpiOsPrintf ("Local%u: ", Index);
266         AcpiDbDisplayInternalObject (ObjDesc, WalkState);
267         break;
268 
269     default:
270 
271         break;
272     }
273 
274 Cleanup:
275     AcpiUtRemoveReference (ObjDesc);
276 }
277 
278 
279 /*******************************************************************************
280  *
281  * FUNCTION:    AcpiDbDisassembleAml
282  *
283  * PARAMETERS:  Statements          - Number of statements to disassemble
284  *              Op                  - Current Op (from parse walk)
285  *
286  * RETURN:      None
287  *
288  * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
289  *              of statements specified.
290  *
291  ******************************************************************************/
292 
293 void
294 AcpiDbDisassembleAml (
295     char                    *Statements,
296     ACPI_PARSE_OBJECT       *Op)
297 {
298     UINT32                  NumStatements = 8;
299 
300 
301     if (!Op)
302     {
303         AcpiOsPrintf ("There is no method currently executing\n");
304         return;
305     }
306 
307     if (Statements)
308     {
309         NumStatements = strtoul (Statements, NULL, 0);
310     }
311 
312 #ifdef ACPI_DISASSEMBLER
313     AcpiDmDisassemble (NULL, Op, NumStatements);
314 #endif
315 }
316 
317 
318 /*******************************************************************************
319  *
320  * FUNCTION:    AcpiDbDisassembleMethod
321  *
322  * PARAMETERS:  Name            - Name of control method
323  *
324  * RETURN:      None
325  *
326  * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
327  *              of statements specified.
328  *
329  ******************************************************************************/
330 
331 ACPI_STATUS
332 AcpiDbDisassembleMethod (
333     char                    *Name)
334 {
335     ACPI_STATUS             Status;
336     ACPI_PARSE_OBJECT       *Op;
337     ACPI_WALK_STATE         *WalkState;
338     ACPI_OPERAND_OBJECT     *ObjDesc;
339     ACPI_NAMESPACE_NODE     *Method;
340 
341 
342     Method = AcpiDbConvertToNode (Name);
343     if (!Method)
344     {
345         return (AE_BAD_PARAMETER);
346     }
347 
348     if (Method->Type != ACPI_TYPE_METHOD)
349     {
350         ACPI_ERROR ((AE_INFO, "%s (%s): Object must be a control method",
351             Name, AcpiUtGetTypeName (Method->Type)));
352         return (AE_BAD_PARAMETER);
353     }
354 
355     ObjDesc = Method->Object;
356 
357     Op = AcpiPsCreateScopeOp (ObjDesc->Method.AmlStart);
358     if (!Op)
359     {
360         return (AE_NO_MEMORY);
361     }
362 
363     /* Create and initialize a new walk state */
364 
365     WalkState = AcpiDsCreateWalkState (0, Op, NULL, NULL);
366     if (!WalkState)
367     {
368         return (AE_NO_MEMORY);
369     }
370 
371     Status = AcpiDsInitAmlWalk (WalkState, Op, NULL,
372         ObjDesc->Method.AmlStart,
373         ObjDesc->Method.AmlLength, NULL, ACPI_IMODE_LOAD_PASS1);
374     if (ACPI_FAILURE (Status))
375     {
376         return (Status);
377     }
378 
379     Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
380     WalkState->OwnerId = ObjDesc->Method.OwnerId;
381 
382     /* Push start scope on scope stack and make it current */
383 
384     Status = AcpiDsScopeStackPush (Method,
385         Method->Type, WalkState);
386     if (ACPI_FAILURE (Status))
387     {
388         return (Status);
389     }
390 
391     /* Parse the entire method AML including deferred operators */
392 
393     WalkState->ParseFlags &= ~ACPI_PARSE_DELETE_TREE;
394     WalkState->ParseFlags |= ACPI_PARSE_DISASSEMBLE;
395 
396     Status = AcpiPsParseAml (WalkState);
397 
398 #ifdef ACPI_DISASSEMBLER
399     (void) AcpiDmParseDeferredOps (Op);
400 
401     /* Now we can disassemble the method */
402 
403     AcpiGbl_DmOpt_Verbose = FALSE;
404     AcpiDmDisassemble (NULL, Op, 0);
405     AcpiGbl_DmOpt_Verbose = TRUE;
406 #endif
407 
408     AcpiPsDeleteParseTree (Op);
409 
410     /* Method cleanup */
411 
412     AcpiNsDeleteNamespaceSubtree (Method);
413     AcpiNsDeleteNamespaceByOwner (ObjDesc->Method.OwnerId);
414     AcpiUtReleaseOwnerId (&ObjDesc->Method.OwnerId);
415     return (AE_OK);
416 }
417