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