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