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