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