1 /*******************************************************************************
2 *
3 * Module Name: dbxface - AML Debugger external interfaces
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 "amlcode.h"
47 #include "acdebug.h"
48 #include "acinterp.h"
49 #include "acparser.h"
50
51
52 #define _COMPONENT ACPI_CA_DEBUGGER
53 ACPI_MODULE_NAME ("dbxface")
54
55
56 /* Local prototypes */
57
58 static ACPI_STATUS
59 AcpiDbStartCommand (
60 ACPI_WALK_STATE *WalkState,
61 ACPI_PARSE_OBJECT *Op);
62
63 #ifdef ACPI_OBSOLETE_FUNCTIONS
64 void
65 AcpiDbMethodEnd (
66 ACPI_WALK_STATE *WalkState);
67 #endif
68
69 #ifdef ACPI_DISASSEMBLER
70 static ACPI_PARSE_OBJECT *
71 AcpiDbGetDisplayOp (
72 ACPI_WALK_STATE *WalkState,
73 ACPI_PARSE_OBJECT *Op);
74 #endif
75
76 /*******************************************************************************
77 *
78 * FUNCTION: AcpiDbStartCommand
79 *
80 * PARAMETERS: WalkState - Current walk
81 * Op - Current executing Op, from AML interpreter
82 *
83 * RETURN: Status
84 *
85 * DESCRIPTION: Enter debugger command loop
86 *
87 ******************************************************************************/
88
89 static ACPI_STATUS
AcpiDbStartCommand(ACPI_WALK_STATE * WalkState,ACPI_PARSE_OBJECT * Op)90 AcpiDbStartCommand (
91 ACPI_WALK_STATE *WalkState,
92 ACPI_PARSE_OBJECT *Op)
93 {
94 ACPI_STATUS Status;
95
96
97 /* TBD: [Investigate] are there namespace locking issues here? */
98
99 /* AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); */
100
101 /* Go into the command loop and await next user command */
102
103
104 AcpiGbl_MethodExecuting = TRUE;
105 Status = AE_CTRL_TRUE;
106
107 while (Status == AE_CTRL_TRUE)
108 {
109 /* Notify the completion of the command */
110
111 Status = AcpiOsNotifyCommandComplete ();
112 if (ACPI_FAILURE (Status))
113 {
114 goto ErrorExit;
115 }
116
117 /* Wait the readiness of the command */
118
119 Status = AcpiOsWaitCommandReady ();
120 if (ACPI_FAILURE (Status))
121 {
122 goto ErrorExit;
123 }
124
125 Status = AcpiDbCommandDispatch (AcpiGbl_DbLineBuf, WalkState, Op);
126 }
127
128 /* AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); */
129
130 ErrorExit:
131 if (ACPI_FAILURE (Status) && Status != AE_CTRL_TERMINATE)
132 {
133 ACPI_EXCEPTION ((AE_INFO, Status,
134 "While parsing/handling command line"));
135 }
136 return (Status);
137 }
138
139
140 /*******************************************************************************
141 *
142 * FUNCTION: AcpiDbSignalBreakPoint
143 *
144 * PARAMETERS: WalkState - Current walk
145 *
146 * RETURN: Status
147 *
148 * DESCRIPTION: Called for AML_BREAKPOINT_OP
149 *
150 ******************************************************************************/
151
152 void
AcpiDbSignalBreakPoint(ACPI_WALK_STATE * WalkState)153 AcpiDbSignalBreakPoint (
154 ACPI_WALK_STATE *WalkState)
155 {
156
157 #ifndef ACPI_APPLICATION
158 if (AcpiGbl_DbThreadId != AcpiOsGetThreadId ())
159 {
160 return;
161 }
162 #endif
163
164 /*
165 * Set the single-step flag. This will cause the debugger (if present)
166 * to break to the console within the AML debugger at the start of the
167 * next AML instruction.
168 */
169 AcpiGbl_CmSingleStep = TRUE;
170 AcpiOsPrintf ("**break** Executed AML BreakPoint opcode\n");
171 }
172
173
174 #ifdef ACPI_DISASSEMBLER
175 /*******************************************************************************
176 *
177 * FUNCTION: AcpiDbGetDisplayOp
178 *
179 * PARAMETERS: WalkState - Current walk
180 * Op - Current executing op (from aml interpreter)
181 *
182 * RETURN: Opcode to display
183 *
184 * DESCRIPTION: Find the opcode to display during single stepping
185 *
186 ******************************************************************************/
187
188 static ACPI_PARSE_OBJECT *
AcpiDbGetDisplayOp(ACPI_WALK_STATE * WalkState,ACPI_PARSE_OBJECT * Op)189 AcpiDbGetDisplayOp (
190 ACPI_WALK_STATE *WalkState,
191 ACPI_PARSE_OBJECT *Op)
192 {
193 ACPI_PARSE_OBJECT *DisplayOp;
194 ACPI_PARSE_OBJECT *ParentOp;
195
196 DisplayOp = Op;
197 ParentOp = Op->Common.Parent;
198 if (ParentOp)
199 {
200 if ((WalkState->ControlState) &&
201 (WalkState->ControlState->Common.State ==
202 ACPI_CONTROL_PREDICATE_EXECUTING))
203 {
204 /*
205 * We are executing the predicate of an IF or WHILE statement
206 * Search upwards for the containing IF or WHILE so that the
207 * entire predicate can be displayed.
208 */
209 while (ParentOp)
210 {
211 if ((ParentOp->Common.AmlOpcode == AML_IF_OP) ||
212 (ParentOp->Common.AmlOpcode == AML_WHILE_OP))
213 {
214 DisplayOp = ParentOp;
215 break;
216 }
217 ParentOp = ParentOp->Common.Parent;
218 }
219 }
220 else
221 {
222 while (ParentOp)
223 {
224 if ((ParentOp->Common.AmlOpcode == AML_IF_OP) ||
225 (ParentOp->Common.AmlOpcode == AML_ELSE_OP) ||
226 (ParentOp->Common.AmlOpcode == AML_SCOPE_OP) ||
227 (ParentOp->Common.AmlOpcode == AML_METHOD_OP) ||
228 (ParentOp->Common.AmlOpcode == AML_WHILE_OP))
229 {
230 break;
231 }
232 DisplayOp = ParentOp;
233 ParentOp = ParentOp->Common.Parent;
234 }
235 }
236 }
237 return DisplayOp;
238 }
239 #endif
240
241
242 /*******************************************************************************
243 *
244 * FUNCTION: AcpiDbSingleStep
245 *
246 * PARAMETERS: WalkState - Current walk
247 * Op - Current executing op (from aml interpreter)
248 * OpcodeClass - Class of the current AML Opcode
249 *
250 * RETURN: Status
251 *
252 * DESCRIPTION: Called just before execution of an AML opcode.
253 *
254 ******************************************************************************/
255
256 ACPI_STATUS
AcpiDbSingleStep(ACPI_WALK_STATE * WalkState,ACPI_PARSE_OBJECT * Op,UINT32 OpcodeClass)257 AcpiDbSingleStep (
258 ACPI_WALK_STATE *WalkState,
259 ACPI_PARSE_OBJECT *Op,
260 UINT32 OpcodeClass)
261 {
262 ACPI_PARSE_OBJECT *Next;
263 ACPI_STATUS Status = AE_OK;
264 UINT32 OriginalDebugLevel;
265 UINT32 AmlOffset;
266
267
268 ACPI_FUNCTION_ENTRY ();
269
270
271 #ifndef ACPI_APPLICATION
272 if (AcpiGbl_DbThreadId != AcpiOsGetThreadId ())
273 {
274 return (AE_OK);
275 }
276 #endif
277
278 /* Check the abort flag */
279
280 if (AcpiGbl_AbortMethod)
281 {
282 AcpiGbl_AbortMethod = FALSE;
283 return (AE_ABORT_METHOD);
284 }
285
286 AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml,
287 WalkState->ParserState.AmlStart);
288
289 /* Check for single-step breakpoint */
290
291 if (WalkState->MethodBreakpoint &&
292 (WalkState->MethodBreakpoint <= AmlOffset))
293 {
294 /* Check if the breakpoint has been reached or passed */
295 /* Hit the breakpoint, resume single step, reset breakpoint */
296
297 AcpiOsPrintf ("***Break*** at AML offset %X\n", AmlOffset);
298 AcpiGbl_CmSingleStep = TRUE;
299 AcpiGbl_StepToNextCall = FALSE;
300 WalkState->MethodBreakpoint = 0;
301 }
302
303 /* Check for user breakpoint (Must be on exact Aml offset) */
304
305 else if (WalkState->UserBreakpoint &&
306 (WalkState->UserBreakpoint == AmlOffset))
307 {
308 AcpiOsPrintf ("***UserBreakpoint*** at AML offset %X\n",
309 AmlOffset);
310 AcpiGbl_CmSingleStep = TRUE;
311 AcpiGbl_StepToNextCall = FALSE;
312 WalkState->MethodBreakpoint = 0;
313 }
314
315 /*
316 * Check if this is an opcode that we are interested in --
317 * namely, opcodes that have arguments
318 */
319 if (Op->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP)
320 {
321 return (AE_OK);
322 }
323
324 switch (OpcodeClass)
325 {
326 case AML_CLASS_UNKNOWN:
327 case AML_CLASS_ARGUMENT: /* constants, literals, etc. do nothing */
328
329 return (AE_OK);
330
331 default:
332
333 /* All other opcodes -- continue */
334 break;
335 }
336
337 /*
338 * Under certain debug conditions, display this opcode and its operands
339 */
340 if ((AcpiGbl_DbOutputToFile) ||
341 (AcpiGbl_CmSingleStep) ||
342 (AcpiDbgLevel & ACPI_LV_PARSE))
343 {
344 if ((AcpiGbl_DbOutputToFile) ||
345 (AcpiDbgLevel & ACPI_LV_PARSE))
346 {
347 AcpiOsPrintf ("\nAML Debug: Next AML Opcode to execute:\n");
348 }
349
350 /*
351 * Display this op (and only this op - zero out the NEXT field
352 * temporarily, and disable parser trace output for the duration of
353 * the display because we don't want the extraneous debug output)
354 */
355 OriginalDebugLevel = AcpiDbgLevel;
356 AcpiDbgLevel &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);
357 Next = Op->Common.Next;
358 Op->Common.Next = NULL;
359
360 /* Now we can disassemble and display it */
361
362 #ifdef ACPI_DISASSEMBLER
363 AcpiDmDisassemble (WalkState, AcpiDbGetDisplayOp (WalkState, Op),
364 ACPI_UINT32_MAX);
365 #else
366 /*
367 * The AML Disassembler is not configured - at least we can
368 * display the opcode value and name
369 */
370 AcpiOsPrintf ("AML Opcode: %4.4X %s\n", Op->Common.AmlOpcode,
371 AcpiPsGetOpcodeName (Op->Common.AmlOpcode));
372 #endif
373
374 if ((Op->Common.AmlOpcode == AML_IF_OP) ||
375 (Op->Common.AmlOpcode == AML_WHILE_OP))
376 {
377 if (WalkState->ControlState->Common.Value)
378 {
379 AcpiOsPrintf ("Predicate = [True], IF block was executed\n");
380 }
381 else
382 {
383 AcpiOsPrintf ("Predicate = [False], Skipping IF block\n");
384 }
385 }
386 else if (Op->Common.AmlOpcode == AML_ELSE_OP)
387 {
388 AcpiOsPrintf ("Predicate = [False], ELSE block was executed\n");
389 }
390
391 /* Restore everything */
392
393 Op->Common.Next = Next;
394 AcpiOsPrintf ("\n");
395 if ((AcpiGbl_DbOutputToFile) ||
396 (AcpiDbgLevel & ACPI_LV_PARSE))
397 {
398 AcpiOsPrintf ("\n");
399 }
400 AcpiDbgLevel = OriginalDebugLevel;
401 }
402
403 /* If we are not single stepping, just continue executing the method */
404
405 if (!AcpiGbl_CmSingleStep)
406 {
407 return (AE_OK);
408 }
409
410 /*
411 * If we are executing a step-to-call command,
412 * Check if this is a method call.
413 */
414 if (AcpiGbl_StepToNextCall)
415 {
416 if (Op->Common.AmlOpcode != AML_INT_METHODCALL_OP)
417 {
418 /* Not a method call, just keep executing */
419
420 return (AE_OK);
421 }
422
423 /* Found a method call, stop executing */
424
425 AcpiGbl_StepToNextCall = FALSE;
426 }
427
428 /*
429 * If the next opcode is a method call, we will "step over" it
430 * by default.
431 */
432 if (Op->Common.AmlOpcode == AML_INT_METHODCALL_OP)
433 {
434 /* Force no more single stepping while executing called method */
435
436 AcpiGbl_CmSingleStep = FALSE;
437
438 /*
439 * Set the breakpoint on/before the call, it will stop execution
440 * as soon as we return
441 */
442 WalkState->MethodBreakpoint = 1; /* Must be non-zero! */
443 }
444
445
446 AcpiExExitInterpreter ();
447 Status = AcpiDbStartCommand (WalkState, Op);
448 AcpiExEnterInterpreter ();
449
450 /* User commands complete, continue execution of the interrupted method */
451
452 return (Status);
453 }
454
455
456 /*******************************************************************************
457 *
458 * FUNCTION: AcpiInitializeDebugger
459 *
460 * PARAMETERS: None
461 *
462 * RETURN: Status
463 *
464 * DESCRIPTION: Init and start debugger
465 *
466 ******************************************************************************/
467
468 ACPI_STATUS
AcpiInitializeDebugger(void)469 AcpiInitializeDebugger (
470 void)
471 {
472 ACPI_STATUS Status;
473
474
475 ACPI_FUNCTION_TRACE (AcpiInitializeDebugger);
476
477
478 /* Init globals */
479
480 AcpiGbl_DbBuffer = NULL;
481 AcpiGbl_DbFilename = NULL;
482 AcpiGbl_DbOutputToFile = FALSE;
483
484 AcpiGbl_DbDebugLevel = ACPI_LV_VERBOSITY2;
485 AcpiGbl_DbConsoleDebugLevel = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
486 AcpiGbl_DbOutputFlags = ACPI_DB_CONSOLE_OUTPUT;
487
488 AcpiGbl_DbOpt_NoIniMethods = FALSE;
489 AcpiGbl_DbOpt_NoRegionSupport = FALSE;
490
491 AcpiGbl_DbBuffer = AcpiOsAllocate (ACPI_DEBUG_BUFFER_SIZE);
492 if (!AcpiGbl_DbBuffer)
493 {
494 return_ACPI_STATUS (AE_NO_MEMORY);
495 }
496 memset (AcpiGbl_DbBuffer, 0, ACPI_DEBUG_BUFFER_SIZE);
497
498 /* Initial scope is the root */
499
500 AcpiGbl_DbScopeBuf [0] = AML_ROOT_PREFIX;
501 AcpiGbl_DbScopeBuf [1] = 0;
502 AcpiGbl_DbScopeNode = AcpiGbl_RootNode;
503
504 /* Initialize user commands loop */
505
506 AcpiGbl_DbTerminateLoop = FALSE;
507
508 /*
509 * If configured for multi-thread support, the debug executor runs in
510 * a separate thread so that the front end can be in another address
511 * space, environment, or even another machine.
512 */
513 if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED)
514 {
515 /* These were created with one unit, grab it */
516
517 Status = AcpiOsInitializeDebugger ();
518 if (ACPI_FAILURE (Status))
519 {
520 AcpiOsPrintf ("Could not get debugger mutex\n");
521 return_ACPI_STATUS (Status);
522 }
523
524 /* Create the debug execution thread to execute commands */
525
526 AcpiGbl_DbThreadsTerminated = FALSE;
527 Status = AcpiOsExecute (OSL_DEBUGGER_MAIN_THREAD,
528 AcpiDbExecuteThread, NULL);
529 if (ACPI_FAILURE (Status))
530 {
531 ACPI_EXCEPTION ((AE_INFO, Status,
532 "Could not start debugger thread"));
533 AcpiGbl_DbThreadsTerminated = TRUE;
534 return_ACPI_STATUS (Status);
535 }
536 }
537 else
538 {
539 AcpiGbl_DbThreadId = AcpiOsGetThreadId ();
540 }
541
542 return_ACPI_STATUS (AE_OK);
543 }
544
ACPI_EXPORT_SYMBOL(AcpiInitializeDebugger)545 ACPI_EXPORT_SYMBOL (AcpiInitializeDebugger)
546
547
548 /*******************************************************************************
549 *
550 * FUNCTION: AcpiTerminateDebugger
551 *
552 * PARAMETERS: None
553 *
554 * RETURN: None
555 *
556 * DESCRIPTION: Stop debugger
557 *
558 ******************************************************************************/
559
560 void
561 AcpiTerminateDebugger (
562 void)
563 {
564
565 /* Terminate the AML Debugger */
566
567 AcpiGbl_DbTerminateLoop = TRUE;
568
569 if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED)
570 {
571 /* Wait the AML Debugger threads */
572
573 while (!AcpiGbl_DbThreadsTerminated)
574 {
575 AcpiOsSleep (100);
576 }
577
578 AcpiOsTerminateDebugger ();
579 }
580
581 if (AcpiGbl_DbBuffer)
582 {
583 AcpiOsFree (AcpiGbl_DbBuffer);
584 AcpiGbl_DbBuffer = NULL;
585 }
586
587 /* Ensure that debug output is now disabled */
588
589 AcpiGbl_DbOutputFlags = ACPI_DB_DISABLE_OUTPUT;
590 }
591
ACPI_EXPORT_SYMBOL(AcpiTerminateDebugger)592 ACPI_EXPORT_SYMBOL (AcpiTerminateDebugger)
593
594
595 /*******************************************************************************
596 *
597 * FUNCTION: AcpiSetDebuggerThreadId
598 *
599 * PARAMETERS: ThreadId - Debugger thread ID
600 *
601 * RETURN: None
602 *
603 * DESCRIPTION: Set debugger thread ID
604 *
605 ******************************************************************************/
606
607 void
608 AcpiSetDebuggerThreadId (
609 ACPI_THREAD_ID ThreadId)
610 {
611 AcpiGbl_DbThreadId = ThreadId;
612 }
613
614 ACPI_EXPORT_SYMBOL (AcpiSetDebuggerThreadId)
615