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