2 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de
3 * Copyright 2006, Stephan Aßmus, superstippi@gmx.de
4 * Distributed under the terms of the MIT License.
16 #include <KernelExport.h>
18 #include <debug_heap.h>
20 #include "debug_commands.h"
21 #include "debug_variables.h"
27 commandLine := ( commandPipe [ ";" commandLine ] ) | assignment
28 expression := term | assignment
29 assignment := lhs ( "=" | "+=" | "-=" | "*=" | "/=" | "%=" )
31 lhs := variable | dereference
33 sum := product ( ( "+" | "-" ) product )*
34 product := unary ( ( "*" | "/" | "%" ) unary )*
35 unary := atom | ( "-" unary ) | dereference
36 dereference := "*" [ "{" expression "}" ] unary
37 atom := variable | ( "(" expression ")" ) | ( "[" command "]" )
38 variable := identifier
39 identifier := ( "$" | "@" | "_" | "a" - "z" | "A" - "Z" )
40 ( "_" | "a" - "z" | "A" - "Z" | "0" - "9" )*
41 commandPipe := command ( "|" command )*
42 command := identifier argument*
43 argument := ( "(" expression ")" ) | ( "[" commandLine "]" )
44 | unquotedString | quotedString
48 static const int kMaxTokenLength
= 128;
49 static const int kJumpBufferCount
= 10;
51 static const int kMaxArgumentCount
= 64;
53 static jmp_buf sJumpBuffers
[kJumpBufferCount
];
54 static int sNextJumpBufferIndex
= 0;
56 static char sExceptionMessage
[128];
57 static int sExceptionPosition
;
59 static char sTempBuffer
[128];
60 // for composing debug output etc.
63 TOKEN_ASSIGN_FLAG
= 0x100,
64 TOKEN_FLAGS
= TOKEN_ASSIGN_FLAG
,
66 TOKEN_IDENTIFIER
= 'a',
77 TOKEN_ASSIGN
= '=' | TOKEN_ASSIGN_FLAG
,
78 TOKEN_PLUS_ASSIGN
= TOKEN_PLUS
| TOKEN_ASSIGN_FLAG
,
79 TOKEN_MINUS_ASSIGN
= TOKEN_MINUS
| TOKEN_ASSIGN_FLAG
,
80 TOKEN_STAR_ASSIGN
= TOKEN_STAR
| TOKEN_ASSIGN_FLAG
,
81 TOKEN_SLASH_ASSIGN
= TOKEN_SLASH
| TOKEN_ASSIGN_FLAG
,
82 TOKEN_MODULO_ASSIGN
= TOKEN_MODULO
| TOKEN_ASSIGN_FLAG
,
84 TOKEN_OPENING_PARENTHESIS
= '(',
85 TOKEN_CLOSING_PARENTHESIS
= ')',
86 TOKEN_OPENING_BRACKET
= '[',
87 TOKEN_CLOSING_BRACKET
= ']',
88 TOKEN_OPENING_BRACE
= '{',
89 TOKEN_CLOSING_BRACE
= '}',
92 TOKEN_SEMICOLON
= ';',
97 TOKEN_END_OF_LINE
= '\n',
101 char string
[kMaxTokenLength
];
106 void SetTo(const char* string
, int32 length
, int32 position
, int32 type
)
108 length
= min_c((size_t)length
, (sizeof(this->string
) - 1));
109 strlcpy(this->string
, string
, length
+ 1);
112 this->position
= position
;
125 // #pragma mark - exceptions
129 parse_exception(const char* message
, int32 position
)
131 if (sNextJumpBufferIndex
== 0) {
132 kprintf_unfiltered("parse_exception(): No jump buffer!\n");
133 kprintf_unfiltered("exception: \"%s\", position: %" B_PRId32
"\n",
138 strlcpy(sExceptionMessage
, message
, sizeof(sExceptionMessage
));
139 sExceptionPosition
= position
;
141 longjmp(sJumpBuffers
[sNextJumpBufferIndex
- 1], 1);
146 checked_malloc(size_t size
)
148 void* address
= debug_malloc(size
);
149 if (address
== NULL
) {
150 parse_exception("out of memory for command execution", -1);
158 // #pragma mark - Tokenizer
163 Tokenizer(const char* string
)
164 : fCommandMode(false)
169 void SetTo(const char* string
)
171 fString
= fCurrentChar
= string
;
172 fCurrentToken
.Unset();
176 void SetPosition(int32 position
)
178 fCurrentChar
= fString
+ position
;
179 fCurrentToken
.Unset();
183 void SetCommandMode(bool commandMode
)
185 if (fCommandMode
== commandMode
)
188 fCommandMode
= commandMode
;
191 // We can't reuse the token, since the parsing mode changed.
192 SetPosition(fCurrentToken
.position
);
196 const char* String() const
201 const Token
& NextToken()
203 if (fCurrentToken
.type
== TOKEN_END_OF_LINE
)
204 return fCurrentToken
;
208 return fCurrentToken
;
211 while (*fCurrentChar
!= 0 && isspace(*fCurrentChar
))
214 if (*fCurrentChar
== 0) {
215 fCurrentToken
.SetTo("", 0, _CurrentPos(), TOKEN_END_OF_LINE
);
216 return fCurrentToken
;
219 return (fCommandMode
? _NextTokenCommand() : _NextTokenExpression());
222 const Token
& CurrentToken() const
224 return fCurrentToken
;
233 const Token
& _NextTokenExpression()
235 if (isdigit(*fCurrentChar
)) {
237 const char* begin
= fCurrentChar
++;
239 if (*fCurrentChar
== 'x') {
242 while (*fCurrentChar
!= 0
243 && (isdigit(*fCurrentChar
)
244 || strchr("abcdefABCDEF", *fCurrentChar
))) {
248 if (fCurrentChar
- begin
== 2)
249 parse_exception("invalid hex number", begin
- fString
);
253 while (*fCurrentChar
!= 0 && isdigit(*fCurrentChar
))
257 int32 length
= fCurrentChar
- begin
;
258 fCurrentToken
.SetTo(begin
, length
, _CurrentPos() - length
,
260 fCurrentToken
.value
= strtoull(fCurrentToken
.string
, NULL
, 0);
262 } else if (isalpha(*fCurrentChar
) || *fCurrentChar
== '_'
263 || *fCurrentChar
== '$' || *fCurrentChar
== '@') {
265 const char* begin
= fCurrentChar
;
267 while (*fCurrentChar
!= 0
268 && (isalpha(*fCurrentChar
) || *fCurrentChar
== '_'
269 || isdigit(*fCurrentChar
))) {
273 int32 length
= fCurrentChar
- begin
;
274 fCurrentToken
.SetTo(begin
, length
, _CurrentPos() - length
,
278 const char* begin
= fCurrentChar
;
279 char c
= *fCurrentChar
;
291 if (*fCurrentChar
== '=') {
293 flags
= TOKEN_ASSIGN_FLAG
;
304 int32 length
= fCurrentChar
- begin
;
305 fCurrentToken
.SetTo(begin
, length
, _CurrentPos() - length
,
326 return fCurrentToken
;
329 const Token
& _NextTokenCommand()
331 switch (*fCurrentChar
) {
338 fCurrentToken
.SetTo(fCurrentChar
, 1, _CurrentPos(),
341 return fCurrentToken
;
343 return _QuotedString();
346 return _UnquotedString();
350 const Token
& _QuotedString()
352 const char* begin
= fCurrentChar
++;
355 while (*fCurrentChar
!= '\0' && *fCurrentChar
!= '"') {
356 char c
= *fCurrentChar
;
369 >= sizeof(fCurrentToken
.string
) - 1) {
370 parse_exception("quoted string too long", begin
- fString
);
373 fCurrentToken
.string
[length
++] = c
;
376 if (*fCurrentChar
== '\0') {
377 parse_exception("unexpected end of line while "
378 "parsing quoted string", begin
- fString
);
383 fCurrentToken
.string
[length
] = '\0';
384 fCurrentToken
.value
= 0;
385 fCurrentToken
.type
= TOKEN_STRING
;
386 fCurrentToken
.position
= begin
- fString
;
388 return fCurrentToken
;
391 const Token
& _UnquotedString()
393 const char* begin
= fCurrentChar
;
395 while (*fCurrentChar
!= 0 && !_IsUnquotedDelimitingChar(*fCurrentChar
))
398 int32 length
= fCurrentChar
- begin
;
399 fCurrentToken
.SetTo(begin
, length
, _CurrentPos() - length
,
402 return fCurrentToken
;
405 bool _IsUnquotedDelimitingChar(char c
)
418 case '|': // TODO: Move when we support & and | in expressions.
430 return !fCommandMode
;
437 int32
_CurrentPos() const
439 return fCurrentChar
- fString
;
444 const char* fCurrentChar
;
451 // #pragma mark - ExpressionParser
454 class ExpressionParser
{
459 uint64
EvaluateExpression(
460 const char* expressionString
);
461 uint64
EvaluateCommand(
462 const char* expressionString
,
464 status_t
ParseNextCommandArgument(
465 const char** expressionString
, char* buffer
,
469 uint64
_ParseExpression(bool expectAssignment
= false);
470 uint64
_ParseCommandPipe(int& returnCode
);
472 debugger_command_pipe_segment
& segment
);
473 bool _ParseArgument(int& argc
, char** argv
);
474 void _GetUnparsedArgument(int& argc
, char** argv
);
475 void _AddArgument(int& argc
, char** argv
,
476 const char* argument
, int32 length
= -1);
477 uint64
_ParseSum(bool useValue
, uint64 value
);
478 uint64
_ParseProduct();
479 uint64
_ParsePower();
480 uint64
_ParseUnary();
481 uint64
_ParseDereference(void** _address
,
485 const Token
& _EatToken(int32 type
);
487 Tokenizer fTokenizer
;
491 ExpressionParser::ExpressionParser()
497 ExpressionParser::~ExpressionParser()
503 ExpressionParser::EvaluateExpression(const char* expressionString
)
505 fTokenizer
.SetTo(expressionString
);
507 uint64 value
= _ParseExpression();
508 const Token
& token
= fTokenizer
.NextToken();
509 if (token
.type
!= TOKEN_END_OF_LINE
)
510 parse_exception("parse error", token
.position
);
517 ExpressionParser::EvaluateCommand(const char* expressionString
, int& returnCode
)
519 fTokenizer
.SetTo(expressionString
);
521 // Allowed are command or assignment. A command always starts with an
522 // identifier, an assignment either with an identifier (variable name) or
523 // a dereferenced address.
524 const Token
& token
= fTokenizer
.NextToken();
528 int32 startPosition
= token
.position
;
530 if (token
.type
== TOKEN_IDENTIFIER
) {
531 fTokenizer
.NextToken();
533 if (token
.type
& TOKEN_ASSIGN_FLAG
) {
535 fTokenizer
.SetPosition(startPosition
);
536 value
= _ParseExpression(true);
539 // no assignment, so let's assume it's a command
540 fTokenizer
.SetPosition(startPosition
);
541 fTokenizer
.SetCommandMode(true);
542 value
= _ParseCommandPipe(returnCode
);
544 } else if (token
.type
== TOKEN_STAR
) {
545 // dereferenced address -- assignment
546 fTokenizer
.SetPosition(startPosition
);
547 value
= _ParseExpression(true);
550 parse_exception("expected command or assignment", token
.position
);
552 // might be chained with ";"
553 if (fTokenizer
.NextToken().type
!= TOKEN_SEMICOLON
)
556 fTokenizer
.SetCommandMode(false);
557 fTokenizer
.NextToken();
560 if (token
.type
!= TOKEN_END_OF_LINE
)
561 parse_exception("parse error", token
.position
);
568 ExpressionParser::ParseNextCommandArgument(const char** expressionString
,
569 char* buffer
, size_t bufferSize
)
571 fTokenizer
.SetTo(*expressionString
);
572 fTokenizer
.SetCommandMode(true);
574 if (fTokenizer
.NextToken().type
== TOKEN_END_OF_LINE
)
575 return B_ENTRY_NOT_FOUND
;
577 fTokenizer
.RewindToken();
581 if (!_ParseArgument(argc
, argv
))
584 strlcpy(buffer
, argv
[0], bufferSize
);
586 const Token
& token
= fTokenizer
.NextToken();
587 if (token
.type
== TOKEN_END_OF_LINE
)
588 *expressionString
= NULL
;
590 *expressionString
+= token
.position
;
597 ExpressionParser::_ParseExpression(bool expectAssignment
)
599 const Token
& token
= fTokenizer
.NextToken();
600 int32 position
= token
.position
;
601 if (token
.type
== TOKEN_IDENTIFIER
) {
602 char variable
[MAX_DEBUG_VARIABLE_NAME_LEN
];
603 strlcpy(variable
, token
.string
, sizeof(variable
));
605 int32 assignmentType
= fTokenizer
.NextToken().type
;
606 if (assignmentType
& TOKEN_ASSIGN_FLAG
) {
608 uint64 rhs
= _ParseExpression();
610 // handle the standard assignment separately -- the other kinds
611 // need the variable to be defined
612 if (assignmentType
== TOKEN_ASSIGN
) {
613 if (!set_debug_variable(variable
, rhs
)) {
614 snprintf(sTempBuffer
, sizeof(sTempBuffer
),
615 "failed to set value for variable \"%s\"",
617 parse_exception(sTempBuffer
, position
);
623 // variable must be defined
624 if (!is_debug_variable_defined(variable
)) {
625 snprintf(sTempBuffer
, sizeof(sTempBuffer
),
626 "variable \"%s\" not defined in modifying assignment",
628 parse_exception(sTempBuffer
, position
);
631 uint64 variableValue
= get_debug_variable(variable
, 0);
633 // check for division by zero for the respective assignment types
634 if ((assignmentType
== TOKEN_SLASH_ASSIGN
635 || assignmentType
== TOKEN_MODULO_ASSIGN
)
637 parse_exception("division by zero", position
);
640 // compute the new variable value
641 switch (assignmentType
) {
642 case TOKEN_PLUS_ASSIGN
:
643 variableValue
+= rhs
;
645 case TOKEN_MINUS_ASSIGN
:
646 variableValue
-= rhs
;
648 case TOKEN_STAR_ASSIGN
:
649 variableValue
*= rhs
;
651 case TOKEN_SLASH_ASSIGN
:
652 variableValue
/= rhs
;
654 case TOKEN_MODULO_ASSIGN
:
655 variableValue
%= rhs
;
658 parse_exception("internal error: unknown assignment token",
663 set_debug_variable(variable
, variableValue
);
664 return variableValue
;
666 } else if (token
.type
== TOKEN_STAR
) {
669 uint64 value
= _ParseDereference(&address
, &size
);
671 int32 assignmentType
= fTokenizer
.NextToken().type
;
672 if (assignmentType
& TOKEN_ASSIGN_FLAG
) {
674 uint64 rhs
= _ParseExpression();
676 // check for division by zero for the respective assignment types
677 if ((assignmentType
== TOKEN_SLASH_ASSIGN
678 || assignmentType
== TOKEN_MODULO_ASSIGN
)
680 parse_exception("division by zero", position
);
683 // compute the new value
684 switch (assignmentType
) {
688 case TOKEN_PLUS_ASSIGN
:
691 case TOKEN_MINUS_ASSIGN
:
694 case TOKEN_STAR_ASSIGN
:
697 case TOKEN_SLASH_ASSIGN
:
700 case TOKEN_MODULO_ASSIGN
:
704 parse_exception("internal error: unknown assignment token",
709 // convert the value for writing to the address
713 *(uint8
*)&buffer
= value
;
716 *(uint16
*)&buffer
= value
;
719 *(uint32
*)&buffer
= value
;
726 if (debug_memcpy(B_CURRENT_TEAM
, address
, &buffer
, size
) != B_OK
) {
727 snprintf(sTempBuffer
, sizeof(sTempBuffer
),
728 "failed to write to address %p", address
);
729 parse_exception(sTempBuffer
, position
);
736 if (expectAssignment
) {
737 parse_exception("expected assignment",
738 fTokenizer
.CurrentToken().position
);
741 // no assignment -- reset to the identifier position and parse a sum
742 fTokenizer
.SetPosition(position
);
743 return _ParseSum(false, 0);
748 ExpressionParser::_ParseCommandPipe(int& returnCode
)
750 debugger_command_pipe
* pipe
= (debugger_command_pipe
*)checked_malloc(
751 sizeof(debugger_command_pipe
));
753 pipe
->segment_count
= 0;
754 pipe
->broken
= false;
757 if (pipe
->segment_count
>= MAX_DEBUGGER_COMMAND_PIPE_LENGTH
)
758 parse_exception("Pipe too long", fTokenizer
.NextToken().position
);
760 debugger_command_pipe_segment
& segment
761 = pipe
->segments
[pipe
->segment_count
];
762 segment
.index
= pipe
->segment_count
++;
764 _ParseCommand(segment
);
766 } while (fTokenizer
.NextToken().type
== TOKEN_PIPE
);
768 fTokenizer
.RewindToken();
771 returnCode
= invoke_debugger_command_pipe(pipe
);
775 return get_debug_variable("_", 0);
780 ExpressionParser::_ParseCommand(debugger_command_pipe_segment
& segment
)
782 fTokenizer
.SetCommandMode(false);
783 const Token
& token
= _EatToken(TOKEN_IDENTIFIER
);
784 fTokenizer
.SetCommandMode(true);
787 debugger_command
* command
= find_debugger_command(token
.string
, true,
790 if (command
== NULL
) {
792 snprintf(sTempBuffer
, sizeof(sTempBuffer
),
793 "Ambiguous command \"%s\". Use tab completion or enter "
794 "\"help %s\" get a list of matching commands.\n", token
.string
,
797 snprintf(sTempBuffer
, sizeof(sTempBuffer
),
798 "Unknown command \"%s\". Enter \"help\" to get a list of "
799 "all supported commands.\n", token
.string
);
802 parse_exception(sTempBuffer
, -1);
805 // allocate temporary buffer for the argument vector
806 char** argv
= (char**)checked_malloc(kMaxArgumentCount
* sizeof(char*));
808 argv
[argc
++] = (char*)command
->name
;
811 if ((command
->flags
& B_KDEBUG_DONT_PARSE_ARGUMENTS
) != 0) {
812 _GetUnparsedArgument(argc
, argv
);
814 while (fTokenizer
.NextToken().type
!= TOKEN_END_OF_LINE
) {
815 fTokenizer
.RewindToken();
816 if (!_ParseArgument(argc
, argv
))
821 if (segment
.index
> 0) {
822 if (argc
>= kMaxArgumentCount
)
823 parse_exception("too many arguments for command", 0);
828 segment
.command
= command
;
831 segment
.invocations
= 0;
836 ExpressionParser::_ParseArgument(int& argc
, char** argv
)
838 const Token
& token
= fTokenizer
.NextToken();
839 switch (token
.type
) {
840 case TOKEN_OPENING_PARENTHESIS
:
842 // this starts an expression
843 fTokenizer
.SetCommandMode(false);
844 uint64 value
= _ParseExpression();
845 fTokenizer
.SetCommandMode(true);
846 _EatToken(TOKEN_CLOSING_PARENTHESIS
);
848 snprintf(sTempBuffer
, sizeof(sTempBuffer
), "%" B_PRIu64
, value
);
849 _AddArgument(argc
, argv
, sTempBuffer
);
853 case TOKEN_OPENING_BRACKET
:
855 // this starts a sub command
857 uint64 value
= _ParseCommandPipe(returnValue
);
858 _EatToken(TOKEN_CLOSING_BRACKET
);
860 snprintf(sTempBuffer
, sizeof(sTempBuffer
), "%" B_PRIu64
, value
);
861 _AddArgument(argc
, argv
, sTempBuffer
);
867 _AddArgument(argc
, argv
, token
.string
);
870 case TOKEN_CLOSING_PARENTHESIS
:
871 case TOKEN_CLOSING_BRACKET
:
873 case TOKEN_SEMICOLON
:
874 // those don't belong to us
875 fTokenizer
.RewindToken();
880 snprintf(sTempBuffer
, sizeof(sTempBuffer
), "unexpected token "
881 "\"%s\"", token
.string
);
882 parse_exception(sTempBuffer
, token
.position
);
890 ExpressionParser::_GetUnparsedArgument(int& argc
, char** argv
)
892 int32 startPosition
= fTokenizer
.NextToken().position
;
893 fTokenizer
.RewindToken();
895 // match parentheses and brackets, but otherwise skip all tokens
896 int32 parentheses
= 0;
900 const Token
& token
= fTokenizer
.NextToken();
901 switch (token
.type
) {
902 case TOKEN_OPENING_PARENTHESIS
:
905 case TOKEN_OPENING_BRACKET
:
908 case TOKEN_CLOSING_PARENTHESIS
:
914 case TOKEN_CLOSING_BRACKET
:
921 case TOKEN_SEMICOLON
:
922 if (parentheses
== 0 && brackets
== 0)
925 case TOKEN_END_OF_LINE
:
931 int32 endPosition
= fTokenizer
.CurrentToken().position
;
932 fTokenizer
.RewindToken();
934 // add the argument only, if it's not just all spaces
935 const char* arg
= fTokenizer
.String() + startPosition
;
936 int32 argLen
= endPosition
- startPosition
;
937 bool allSpaces
= true;
938 for (int32 i
= 0; allSpaces
&& i
< argLen
; i
++)
939 allSpaces
= isspace(arg
[i
]);
942 _AddArgument(argc
, argv
, arg
, argLen
);
947 ExpressionParser::_AddArgument(int& argc
, char** argv
, const char* argument
,
950 if (argc
== kMaxArgumentCount
)
951 parse_exception("too many arguments for command", 0);
954 length
= strlen(argument
);
956 char* buffer
= (char*)checked_malloc(length
);
957 strlcpy(buffer
, argument
, length
);
959 argv
[argc
++] = buffer
;
964 ExpressionParser::_ParseSum(bool useValue
, uint64 value
)
967 value
= _ParseProduct();
970 const Token
& token
= fTokenizer
.NextToken();
971 switch (token
.type
) {
973 value
= value
+ _ParseProduct();
976 value
= value
- _ParseProduct();
980 fTokenizer
.RewindToken();
988 ExpressionParser::_ParseProduct()
990 uint64 value
= _ParseUnary();
993 Token token
= fTokenizer
.NextToken();
994 switch (token
.type
) {
996 value
= value
* _ParseUnary();
999 uint64 rhs
= _ParseUnary();
1001 parse_exception("division by zero", token
.position
);
1002 value
= value
/ rhs
;
1005 case TOKEN_MODULO
: {
1006 uint64 rhs
= _ParseUnary();
1008 parse_exception("modulo by zero", token
.position
);
1009 value
= value
% rhs
;
1014 fTokenizer
.RewindToken();
1022 ExpressionParser::_ParseUnary()
1024 switch (fTokenizer
.NextToken().type
) {
1026 return -_ParseUnary();
1029 return _ParseDereference(NULL
, NULL
);
1032 fTokenizer
.RewindToken();
1033 return _ParseAtom();
1041 ExpressionParser::_ParseDereference(void** _address
, uint32
* _size
)
1043 int32 starPosition
= fTokenizer
.CurrentToken().position
;
1045 // optional "{ ... }" specifying the size to read
1047 if (fTokenizer
.NextToken().type
== TOKEN_OPENING_BRACE
) {
1048 int32 position
= fTokenizer
.CurrentToken().position
;
1049 size
= _ParseExpression();
1051 if (size
!= 1 && size
!= 2 && size
!= 4 && size
!= 8) {
1052 snprintf(sTempBuffer
, sizeof(sTempBuffer
),
1053 "invalid size (%" B_PRIu64
") for unary * operator", size
);
1054 parse_exception(sTempBuffer
, position
);
1057 _EatToken(TOKEN_CLOSING_BRACE
);
1059 fTokenizer
.RewindToken();
1061 const void* address
= (const void*)(addr_t
)_ParseUnary();
1063 // read bytes from address into a tempory buffer
1065 if (debug_memcpy(B_CURRENT_TEAM
, &buffer
, address
, size
) != B_OK
) {
1066 snprintf(sTempBuffer
, sizeof(sTempBuffer
),
1067 "failed to dereference address %p", address
);
1068 parse_exception(sTempBuffer
, starPosition
);
1071 // convert the value to uint64
1075 value
= *(uint8
*)&buffer
;
1078 value
= *(uint16
*)&buffer
;
1081 value
= *(uint32
*)&buffer
;
1088 if (_address
!= NULL
)
1089 *_address
= (void*)address
;
1098 ExpressionParser::_ParseAtom()
1100 const Token
& token
= fTokenizer
.NextToken();
1101 if (token
.type
== TOKEN_END_OF_LINE
)
1102 parse_exception("unexpected end of expression", token
.position
);
1104 if (token
.type
== TOKEN_CONSTANT
)
1107 if (token
.type
== TOKEN_IDENTIFIER
) {
1108 if (!is_debug_variable_defined(token
.string
)) {
1109 snprintf(sTempBuffer
, sizeof(sTempBuffer
),
1110 "variable '%s' undefined", token
.string
);
1111 parse_exception(sTempBuffer
, token
.position
);
1114 return get_debug_variable(token
.string
, 0);
1117 if (token
.type
== TOKEN_OPENING_PARENTHESIS
) {
1118 uint64 value
= _ParseExpression();
1120 _EatToken(TOKEN_CLOSING_PARENTHESIS
);
1125 // it can only be a "[ command ]" expression now
1126 fTokenizer
.RewindToken();
1128 _EatToken(TOKEN_OPENING_BRACKET
);
1130 fTokenizer
.SetCommandMode(true);
1132 uint64 value
= _ParseCommandPipe(returnValue
);
1133 fTokenizer
.SetCommandMode(false);
1135 _EatToken(TOKEN_CLOSING_BRACKET
);
1142 ExpressionParser::_EatToken(int32 type
)
1144 const Token
& token
= fTokenizer
.NextToken();
1145 if (token
.type
!= type
) {
1146 snprintf(sTempBuffer
, sizeof(sTempBuffer
), "expected token type '%c', "
1147 "got token '%s'", char(type
& ~TOKEN_FLAGS
), token
.string
);
1148 parse_exception(sTempBuffer
, token
.position
);
1160 evaluate_debug_expression(const char* expression
, uint64
* _result
, bool silent
)
1162 if (sNextJumpBufferIndex
>= kJumpBufferCount
) {
1163 kprintf_unfiltered("evaluate_debug_expression(): Out of jump buffers "
1164 "for exception handling\n");
1170 DebugAllocPoolScope allocPoolScope
;
1171 // Will clean up all allocations when we return.
1173 if (setjmp(sJumpBuffers
[sNextJumpBufferIndex
++]) == 0) {
1174 result
= ExpressionParser().EvaluateExpression(expression
);
1180 if (sExceptionPosition
>= 0) {
1181 kprintf_unfiltered("%s, at position: %d, in expression: %s\n",
1182 sExceptionMessage
, sExceptionPosition
, expression
);
1184 kprintf_unfiltered("%s", sExceptionMessage
);
1188 sNextJumpBufferIndex
--;
1190 if (success
&& _result
!= NULL
)
1198 evaluate_debug_command(const char* commandLine
)
1200 if (sNextJumpBufferIndex
>= kJumpBufferCount
) {
1201 kprintf_unfiltered("evaluate_debug_command(): Out of jump buffers for "
1202 "exception handling\n");
1207 DebugAllocPoolScope allocPoolScope
;
1208 // Will clean up all allocations when we return.
1210 if (setjmp(sJumpBuffers
[sNextJumpBufferIndex
++]) == 0) {
1211 ExpressionParser().EvaluateCommand(commandLine
, returnCode
);
1213 if (sExceptionPosition
>= 0) {
1214 kprintf_unfiltered("%s, at position: %d, in command line: %s\n",
1215 sExceptionMessage
, sExceptionPosition
, commandLine
);
1217 kprintf_unfiltered("%s", sExceptionMessage
);
1220 sNextJumpBufferIndex
--;
1227 parse_next_debug_command_argument(const char** expressionString
, char* buffer
,
1230 if (sNextJumpBufferIndex
>= kJumpBufferCount
) {
1231 kprintf_unfiltered("parse_next_debug_command_argument(): Out of jump "
1232 "buffers for exception handling\n");
1237 DebugAllocPoolScope allocPoolScope
;
1238 // Will clean up all allocations when we return.
1240 if (setjmp(sJumpBuffers
[sNextJumpBufferIndex
++]) == 0) {
1241 error
= ExpressionParser().ParseNextCommandArgument(expressionString
,
1242 buffer
, bufferSize
);
1244 if (sExceptionPosition
>= 0) {
1245 kprintf_unfiltered("%s, at position: %d, in command line: %s\n",
1246 sExceptionMessage
, sExceptionPosition
, *expressionString
);
1248 kprintf_unfiltered("%s", sExceptionMessage
);
1249 error
= B_BAD_VALUE
;
1252 sNextJumpBufferIndex
--;