1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /******************************************************************************* |
3 | * |
4 | * Module Name: dbinput - user front-end to the AML debugger |
5 | * |
6 | ******************************************************************************/ |
7 | |
8 | #include <acpi/acpi.h> |
9 | #include "accommon.h" |
10 | #include "acdebug.h" |
11 | |
12 | #ifdef ACPI_APPLICATION |
13 | #include "acapps.h" |
14 | #endif |
15 | |
16 | #define _COMPONENT ACPI_CA_DEBUGGER |
17 | ACPI_MODULE_NAME("dbinput" ) |
18 | |
19 | /* Local prototypes */ |
20 | static u32 acpi_db_get_line(char *input_buffer); |
21 | |
22 | static u32 acpi_db_match_command(char *user_command); |
23 | |
24 | static void acpi_db_display_command_info(const char *command, u8 display_all); |
25 | |
26 | static void acpi_db_display_help(char *command); |
27 | |
28 | static u8 |
29 | acpi_db_match_command_help(const char *command, |
30 | const struct acpi_db_command_help *help); |
31 | |
32 | /* |
33 | * Top-level debugger commands. |
34 | * |
35 | * This list of commands must match the string table below it |
36 | */ |
37 | enum acpi_ex_debugger_commands { |
38 | CMD_NOT_FOUND = 0, |
39 | CMD_NULL, |
40 | CMD_ALL, |
41 | CMD_ALLOCATIONS, |
42 | CMD_ARGS, |
43 | CMD_ARGUMENTS, |
44 | CMD_BREAKPOINT, |
45 | CMD_BUSINFO, |
46 | CMD_CALL, |
47 | CMD_DEBUG, |
48 | CMD_DISASSEMBLE, |
49 | CMD_DISASM, |
50 | CMD_DUMP, |
51 | CMD_EVALUATE, |
52 | CMD_EXECUTE, |
53 | CMD_EXIT, |
54 | CMD_FIELDS, |
55 | CMD_FIND, |
56 | CMD_GO, |
57 | CMD_HANDLERS, |
58 | CMD_HELP, |
59 | CMD_HELP2, |
60 | CMD_HISTORY, |
61 | CMD_HISTORY_EXE, |
62 | CMD_HISTORY_LAST, |
63 | CMD_INFORMATION, |
64 | CMD_INTEGRITY, |
65 | CMD_INTO, |
66 | CMD_LEVEL, |
67 | CMD_LIST, |
68 | CMD_LOCALS, |
69 | CMD_LOCKS, |
70 | CMD_METHODS, |
71 | CMD_NAMESPACE, |
72 | CMD_NOTIFY, |
73 | CMD_OBJECTS, |
74 | CMD_OSI, |
75 | CMD_OWNER, |
76 | CMD_PATHS, |
77 | CMD_PREDEFINED, |
78 | CMD_PREFIX, |
79 | CMD_QUIT, |
80 | CMD_REFERENCES, |
81 | CMD_RESOURCES, |
82 | CMD_RESULTS, |
83 | CMD_SET, |
84 | CMD_STATS, |
85 | CMD_STOP, |
86 | CMD_TABLES, |
87 | CMD_TEMPLATE, |
88 | CMD_TRACE, |
89 | CMD_TREE, |
90 | CMD_TYPE, |
91 | #ifdef ACPI_APPLICATION |
92 | CMD_ENABLEACPI, |
93 | CMD_EVENT, |
94 | CMD_GPE, |
95 | CMD_GPES, |
96 | CMD_SCI, |
97 | CMD_SLEEP, |
98 | |
99 | CMD_CLOSE, |
100 | CMD_LOAD, |
101 | CMD_OPEN, |
102 | CMD_UNLOAD, |
103 | |
104 | CMD_TERMINATE, |
105 | CMD_BACKGROUND, |
106 | CMD_THREADS, |
107 | |
108 | CMD_TEST, |
109 | CMD_INTERRUPT, |
110 | #endif |
111 | }; |
112 | |
113 | #define CMD_FIRST_VALID 2 |
114 | |
115 | /* Second parameter is the required argument count */ |
116 | |
117 | static const struct acpi_db_command_info acpi_gbl_db_commands[] = { |
118 | {"<NOT FOUND>" , 0}, |
119 | {"<NULL>" , 0}, |
120 | {"ALL" , 1}, |
121 | {"ALLOCATIONS" , 0}, |
122 | {"ARGS" , 0}, |
123 | {"ARGUMENTS" , 0}, |
124 | {"BREAKPOINT" , 1}, |
125 | {"BUSINFO" , 0}, |
126 | {"CALL" , 0}, |
127 | {"DEBUG" , 1}, |
128 | {"DISASSEMBLE" , 1}, |
129 | {"DISASM" , 1}, |
130 | {"DUMP" , 1}, |
131 | {"EVALUATE" , 1}, |
132 | {"EXECUTE" , 1}, |
133 | {"EXIT" , 0}, |
134 | {"FIELDS" , 1}, |
135 | {"FIND" , 1}, |
136 | {"GO" , 0}, |
137 | {"HANDLERS" , 0}, |
138 | {"HELP" , 0}, |
139 | {"?" , 0}, |
140 | {"HISTORY" , 0}, |
141 | {"!" , 1}, |
142 | {"!!" , 0}, |
143 | {"INFORMATION" , 0}, |
144 | {"INTEGRITY" , 0}, |
145 | {"INTO" , 0}, |
146 | {"LEVEL" , 0}, |
147 | {"LIST" , 0}, |
148 | {"LOCALS" , 0}, |
149 | {"LOCKS" , 0}, |
150 | {"METHODS" , 0}, |
151 | {"NAMESPACE" , 0}, |
152 | {"NOTIFY" , 2}, |
153 | {"OBJECTS" , 0}, |
154 | {"OSI" , 0}, |
155 | {"OWNER" , 1}, |
156 | {"PATHS" , 0}, |
157 | {"PREDEFINED" , 0}, |
158 | {"PREFIX" , 0}, |
159 | {"QUIT" , 0}, |
160 | {"REFERENCES" , 1}, |
161 | {"RESOURCES" , 0}, |
162 | {"RESULTS" , 0}, |
163 | {"SET" , 3}, |
164 | {"STATS" , 1}, |
165 | {"STOP" , 0}, |
166 | {"TABLES" , 0}, |
167 | {"TEMPLATE" , 1}, |
168 | {"TRACE" , 1}, |
169 | {"TREE" , 0}, |
170 | {"TYPE" , 1}, |
171 | #ifdef ACPI_APPLICATION |
172 | {"ENABLEACPI" , 0}, |
173 | {"EVENT" , 1}, |
174 | {"GPE" , 1}, |
175 | {"GPES" , 0}, |
176 | {"SCI" , 0}, |
177 | {"SLEEP" , 0}, |
178 | |
179 | {"CLOSE" , 0}, |
180 | {"LOAD" , 1}, |
181 | {"OPEN" , 1}, |
182 | {"UNLOAD" , 1}, |
183 | |
184 | {"TERMINATE" , 0}, |
185 | {"BACKGROUND" , 1}, |
186 | {"THREADS" , 3}, |
187 | |
188 | {"TEST" , 1}, |
189 | {"INTERRUPT" , 1}, |
190 | #endif |
191 | {NULL, 0} |
192 | }; |
193 | |
194 | /* |
195 | * Help for all debugger commands. First argument is the number of lines |
196 | * of help to output for the command. |
197 | * |
198 | * Note: Some commands are not supported by the kernel-level version of |
199 | * the debugger. |
200 | */ |
201 | static const struct acpi_db_command_help acpi_gbl_db_command_help[] = { |
202 | {0, "\nNamespace Access:" , "\n" }, |
203 | {1, " Businfo" , "Display system bus info\n" }, |
204 | {1, " Disassemble <Method>" , "Disassemble a control method\n" }, |
205 | {1, " Find <AcpiName> (? is wildcard)" , |
206 | "Find ACPI name(s) with wildcards\n" }, |
207 | {1, " Integrity" , "Validate namespace integrity\n" }, |
208 | {1, " Methods" , "Display list of loaded control methods\n" }, |
209 | {1, " Fields <AddressSpaceId>" , |
210 | "Display list of loaded field units by space ID\n" }, |
211 | {1, " Namespace [Object] [Depth]" , |
212 | "Display loaded namespace tree/subtree\n" }, |
213 | {1, " Notify <Object> <Value>" , "Send a notification on Object\n" }, |
214 | {1, " Objects [ObjectType]" , |
215 | "Display summary of all objects or just given type\n" }, |
216 | {1, " Owner <OwnerId> [Depth]" , |
217 | "Display loaded namespace by object owner\n" }, |
218 | {1, " Paths" , "Display full pathnames of namespace objects\n" }, |
219 | {1, " Predefined" , "Check all predefined names\n" }, |
220 | {1, " Prefix [<Namepath>]" , "Set or Get current execution prefix\n" }, |
221 | {1, " References <Addr>" , "Find all references to object at addr\n" }, |
222 | {1, " Resources [DeviceName]" , |
223 | "Display Device resources (no arg = all devices)\n" }, |
224 | {1, " Set N <NamedObject> <Value>" , "Set value for named integer\n" }, |
225 | {1, " Template <Object>" , "Format/dump a Buffer/ResourceTemplate\n" }, |
226 | {1, " Type <Object>" , "Display object type\n" }, |
227 | |
228 | {0, "\nControl Method Execution:" , "\n" }, |
229 | {1, " All <NameSeg>" , "Evaluate all objects named NameSeg\n" }, |
230 | {1, " Evaluate <Namepath> [Arguments]" , |
231 | "Evaluate object or control method\n" }, |
232 | {1, " Execute <Namepath> [Arguments]" , "Synonym for Evaluate\n" }, |
233 | #ifdef ACPI_APPLICATION |
234 | {1, " Background <Namepath> [Arguments]" , |
235 | "Evaluate object/method in a separate thread\n" }, |
236 | {1, " Thread <Threads><Loops><NamePath>" , |
237 | "Spawn threads to execute method(s)\n" }, |
238 | #endif |
239 | {1, " Debug <Namepath> [Arguments]" , "Single-Step a control method\n" }, |
240 | {7, " [Arguments] formats:" , "Control method argument formats\n" }, |
241 | {1, " Hex Integer" , "Integer\n" }, |
242 | {1, " \"Ascii String\"" , "String\n" }, |
243 | {1, " (Hex Byte List)" , "Buffer\n" }, |
244 | {1, " (01 42 7A BF)" , "Buffer example (4 bytes)\n" }, |
245 | {1, " [Package Element List]" , "Package\n" }, |
246 | {1, " [0x01 0x1234 \"string\"]" , |
247 | "Package example (3 elements)\n" }, |
248 | |
249 | {0, "\nMiscellaneous:" , "\n" }, |
250 | {1, " Allocations" , "Display list of current memory allocations\n" }, |
251 | {2, " Dump <Address>|<Namepath>" , "\n" }, |
252 | {0, " [Byte|Word|Dword|Qword]" , |
253 | "Display ACPI objects or memory\n" }, |
254 | {1, " Handlers" , "Info about global handlers\n" }, |
255 | {1, " Help [Command]" , "This help screen or individual command\n" }, |
256 | {1, " History" , "Display command history buffer\n" }, |
257 | {1, " Level <DebugLevel>] [console]" , |
258 | "Get/Set debug level for file or console\n" }, |
259 | {1, " Locks" , "Current status of internal mutexes\n" }, |
260 | {1, " Osi [Install|Remove <name>]" , |
261 | "Display or modify global _OSI list\n" }, |
262 | {1, " Quit or Exit" , "Exit this command\n" }, |
263 | {8, " Stats <SubCommand>" , |
264 | "Display namespace and memory statistics\n" }, |
265 | {1, " Allocations" , "Display list of current memory allocations\n" }, |
266 | {1, " Memory" , "Dump internal memory lists\n" }, |
267 | {1, " Misc" , "Namespace search and mutex stats\n" }, |
268 | {1, " Objects" , "Summary of namespace objects\n" }, |
269 | {1, " Sizes" , "Sizes for each of the internal objects\n" }, |
270 | {1, " Stack" , "Display CPU stack usage\n" }, |
271 | {1, " Tables" , "Info about current ACPI table(s)\n" }, |
272 | {1, " Tables" , "Display info about loaded ACPI tables\n" }, |
273 | #ifdef ACPI_APPLICATION |
274 | {1, " Terminate" , "Delete namespace and all internal objects\n" }, |
275 | #endif |
276 | {1, " ! <CommandNumber>" , "Execute command from history buffer\n" }, |
277 | {1, " !!" , "Execute last command again\n" }, |
278 | |
279 | {0, "\nMethod and Namespace Debugging:" , "\n" }, |
280 | {5, " Trace <State> [<Namepath>] [Once]" , |
281 | "Trace control method execution\n" }, |
282 | {1, " Enable" , "Enable all messages\n" }, |
283 | {1, " Disable" , "Disable tracing\n" }, |
284 | {1, " Method" , "Enable method execution messages\n" }, |
285 | {1, " Opcode" , "Enable opcode execution messages\n" }, |
286 | {3, " Test <TestName>" , "Invoke a debug test\n" }, |
287 | {1, " Objects" , "Read/write/compare all namespace data objects\n" }, |
288 | {1, " Predefined" , |
289 | "Validate all ACPI predefined names (_STA, etc.)\n" }, |
290 | {1, " Execute predefined" , |
291 | "Execute all predefined (public) methods\n" }, |
292 | |
293 | {0, "\nControl Method Single-Step Execution:" , "\n" }, |
294 | {1, " Arguments (or Args)" , "Display method arguments\n" }, |
295 | {1, " Breakpoint <AmlOffset>" , "Set an AML execution breakpoint\n" }, |
296 | {1, " Call" , "Run to next control method invocation\n" }, |
297 | {1, " Go" , "Allow method to run to completion\n" }, |
298 | {1, " Information" , "Display info about the current method\n" }, |
299 | {1, " Into" , "Step into (not over) a method call\n" }, |
300 | {1, " List [# of Aml Opcodes]" , "Display method ASL statements\n" }, |
301 | {1, " Locals" , "Display method local variables\n" }, |
302 | {1, " Results" , "Display method result stack\n" }, |
303 | {1, " Set <A|L> <#> <Value>" , "Set method data (Arguments/Locals)\n" }, |
304 | {1, " Stop" , "Terminate control method\n" }, |
305 | {1, " Tree" , "Display control method calling tree\n" }, |
306 | {1, " <Enter>" , "Single step next AML opcode (over calls)\n" }, |
307 | |
308 | #ifdef ACPI_APPLICATION |
309 | {0, "\nFile Operations:" , "\n" }, |
310 | {1, " Close" , "Close debug output file\n" }, |
311 | {1, " Load <Input Filename>" , "Load ACPI table from a file\n" }, |
312 | {1, " Open <Output Filename>" , "Open a file for debug output\n" }, |
313 | {1, " Unload <Namepath>" , |
314 | "Unload an ACPI table via namespace object\n" }, |
315 | |
316 | {0, "\nHardware Simulation:" , "\n" }, |
317 | {1, " EnableAcpi" , "Enable ACPI (hardware) mode\n" }, |
318 | {1, " Event <F|G> <Value>" , "Generate AcpiEvent (Fixed/GPE)\n" }, |
319 | {1, " Gpe <GpeNum> [GpeBlockDevice]" , "Simulate a GPE\n" }, |
320 | {1, " Gpes" , "Display info on all GPE devices\n" }, |
321 | {1, " Sci" , "Generate an SCI\n" }, |
322 | {1, " Sleep [SleepState]" , "Simulate sleep/wake sequence(s) (0-5)\n" }, |
323 | {1, " Interrupt <GSIV>" , "Simulate an interrupt\n" }, |
324 | #endif |
325 | {0, NULL, NULL} |
326 | }; |
327 | |
328 | /******************************************************************************* |
329 | * |
330 | * FUNCTION: acpi_db_match_command_help |
331 | * |
332 | * PARAMETERS: command - Command string to match |
333 | * help - Help table entry to attempt match |
334 | * |
335 | * RETURN: TRUE if command matched, FALSE otherwise |
336 | * |
337 | * DESCRIPTION: Attempt to match a command in the help table in order to |
338 | * print help information for a single command. |
339 | * |
340 | ******************************************************************************/ |
341 | |
342 | static u8 |
343 | acpi_db_match_command_help(const char *command, |
344 | const struct acpi_db_command_help *help) |
345 | { |
346 | char *invocation = help->invocation; |
347 | u32 line_count; |
348 | |
349 | /* Valid commands in the help table begin with a couple of spaces */ |
350 | |
351 | if (*invocation != ' ') { |
352 | return (FALSE); |
353 | } |
354 | |
355 | while (*invocation == ' ') { |
356 | invocation++; |
357 | } |
358 | |
359 | /* Match command name (full command or substring) */ |
360 | |
361 | while ((*command) && (*invocation) && (*invocation != ' ')) { |
362 | if (tolower((int)*command) != tolower((int)*invocation)) { |
363 | return (FALSE); |
364 | } |
365 | |
366 | invocation++; |
367 | command++; |
368 | } |
369 | |
370 | /* Print the appropriate number of help lines */ |
371 | |
372 | line_count = help->line_count; |
373 | while (line_count) { |
374 | acpi_os_printf(format: "%-38s : %s" , help->invocation, |
375 | help->description); |
376 | help++; |
377 | line_count--; |
378 | } |
379 | |
380 | return (TRUE); |
381 | } |
382 | |
383 | /******************************************************************************* |
384 | * |
385 | * FUNCTION: acpi_db_display_command_info |
386 | * |
387 | * PARAMETERS: command - Command string to match |
388 | * display_all - Display all matching commands, or just |
389 | * the first one (substring match) |
390 | * |
391 | * RETURN: None |
392 | * |
393 | * DESCRIPTION: Display help information for a Debugger command. |
394 | * |
395 | ******************************************************************************/ |
396 | |
397 | static void acpi_db_display_command_info(const char *command, u8 display_all) |
398 | { |
399 | const struct acpi_db_command_help *next; |
400 | u8 matched; |
401 | |
402 | next = acpi_gbl_db_command_help; |
403 | while (next->invocation) { |
404 | matched = acpi_db_match_command_help(command, help: next); |
405 | if (!display_all && matched) { |
406 | return; |
407 | } |
408 | |
409 | next++; |
410 | } |
411 | } |
412 | |
413 | /******************************************************************************* |
414 | * |
415 | * FUNCTION: acpi_db_display_help |
416 | * |
417 | * PARAMETERS: command - Optional command string to display help. |
418 | * if not specified, all debugger command |
419 | * help strings are displayed |
420 | * |
421 | * RETURN: None |
422 | * |
423 | * DESCRIPTION: Display help for a single debugger command, or all of them. |
424 | * |
425 | ******************************************************************************/ |
426 | |
427 | static void acpi_db_display_help(char *command) |
428 | { |
429 | const struct acpi_db_command_help *next = acpi_gbl_db_command_help; |
430 | |
431 | if (!command) { |
432 | |
433 | /* No argument to help, display help for all commands */ |
434 | |
435 | acpi_os_printf(format: "\nSummary of AML Debugger Commands\n\n" ); |
436 | |
437 | while (next->invocation) { |
438 | acpi_os_printf(format: "%-38s%s" , next->invocation, |
439 | next->description); |
440 | next++; |
441 | } |
442 | acpi_os_printf(format: "\n" ); |
443 | |
444 | } else { |
445 | /* Display help for all commands that match the substring */ |
446 | |
447 | acpi_db_display_command_info(command, TRUE); |
448 | } |
449 | } |
450 | |
451 | /******************************************************************************* |
452 | * |
453 | * FUNCTION: acpi_db_get_next_token |
454 | * |
455 | * PARAMETERS: string - Command buffer |
456 | * next - Return value, end of next token |
457 | * |
458 | * RETURN: Pointer to the start of the next token. |
459 | * |
460 | * DESCRIPTION: Command line parsing. Get the next token on the command line |
461 | * |
462 | ******************************************************************************/ |
463 | |
464 | char *acpi_db_get_next_token(char *string, |
465 | char **next, acpi_object_type *return_type) |
466 | { |
467 | char *start; |
468 | u32 depth; |
469 | acpi_object_type type = ACPI_TYPE_INTEGER; |
470 | |
471 | /* At end of buffer? */ |
472 | |
473 | if (!string || !(*string)) { |
474 | return (NULL); |
475 | } |
476 | |
477 | /* Remove any spaces at the beginning, ignore blank lines */ |
478 | |
479 | while (*string && isspace((int)*string)) { |
480 | string++; |
481 | } |
482 | |
483 | if (!(*string)) { |
484 | return (NULL); |
485 | } |
486 | |
487 | switch (*string) { |
488 | case '"': |
489 | |
490 | /* This is a quoted string, scan until closing quote */ |
491 | |
492 | string++; |
493 | start = string; |
494 | type = ACPI_TYPE_STRING; |
495 | |
496 | /* Find end of string */ |
497 | |
498 | while (*string && (*string != '"')) { |
499 | string++; |
500 | } |
501 | break; |
502 | |
503 | case '(': |
504 | |
505 | /* This is the start of a buffer, scan until closing paren */ |
506 | |
507 | string++; |
508 | start = string; |
509 | type = ACPI_TYPE_BUFFER; |
510 | |
511 | /* Find end of buffer */ |
512 | |
513 | while (*string && (*string != ')')) { |
514 | string++; |
515 | } |
516 | break; |
517 | |
518 | case '{': |
519 | |
520 | /* This is the start of a field unit, scan until closing brace */ |
521 | |
522 | string++; |
523 | start = string; |
524 | type = ACPI_TYPE_FIELD_UNIT; |
525 | |
526 | /* Find end of buffer */ |
527 | |
528 | while (*string && (*string != '}')) { |
529 | string++; |
530 | } |
531 | break; |
532 | |
533 | case '[': |
534 | |
535 | /* This is the start of a package, scan until closing bracket */ |
536 | |
537 | string++; |
538 | depth = 1; |
539 | start = string; |
540 | type = ACPI_TYPE_PACKAGE; |
541 | |
542 | /* Find end of package (closing bracket) */ |
543 | |
544 | while (*string) { |
545 | |
546 | /* Handle String package elements */ |
547 | |
548 | if (*string == '"') { |
549 | /* Find end of string */ |
550 | |
551 | string++; |
552 | while (*string && (*string != '"')) { |
553 | string++; |
554 | } |
555 | if (!(*string)) { |
556 | break; |
557 | } |
558 | } else if (*string == '[') { |
559 | depth++; /* A nested package declaration */ |
560 | } else if (*string == ']') { |
561 | depth--; |
562 | if (depth == 0) { /* Found final package closing bracket */ |
563 | break; |
564 | } |
565 | } |
566 | |
567 | string++; |
568 | } |
569 | break; |
570 | |
571 | default: |
572 | |
573 | start = string; |
574 | |
575 | /* Find end of token */ |
576 | |
577 | while (*string && !isspace((int)*string)) { |
578 | string++; |
579 | } |
580 | break; |
581 | } |
582 | |
583 | if (!(*string)) { |
584 | *next = NULL; |
585 | } else { |
586 | *string = 0; |
587 | *next = string + 1; |
588 | } |
589 | |
590 | *return_type = type; |
591 | return (start); |
592 | } |
593 | |
594 | /******************************************************************************* |
595 | * |
596 | * FUNCTION: acpi_db_get_line |
597 | * |
598 | * PARAMETERS: input_buffer - Command line buffer |
599 | * |
600 | * RETURN: Count of arguments to the command |
601 | * |
602 | * DESCRIPTION: Get the next command line from the user. Gets entire line |
603 | * up to the next newline |
604 | * |
605 | ******************************************************************************/ |
606 | |
607 | static u32 acpi_db_get_line(char *input_buffer) |
608 | { |
609 | u32 i; |
610 | u32 count; |
611 | char *next; |
612 | char *this; |
613 | |
614 | if (acpi_ut_safe_strcpy |
615 | (dest: acpi_gbl_db_parsed_buf, dest_size: sizeof(acpi_gbl_db_parsed_buf), |
616 | source: input_buffer)) { |
617 | acpi_os_printf |
618 | (format: "Buffer overflow while parsing input line (max %u characters)\n" , |
619 | (u32)sizeof(acpi_gbl_db_parsed_buf)); |
620 | return (0); |
621 | } |
622 | |
623 | this = acpi_gbl_db_parsed_buf; |
624 | for (i = 0; i < ACPI_DEBUGGER_MAX_ARGS; i++) { |
625 | acpi_gbl_db_args[i] = acpi_db_get_next_token(string: this, next: &next, |
626 | return_type: &acpi_gbl_db_arg_types |
627 | [i]); |
628 | if (!acpi_gbl_db_args[i]) { |
629 | break; |
630 | } |
631 | |
632 | this = next; |
633 | } |
634 | |
635 | /* Uppercase the actual command */ |
636 | |
637 | acpi_ut_strupr(src_string: acpi_gbl_db_args[0]); |
638 | |
639 | count = i; |
640 | if (count) { |
641 | count--; /* Number of args only */ |
642 | } |
643 | |
644 | return (count); |
645 | } |
646 | |
647 | /******************************************************************************* |
648 | * |
649 | * FUNCTION: acpi_db_match_command |
650 | * |
651 | * PARAMETERS: user_command - User command line |
652 | * |
653 | * RETURN: Index into command array, -1 if not found |
654 | * |
655 | * DESCRIPTION: Search command array for a command match |
656 | * |
657 | ******************************************************************************/ |
658 | |
659 | static u32 acpi_db_match_command(char *user_command) |
660 | { |
661 | u32 i; |
662 | |
663 | if (!user_command || user_command[0] == 0) { |
664 | return (CMD_NULL); |
665 | } |
666 | |
667 | for (i = CMD_FIRST_VALID; acpi_gbl_db_commands[i].name; i++) { |
668 | if (strstr |
669 | (ACPI_CAST_PTR(char, acpi_gbl_db_commands[i].name), |
670 | user_command) == acpi_gbl_db_commands[i].name) { |
671 | return (i); |
672 | } |
673 | } |
674 | |
675 | /* Command not recognized */ |
676 | |
677 | return (CMD_NOT_FOUND); |
678 | } |
679 | |
680 | /******************************************************************************* |
681 | * |
682 | * FUNCTION: acpi_db_command_dispatch |
683 | * |
684 | * PARAMETERS: input_buffer - Command line buffer |
685 | * walk_state - Current walk |
686 | * op - Current (executing) parse op |
687 | * |
688 | * RETURN: Status |
689 | * |
690 | * DESCRIPTION: Command dispatcher. |
691 | * |
692 | ******************************************************************************/ |
693 | |
694 | acpi_status |
695 | acpi_db_command_dispatch(char *input_buffer, |
696 | struct acpi_walk_state *walk_state, |
697 | union acpi_parse_object *op) |
698 | { |
699 | u32 temp; |
700 | u64 temp64; |
701 | u32 command_index; |
702 | u32 param_count; |
703 | char *command_line; |
704 | acpi_status status = AE_CTRL_TRUE; |
705 | |
706 | /* If acpi_terminate has been called, terminate this thread */ |
707 | |
708 | if (acpi_gbl_db_terminate_loop) { |
709 | return (AE_CTRL_TERMINATE); |
710 | } |
711 | |
712 | /* Find command and add to the history buffer */ |
713 | |
714 | param_count = acpi_db_get_line(input_buffer); |
715 | command_index = acpi_db_match_command(user_command: acpi_gbl_db_args[0]); |
716 | |
717 | /* |
718 | * We don't want to add the !! command to the history buffer. It |
719 | * would cause an infinite loop because it would always be the |
720 | * previous command. |
721 | */ |
722 | if (command_index != CMD_HISTORY_LAST) { |
723 | acpi_db_add_to_history(command_line: input_buffer); |
724 | } |
725 | |
726 | /* Verify that we have the minimum number of params */ |
727 | |
728 | if (param_count < acpi_gbl_db_commands[command_index].min_args) { |
729 | acpi_os_printf |
730 | (format: "%u parameters entered, [%s] requires %u parameters\n" , |
731 | param_count, acpi_gbl_db_commands[command_index].name, |
732 | acpi_gbl_db_commands[command_index].min_args); |
733 | |
734 | acpi_db_display_command_info(command: acpi_gbl_db_commands |
735 | [command_index].name, FALSE); |
736 | return (AE_CTRL_TRUE); |
737 | } |
738 | |
739 | /* Decode and dispatch the command */ |
740 | |
741 | switch (command_index) { |
742 | case CMD_NULL: |
743 | |
744 | if (op) { |
745 | return (AE_OK); |
746 | } |
747 | break; |
748 | |
749 | case CMD_ALL: |
750 | |
751 | acpi_os_printf(format: "Executing all objects with NameSeg: %s\n" , |
752 | acpi_gbl_db_args[1]); |
753 | acpi_db_execute(name: acpi_gbl_db_args[1], args: &acpi_gbl_db_args[2], |
754 | types: &acpi_gbl_db_arg_types[2], |
755 | EX_NO_SINGLE_STEP | EX_ALL); |
756 | break; |
757 | |
758 | case CMD_ALLOCATIONS: |
759 | |
760 | #ifdef ACPI_DBG_TRACK_ALLOCATIONS |
761 | acpi_ut_dump_allocations((u32)-1, NULL); |
762 | #endif |
763 | break; |
764 | |
765 | case CMD_ARGS: |
766 | case CMD_ARGUMENTS: |
767 | |
768 | acpi_db_display_arguments(); |
769 | break; |
770 | |
771 | case CMD_BREAKPOINT: |
772 | |
773 | acpi_db_set_method_breakpoint(location: acpi_gbl_db_args[1], walk_state, |
774 | op); |
775 | break; |
776 | |
777 | case CMD_BUSINFO: |
778 | |
779 | acpi_db_get_bus_info(); |
780 | break; |
781 | |
782 | case CMD_CALL: |
783 | |
784 | acpi_db_set_method_call_breakpoint(op); |
785 | status = AE_OK; |
786 | break; |
787 | |
788 | case CMD_DEBUG: |
789 | |
790 | acpi_db_execute(name: acpi_gbl_db_args[1], |
791 | args: &acpi_gbl_db_args[2], types: &acpi_gbl_db_arg_types[2], |
792 | EX_SINGLE_STEP); |
793 | break; |
794 | |
795 | case CMD_DISASSEMBLE: |
796 | case CMD_DISASM: |
797 | |
798 | #ifdef ACPI_DISASSEMBLER |
799 | (void)acpi_db_disassemble_method(acpi_gbl_db_args[1]); |
800 | #else |
801 | acpi_os_printf |
802 | (format: "The AML Disassembler is not configured/present\n" ); |
803 | #endif |
804 | break; |
805 | |
806 | case CMD_DUMP: |
807 | |
808 | acpi_db_decode_and_display_object(target: acpi_gbl_db_args[1], |
809 | output_type: acpi_gbl_db_args[2]); |
810 | break; |
811 | |
812 | case CMD_EVALUATE: |
813 | case CMD_EXECUTE: |
814 | |
815 | acpi_db_execute(name: acpi_gbl_db_args[1], |
816 | args: &acpi_gbl_db_args[2], types: &acpi_gbl_db_arg_types[2], |
817 | EX_NO_SINGLE_STEP); |
818 | break; |
819 | |
820 | case CMD_FIND: |
821 | |
822 | status = acpi_db_find_name_in_namespace(name_arg: acpi_gbl_db_args[1]); |
823 | break; |
824 | |
825 | case CMD_FIELDS: |
826 | |
827 | status = acpi_ut_strtoul64(string: acpi_gbl_db_args[1], ret_integer: &temp64); |
828 | |
829 | if (ACPI_FAILURE(status) |
830 | || temp64 >= ACPI_NUM_PREDEFINED_REGIONS) { |
831 | acpi_os_printf |
832 | (format: "Invalid address space ID: must be between 0 and %u inclusive\n" , |
833 | ACPI_NUM_PREDEFINED_REGIONS - 1); |
834 | return (AE_OK); |
835 | } |
836 | |
837 | status = acpi_db_display_fields(address_space_id: (u32)temp64); |
838 | break; |
839 | |
840 | case CMD_GO: |
841 | |
842 | acpi_gbl_cm_single_step = FALSE; |
843 | return (AE_OK); |
844 | |
845 | case CMD_HANDLERS: |
846 | |
847 | acpi_db_display_handlers(); |
848 | break; |
849 | |
850 | case CMD_HELP: |
851 | case CMD_HELP2: |
852 | |
853 | acpi_db_display_help(command: acpi_gbl_db_args[1]); |
854 | break; |
855 | |
856 | case CMD_HISTORY: |
857 | |
858 | acpi_db_display_history(); |
859 | break; |
860 | |
861 | case CMD_HISTORY_EXE: /* ! command */ |
862 | |
863 | command_line = acpi_db_get_from_history(command_num_arg: acpi_gbl_db_args[1]); |
864 | if (!command_line) { |
865 | return (AE_CTRL_TRUE); |
866 | } |
867 | |
868 | status = acpi_db_command_dispatch(input_buffer: command_line, walk_state, op); |
869 | return (status); |
870 | |
871 | case CMD_HISTORY_LAST: /* !! command */ |
872 | |
873 | command_line = acpi_db_get_from_history(NULL); |
874 | if (!command_line) { |
875 | return (AE_CTRL_TRUE); |
876 | } |
877 | |
878 | status = acpi_db_command_dispatch(input_buffer: command_line, walk_state, op); |
879 | return (status); |
880 | |
881 | case CMD_INFORMATION: |
882 | |
883 | acpi_db_display_method_info(op); |
884 | break; |
885 | |
886 | case CMD_INTEGRITY: |
887 | |
888 | acpi_db_check_integrity(); |
889 | break; |
890 | |
891 | case CMD_INTO: |
892 | |
893 | if (op) { |
894 | acpi_gbl_cm_single_step = TRUE; |
895 | return (AE_OK); |
896 | } |
897 | break; |
898 | |
899 | case CMD_LEVEL: |
900 | |
901 | if (param_count == 0) { |
902 | acpi_os_printf |
903 | (format: "Current debug level for file output is: %8.8X\n" , |
904 | acpi_gbl_db_debug_level); |
905 | acpi_os_printf |
906 | (format: "Current debug level for console output is: %8.8X\n" , |
907 | acpi_gbl_db_console_debug_level); |
908 | } else if (param_count == 2) { |
909 | temp = acpi_gbl_db_console_debug_level; |
910 | acpi_gbl_db_console_debug_level = |
911 | strtoul(acpi_gbl_db_args[1], NULL, 16); |
912 | acpi_os_printf |
913 | (format: "Debug Level for console output was %8.8X, now %8.8X\n" , |
914 | temp, acpi_gbl_db_console_debug_level); |
915 | } else { |
916 | temp = acpi_gbl_db_debug_level; |
917 | acpi_gbl_db_debug_level = |
918 | strtoul(acpi_gbl_db_args[1], NULL, 16); |
919 | acpi_os_printf |
920 | (format: "Debug Level for file output was %8.8X, now %8.8X\n" , |
921 | temp, acpi_gbl_db_debug_level); |
922 | } |
923 | break; |
924 | |
925 | case CMD_LIST: |
926 | |
927 | #ifdef ACPI_DISASSEMBLER |
928 | acpi_db_disassemble_aml(acpi_gbl_db_args[1], op); |
929 | #else |
930 | acpi_os_printf |
931 | (format: "The AML Disassembler is not configured/present\n" ); |
932 | #endif |
933 | break; |
934 | |
935 | case CMD_LOCKS: |
936 | |
937 | acpi_db_display_locks(); |
938 | break; |
939 | |
940 | case CMD_LOCALS: |
941 | |
942 | acpi_db_display_locals(); |
943 | break; |
944 | |
945 | case CMD_METHODS: |
946 | |
947 | status = acpi_db_display_objects(obj_type_arg: "METHOD" , display_count_arg: acpi_gbl_db_args[1]); |
948 | break; |
949 | |
950 | case CMD_NAMESPACE: |
951 | |
952 | acpi_db_dump_namespace(start_arg: acpi_gbl_db_args[1], |
953 | depth_arg: acpi_gbl_db_args[2]); |
954 | break; |
955 | |
956 | case CMD_NOTIFY: |
957 | |
958 | temp = strtoul(acpi_gbl_db_args[2], NULL, 0); |
959 | acpi_db_send_notify(name: acpi_gbl_db_args[1], value: temp); |
960 | break; |
961 | |
962 | case CMD_OBJECTS: |
963 | |
964 | acpi_ut_strupr(src_string: acpi_gbl_db_args[1]); |
965 | status = |
966 | acpi_db_display_objects(obj_type_arg: acpi_gbl_db_args[1], |
967 | display_count_arg: acpi_gbl_db_args[2]); |
968 | break; |
969 | |
970 | case CMD_OSI: |
971 | |
972 | acpi_db_display_interfaces(action_arg: acpi_gbl_db_args[1], |
973 | interface_name_arg: acpi_gbl_db_args[2]); |
974 | break; |
975 | |
976 | case CMD_OWNER: |
977 | |
978 | acpi_db_dump_namespace_by_owner(owner_arg: acpi_gbl_db_args[1], |
979 | depth_arg: acpi_gbl_db_args[2]); |
980 | break; |
981 | |
982 | case CMD_PATHS: |
983 | |
984 | acpi_db_dump_namespace_paths(); |
985 | break; |
986 | |
987 | case CMD_PREFIX: |
988 | |
989 | acpi_db_set_scope(name: acpi_gbl_db_args[1]); |
990 | break; |
991 | |
992 | case CMD_REFERENCES: |
993 | |
994 | acpi_db_find_references(object_arg: acpi_gbl_db_args[1]); |
995 | break; |
996 | |
997 | case CMD_RESOURCES: |
998 | |
999 | acpi_db_display_resources(object_arg: acpi_gbl_db_args[1]); |
1000 | break; |
1001 | |
1002 | case CMD_RESULTS: |
1003 | |
1004 | acpi_db_display_results(); |
1005 | break; |
1006 | |
1007 | case CMD_SET: |
1008 | |
1009 | acpi_db_set_method_data(type_arg: acpi_gbl_db_args[1], |
1010 | index_arg: acpi_gbl_db_args[2], |
1011 | value_arg: acpi_gbl_db_args[3]); |
1012 | break; |
1013 | |
1014 | case CMD_STATS: |
1015 | |
1016 | status = acpi_db_display_statistics(type_arg: acpi_gbl_db_args[1]); |
1017 | break; |
1018 | |
1019 | case CMD_STOP: |
1020 | |
1021 | return (AE_NOT_IMPLEMENTED); |
1022 | |
1023 | case CMD_TABLES: |
1024 | |
1025 | acpi_db_display_table_info(table_arg: acpi_gbl_db_args[1]); |
1026 | break; |
1027 | |
1028 | case CMD_TEMPLATE: |
1029 | |
1030 | acpi_db_display_template(buffer_arg: acpi_gbl_db_args[1]); |
1031 | break; |
1032 | |
1033 | case CMD_TRACE: |
1034 | |
1035 | acpi_db_trace(enable_arg: acpi_gbl_db_args[1], method_arg: acpi_gbl_db_args[2], |
1036 | once_arg: acpi_gbl_db_args[3]); |
1037 | break; |
1038 | |
1039 | case CMD_TREE: |
1040 | |
1041 | acpi_db_display_calling_tree(); |
1042 | break; |
1043 | |
1044 | case CMD_TYPE: |
1045 | |
1046 | acpi_db_display_object_type(object_arg: acpi_gbl_db_args[1]); |
1047 | break; |
1048 | |
1049 | #ifdef ACPI_APPLICATION |
1050 | |
1051 | /* Hardware simulation commands. */ |
1052 | |
1053 | case CMD_ENABLEACPI: |
1054 | #if (!ACPI_REDUCED_HARDWARE) |
1055 | |
1056 | status = acpi_enable(); |
1057 | if (ACPI_FAILURE(status)) { |
1058 | acpi_os_printf("AcpiEnable failed (Status=%X)\n" , |
1059 | status); |
1060 | return (status); |
1061 | } |
1062 | #endif /* !ACPI_REDUCED_HARDWARE */ |
1063 | break; |
1064 | |
1065 | case CMD_EVENT: |
1066 | |
1067 | acpi_os_printf("Event command not implemented\n" ); |
1068 | break; |
1069 | |
1070 | case CMD_INTERRUPT: |
1071 | |
1072 | acpi_db_generate_interrupt(acpi_gbl_db_args[1]); |
1073 | break; |
1074 | |
1075 | case CMD_GPE: |
1076 | |
1077 | acpi_db_generate_gpe(acpi_gbl_db_args[1], acpi_gbl_db_args[2]); |
1078 | break; |
1079 | |
1080 | case CMD_GPES: |
1081 | |
1082 | acpi_db_display_gpes(); |
1083 | break; |
1084 | |
1085 | case CMD_SCI: |
1086 | |
1087 | acpi_db_generate_sci(); |
1088 | break; |
1089 | |
1090 | case CMD_SLEEP: |
1091 | |
1092 | status = acpi_db_sleep(acpi_gbl_db_args[1]); |
1093 | break; |
1094 | |
1095 | /* File I/O commands. */ |
1096 | |
1097 | case CMD_CLOSE: |
1098 | |
1099 | acpi_db_close_debug_file(); |
1100 | break; |
1101 | |
1102 | case CMD_LOAD:{ |
1103 | struct acpi_new_table_desc *list_head = NULL; |
1104 | |
1105 | status = |
1106 | ac_get_all_tables_from_file(acpi_gbl_db_args[1], |
1107 | ACPI_GET_ALL_TABLES, |
1108 | &list_head); |
1109 | if (ACPI_SUCCESS(status)) { |
1110 | acpi_db_load_tables(list_head); |
1111 | } |
1112 | } |
1113 | break; |
1114 | |
1115 | case CMD_OPEN: |
1116 | |
1117 | acpi_db_open_debug_file(acpi_gbl_db_args[1]); |
1118 | break; |
1119 | |
1120 | /* User space commands. */ |
1121 | |
1122 | case CMD_TERMINATE: |
1123 | |
1124 | acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
1125 | acpi_ut_subsystem_shutdown(); |
1126 | |
1127 | /* |
1128 | * TBD: [Restructure] Need some way to re-initialize without |
1129 | * re-creating the semaphores! |
1130 | */ |
1131 | |
1132 | acpi_gbl_db_terminate_loop = TRUE; |
1133 | /* acpi_initialize (NULL); */ |
1134 | break; |
1135 | |
1136 | case CMD_BACKGROUND: |
1137 | |
1138 | acpi_db_create_execution_thread(acpi_gbl_db_args[1], |
1139 | &acpi_gbl_db_args[2], |
1140 | &acpi_gbl_db_arg_types[2]); |
1141 | break; |
1142 | |
1143 | case CMD_THREADS: |
1144 | |
1145 | acpi_db_create_execution_threads(acpi_gbl_db_args[1], |
1146 | acpi_gbl_db_args[2], |
1147 | acpi_gbl_db_args[3]); |
1148 | break; |
1149 | |
1150 | /* Debug test commands. */ |
1151 | |
1152 | case CMD_PREDEFINED: |
1153 | |
1154 | acpi_db_check_predefined_names(); |
1155 | break; |
1156 | |
1157 | case CMD_TEST: |
1158 | |
1159 | acpi_db_execute_test(acpi_gbl_db_args[1]); |
1160 | break; |
1161 | |
1162 | case CMD_UNLOAD: |
1163 | |
1164 | acpi_db_unload_acpi_table(acpi_gbl_db_args[1]); |
1165 | break; |
1166 | #endif |
1167 | |
1168 | case CMD_EXIT: |
1169 | case CMD_QUIT: |
1170 | |
1171 | if (op) { |
1172 | acpi_os_printf(format: "Method execution terminated\n" ); |
1173 | return (AE_CTRL_TERMINATE); |
1174 | } |
1175 | |
1176 | if (!acpi_gbl_db_output_to_file) { |
1177 | acpi_dbg_level = ACPI_DEBUG_DEFAULT; |
1178 | } |
1179 | #ifdef ACPI_APPLICATION |
1180 | acpi_db_close_debug_file(); |
1181 | #endif |
1182 | acpi_gbl_db_terminate_loop = TRUE; |
1183 | return (AE_CTRL_TERMINATE); |
1184 | |
1185 | case CMD_NOT_FOUND: |
1186 | default: |
1187 | |
1188 | acpi_os_printf(format: "%s: unknown command\n" , acpi_gbl_db_args[0]); |
1189 | return (AE_CTRL_TRUE); |
1190 | } |
1191 | |
1192 | if (ACPI_SUCCESS(status)) { |
1193 | status = AE_CTRL_TRUE; |
1194 | } |
1195 | |
1196 | return (status); |
1197 | } |
1198 | |
1199 | /******************************************************************************* |
1200 | * |
1201 | * FUNCTION: acpi_db_execute_thread |
1202 | * |
1203 | * PARAMETERS: context - Not used |
1204 | * |
1205 | * RETURN: None |
1206 | * |
1207 | * DESCRIPTION: Debugger execute thread. Waits for a command line, then |
1208 | * simply dispatches it. |
1209 | * |
1210 | ******************************************************************************/ |
1211 | |
1212 | void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context) |
1213 | { |
1214 | |
1215 | (void)acpi_db_user_commands(); |
1216 | acpi_gbl_db_threads_terminated = TRUE; |
1217 | } |
1218 | |
1219 | /******************************************************************************* |
1220 | * |
1221 | * FUNCTION: acpi_db_user_commands |
1222 | * |
1223 | * PARAMETERS: None |
1224 | * |
1225 | * RETURN: None |
1226 | * |
1227 | * DESCRIPTION: Command line execution for the AML debugger. Commands are |
1228 | * matched and dispatched here. |
1229 | * |
1230 | ******************************************************************************/ |
1231 | |
1232 | acpi_status acpi_db_user_commands(void) |
1233 | { |
1234 | acpi_status status = AE_OK; |
1235 | |
1236 | acpi_os_printf(format: "\n" ); |
1237 | |
1238 | /* TBD: [Restructure] Need a separate command line buffer for step mode */ |
1239 | |
1240 | while (!acpi_gbl_db_terminate_loop) { |
1241 | |
1242 | /* Wait the readiness of the command */ |
1243 | |
1244 | status = acpi_os_wait_command_ready(); |
1245 | if (ACPI_FAILURE(status)) { |
1246 | break; |
1247 | } |
1248 | |
1249 | /* Just call to the command line interpreter */ |
1250 | |
1251 | acpi_gbl_method_executing = FALSE; |
1252 | acpi_gbl_step_to_next_call = FALSE; |
1253 | |
1254 | (void)acpi_db_command_dispatch(input_buffer: acpi_gbl_db_line_buf, NULL, |
1255 | NULL); |
1256 | |
1257 | /* Notify the completion of the command */ |
1258 | |
1259 | status = acpi_os_notify_command_complete(); |
1260 | if (ACPI_FAILURE(status)) { |
1261 | break; |
1262 | } |
1263 | } |
1264 | |
1265 | if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) { |
1266 | ACPI_EXCEPTION((AE_INFO, status, "While parsing command line" )); |
1267 | } |
1268 | return (status); |
1269 | } |
1270 | |