xref: /haiku/src/system/kernel/debug/debug_parser.cpp (revision 2600324b57fa31cdea1627d584d314f2a579c4a8)
1 /*
2  * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de
3  * Copyright 2006, Stephan Aßmus, superstippi@gmx.de
4  * Distributed under the terms of the MIT License.
5  */
6 
7 #include <debug.h>
8 
9 #include <ctype.h>
10 #include <setjmp.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include <KernelExport.h>
16 
17 #include "debug_commands.h"
18 #include "debug_variables.h"
19 
20 
21 /*
22 	Grammar:
23 
24 	commandLine	:= commandPipe | ( "(" expression ")" )
25 	expression	:= term | assignment
26 	assignment	:= lhs ( "=" | "+=" | "-=" | "*=" | "/=" | "%=" )
27 				   expression
28 	lhs			:= variable | dereference
29 	term		:= sum
30 	sum			:= product ( ( "+" | "-" ) product )*
31 	product		:= unary ( ( "*" | "/" | "%" ) unary )*
32 	unary		:= atom | ( "-"  unary ) | dereference
33 	dereference	:= "*" [ "{" expression "}" ] unary
34 	atom		:= variable | ( "(" expression ")" ) | ( "[" command "]" )
35 	variable	:= identifier
36 	identifier	:= ( "$" | "_" | "a" - "z" | "A" - "Z" )
37 				   ( "_" | "a" - "z" | "A" - "Z" | "0" - "9" )*
38 	commandPipe	:= command ( "|" command )*
39 	command		:= identifier argument*
40 	argument	:= ( "(" expression ")" ) | ( "[" commandLine "]" )
41 				   | unquotedString | quotedString
42 */
43 
44 
45 static const int kMaxTokenLength = 128;
46 static const int kJumpBufferCount = 10;
47 
48 static const int kMaxArgumentCount = 64;
49 static const size_t kTemporaryStorageSize = 10240;
50 
51 static jmp_buf sJumpBuffers[kJumpBufferCount];
52 static int sNextJumpBufferIndex = 0;
53 
54 static char sExceptionMessage[128];
55 static int	sExceptionPosition;
56 
57 static char sTempBuffer[128];
58 	// for composing debug output etc.
59 
60 // temporary storage for command argument vectors and the arguments itself
61 static uint8	sTemporaryStorage[kTemporaryStorageSize];
62 static size_t	sTemporaryStorageUsed = 0;
63 
64 enum {
65 	TOKEN_ASSIGN_FLAG			= 0x100,
66 	TOKEN_FLAGS					= TOKEN_ASSIGN_FLAG,
67 
68 	TOKEN_IDENTIFIER			= 'a',
69 
70 	TOKEN_CONSTANT				= '0',
71 
72 	TOKEN_PLUS					= '+',
73 	TOKEN_MINUS					= '-',
74 
75 	TOKEN_STAR					= '*',
76 	TOKEN_SLASH					= '/',
77 	TOKEN_MODULO				= '%',
78 
79 	TOKEN_ASSIGN				= '='			| TOKEN_ASSIGN_FLAG,
80 	TOKEN_PLUS_ASSIGN			= TOKEN_PLUS	| TOKEN_ASSIGN_FLAG,
81 	TOKEN_MINUS_ASSIGN			= TOKEN_MINUS	| TOKEN_ASSIGN_FLAG,
82 	TOKEN_STAR_ASSIGN			= TOKEN_STAR	| TOKEN_ASSIGN_FLAG,
83 	TOKEN_SLASH_ASSIGN			= TOKEN_SLASH	| TOKEN_ASSIGN_FLAG,
84 	TOKEN_MODULO_ASSIGN			= TOKEN_MODULO	| TOKEN_ASSIGN_FLAG,
85 
86 	TOKEN_OPENING_PARENTHESIS	= '(',
87 	TOKEN_CLOSING_PARENTHESIS	= ')',
88 	TOKEN_OPENING_BRACKET		= '[',
89 	TOKEN_CLOSING_BRACKET		= ']',
90 	TOKEN_OPENING_BRACE			= '{',
91 	TOKEN_CLOSING_BRACE			= '}',
92 
93 	TOKEN_PIPE					= '|',
94 
95 	TOKEN_STRING				= '"',
96 	TOKEN_UNKNOWN				= '?',
97 	TOKEN_NONE					= ' ',
98 	TOKEN_END_OF_LINE			= '\n',
99 };
100 
101 struct Token {
102 	char	string[kMaxTokenLength];
103 	uint64	value;
104 	int32	type;
105 	int32	position;
106 
107 	void SetTo(const char* string, int32 length, int32 position, int32 type)
108 	{
109 		length = min_c((size_t)length, (sizeof(this->string) - 1));
110 		strlcpy(this->string, string, length + 1);
111 		this->type = type;
112 		this->value = 0;
113 		this->position = position;
114 	}
115 
116 	void Unset()
117 	{
118 		string[0] = '\0';
119 		value = 0;
120 		type = TOKEN_NONE;
121 		position = 0;
122 	}
123 };
124 
125 
126 // #pragma mark - exceptions
127 
128 
129 static void
130 parse_exception(const char* message, int32 position)
131 {
132 	if (sNextJumpBufferIndex == 0) {
133 		kprintf_unfiltered("parse_exception(): No jump buffer!\n");
134 		kprintf_unfiltered("exception: \"%s\", position: %lu\n", message,
135 			position);
136 		return;
137 	}
138 
139 	strlcpy(sExceptionMessage, message, sizeof(sExceptionMessage));
140 	sExceptionPosition = position;
141 
142 	longjmp(sJumpBuffers[sNextJumpBufferIndex - 1], 1);
143 }
144 
145 
146 // #pragma mark - temporary storage
147 
148 
149 static void*
150 allocate_temp_storage(size_t size)
151 {
152 	// 8 byte align
153 	size = (size + 7) & ~7;
154 
155 	if (sTemporaryStorageUsed + size > kTemporaryStorageSize) {
156 		parse_exception("out of temporary storage for command execution", -1);
157 		return NULL;
158 	}
159 
160 	void* buffer = sTemporaryStorage + sTemporaryStorageUsed;
161 	sTemporaryStorageUsed += size;
162 
163 	return buffer;
164 }
165 
166 
167 static void
168 free_temp_storage(void* _buffer)
169 {
170 	uint8* buffer = (uint8*)_buffer;
171 
172 	if (buffer == NULL)
173 		return;
174 
175 	// must be freed in the reverse allocation order
176 	if (buffer < sTemporaryStorage
177 		|| buffer > sTemporaryStorage + sTemporaryStorageUsed) {
178 		panic("Invalid pointer passed to free_temp_storage(): %p, temp "
179 			"storage base: %p", buffer, sTemporaryStorage);
180 		return;
181 	}
182 
183 	sTemporaryStorageUsed = buffer - sTemporaryStorage;
184 }
185 
186 
187 // #pragma mark - Tokenizer
188 
189 
190 class Tokenizer {
191 public:
192 	Tokenizer(const char* string)
193 		: fCommandMode(false)
194 	{
195 		SetTo(string);
196 	}
197 
198 	void SetTo(const char* string)
199 	{
200 		fString = fCurrentChar = string;
201 		fCurrentToken.Unset();
202 		fReuseToken = false;
203 	}
204 
205 	void SetPosition(int32 position)
206 	{
207 		fCurrentChar = fString + position;
208 		fCurrentToken.Unset();
209 		fReuseToken = false;
210 	}
211 
212 	void SetCommandMode(bool commandMode)
213 	{
214 		fCommandMode = commandMode;
215 	}
216 
217 	const char* String() const
218 	{
219 		return fString;
220 	}
221 
222 	const Token& NextToken()
223 	{
224 		if (fCurrentToken.type == TOKEN_END_OF_LINE)
225 			return fCurrentToken;
226 
227 		if (fReuseToken) {
228 			fReuseToken = false;
229 			return fCurrentToken;
230 		}
231 
232 		while (*fCurrentChar != 0 && isspace(*fCurrentChar))
233 			fCurrentChar++;
234 
235 		if (*fCurrentChar == 0) {
236 			fCurrentToken.SetTo("", 0, _CurrentPos(), TOKEN_END_OF_LINE);
237 			return fCurrentToken;
238 		}
239 
240 		return (fCommandMode ? _NextTokenCommand() : _NextTokenExpression());
241 	}
242 
243 	const Token& CurrentToken() const
244 	{
245 		return fCurrentToken;
246 	}
247 
248 	void RewindToken()
249 	{
250 		fReuseToken = true;
251 	}
252 
253  private:
254 	const Token& _NextTokenExpression()
255 	{
256 		if (isdigit(*fCurrentChar)) {
257 			// number
258 			const char* begin = fCurrentChar++;
259 
260 			if (*fCurrentChar == 'x') {
261 				// hex number
262 				fCurrentChar++;
263 				while (*fCurrentChar != 0
264 					&& (isdigit(*fCurrentChar)
265 						|| strchr("abcdefABCDEF", *fCurrentChar))) {
266 					fCurrentChar++;
267 				}
268 
269 				if (fCurrentChar - begin == 2)
270 					parse_exception("invalid hex number", begin - fString);
271 
272 			} else {
273 				// decimal number
274 				while (*fCurrentChar != 0 && isdigit(*fCurrentChar))
275 					fCurrentChar++;
276 			}
277 
278 			int32 length = fCurrentChar - begin;
279 			fCurrentToken.SetTo(begin, length, _CurrentPos() - length,
280 				TOKEN_CONSTANT);
281 			fCurrentToken.value = strtoull(fCurrentToken.string, NULL, 0);
282 
283 		} else if (isalpha(*fCurrentChar) || *fCurrentChar == '_'
284 				|| *fCurrentChar == '$') {
285 			// identifier
286 			const char* begin = fCurrentChar;
287 			fCurrentChar++;
288 			while (*fCurrentChar != 0
289 				&& (isalpha(*fCurrentChar) || *fCurrentChar == '_'
290 					|| isdigit(*fCurrentChar))) {
291 				fCurrentChar++;
292 			}
293 
294 			int32 length = fCurrentChar - begin;
295 			fCurrentToken.SetTo(begin, length, _CurrentPos() - length,
296 				TOKEN_IDENTIFIER);
297 
298 		} else {
299 			const char* begin = fCurrentChar;
300 			char c = *fCurrentChar;
301 			fCurrentChar++;
302 			int32 flags = 0;
303 
304 			switch (c) {
305 				case '=':
306 					fCurrentChar--;
307 				case '+':
308 				case '-':
309 				case '*':
310 				case '/':
311 				case '%':
312 					if (*fCurrentChar == '=') {
313 						fCurrentChar++;
314 						flags = TOKEN_ASSIGN_FLAG;
315 					}
316 
317 				case '(':
318 				case ')':
319 				case '[':
320 				case ']':
321 				case '{':
322 				case '}':
323 				{
324 					int32 length = fCurrentChar - begin;
325 					fCurrentToken.SetTo(begin, length, _CurrentPos() - length,
326 						c | flags);
327 					break;
328 				}
329 
330 				case '"':
331 				{
332 					fCurrentChar--;
333 					_QuotedString();
334 					break;
335 				}
336 
337 				default:
338 				{
339 					fCurrentChar--;
340 					_UnquotedString();
341 					break;
342 				}
343 			}
344 		}
345 
346 		return fCurrentToken;
347 	}
348 
349 	const Token& _NextTokenCommand()
350 	{
351 		switch (*fCurrentChar) {
352 			case '(':
353 			case ')':
354 			case '[':
355 			case ']':
356 			case '|':
357 				fCurrentToken.SetTo(fCurrentChar, 1, _CurrentPos(),
358 					*fCurrentChar);
359 				fCurrentChar++;
360 				return fCurrentToken;
361 			case '"':
362 				return _QuotedString();
363 
364 			default:
365 				return _UnquotedString();
366 		}
367 	}
368 
369 	const Token& _QuotedString()
370 	{
371 		const char* begin = fCurrentChar++;
372 		int32 length = 0;
373 
374 		while (*fCurrentChar != '\0' && *fCurrentChar != '"') {
375 			char c = *fCurrentChar;
376 			fCurrentChar++;
377 
378 			if (c == '\\') {
379 				// an escaped char
380 				c = *fCurrentChar;
381 				fCurrentChar++;
382 
383 				if (c == '\0')
384 					break;
385 			}
386 
387 			if ((size_t)length
388 					>= sizeof(fCurrentToken.string) - 1) {
389 				parse_exception("quoted string too long", begin - fString);
390 			}
391 
392 			fCurrentToken.string[length++] = c;
393 		}
394 
395 		if (*fCurrentChar == '\0') {
396 			parse_exception("unexpected end of line while "
397 				"parsing quoted string", begin - fString);
398 		}
399 
400 		fCurrentChar++;
401 
402 		fCurrentToken.string[length] = '\0';
403 		fCurrentToken.value = 0;
404 		fCurrentToken.type = TOKEN_STRING;
405 		fCurrentToken.position = begin - fString;
406 
407 		return fCurrentToken;
408 	}
409 
410 	const Token& _UnquotedString()
411 	{
412 		const char* begin = fCurrentChar;
413 
414 		while (*fCurrentChar != 0 && !_IsUnquotedDelimitingChar(*fCurrentChar))
415 			fCurrentChar++;
416 
417 		int32 length = fCurrentChar - begin;
418 		fCurrentToken.SetTo(begin, length, _CurrentPos() - length,
419 			TOKEN_UNKNOWN);
420 
421 		return fCurrentToken;
422 	}
423 
424 	bool _IsUnquotedDelimitingChar(char c)
425 	{
426 		if (isspace(c))
427 			return true;
428 
429 		switch (c) {
430 			case '(':
431 			case ')':
432 			case '[':
433 			case ']':
434 			case '"':
435 				return true;
436 
437 			case '{':
438 			case '}':
439 			case '=':
440 			case '+':
441 			case '-':
442 			case '*':
443 			case '/':
444 			case '%':
445 				return !fCommandMode;
446 
447 			default:
448 				return false;
449 		}
450 	}
451 
452 	int32 _CurrentPos() const
453 	{
454 		return fCurrentChar - fString;
455 	}
456 
457 private:
458 	const char*	fString;
459 	const char*	fCurrentChar;
460 	Token		fCurrentToken;
461 	bool		fReuseToken;
462 	bool		fCommandMode;
463 };
464 
465 
466 // #pragma mark - ExpressionParser
467 
468 
469 class ExpressionParser {
470  public:
471 								ExpressionParser();
472 								~ExpressionParser();
473 
474 			uint64				EvaluateExpression(
475 									const char* expressionString);
476 			uint64				EvaluateCommand(
477 									const char* expressionString,
478 									int& returnCode);
479 			status_t			ParseNextCommandArgument(
480 									const char** expressionString, char* buffer,
481 									size_t bufferSize);
482 
483  private:
484 			uint64				_ParseExpression(bool expectAssignment = false);
485 			uint64				_ParseCommandPipe(int& returnCode);
486 			void				_ParseCommand(
487 									debugger_command_pipe_segment& segment);
488 			bool				_ParseArgument(int& argc, char** argv);
489 			void				_GetUnparsedArgument(int& argc, char** argv);
490 			void				_AddArgument(int& argc, char** argv,
491 									const char* argument, int32 length = -1);
492 			uint64				_ParseSum(bool useValue, uint64 value);
493 			uint64				_ParseProduct();
494 			uint64				_ParsePower();
495 			uint64				_ParseUnary();
496 			uint64				_ParseDereference(void** _address,
497 									uint32* _size);
498 			uint64				_ParseAtom();
499 
500 			const Token&		_EatToken(int32 type);
501 
502 			Tokenizer			fTokenizer;
503 };
504 
505 
506 ExpressionParser::ExpressionParser()
507 	: fTokenizer("")
508 {
509 }
510 
511 
512 ExpressionParser::~ExpressionParser()
513 {
514 }
515 
516 
517 uint64
518 ExpressionParser::EvaluateExpression(const char* expressionString)
519 {
520 	fTokenizer.SetTo(expressionString);
521 
522 	uint64 value = _ParseExpression();
523 	const Token& token = fTokenizer.NextToken();
524 	if (token.type != TOKEN_END_OF_LINE)
525 		parse_exception("parse error", token.position);
526 
527 	return value;
528 }
529 
530 
531 uint64
532 ExpressionParser::EvaluateCommand(const char* expressionString, int& returnCode)
533 {
534 	fTokenizer.SetTo(expressionString);
535 
536 	// Allowed are command or assignment. A command always starts with an
537 	// identifier, an assignment either with an identifier (variable name) or
538 	// a dereferenced address.
539 	const Token& token = fTokenizer.NextToken();
540 	uint64 value = 0;
541 
542 	if (token.type == TOKEN_IDENTIFIER) {
543 		fTokenizer.NextToken();
544 		if (token.type & TOKEN_ASSIGN_FLAG) {
545 			// an assignment
546 			fTokenizer.SetTo(expressionString);
547 			value =  _ParseExpression(true);
548 			returnCode = 0;
549 		} else {
550 			// no assignment, so let's assume it's a command
551 			fTokenizer.SetTo(expressionString);
552 			fTokenizer.SetCommandMode(true);
553 			value = _ParseCommandPipe(returnCode);
554 		}
555 	} else if (token.type == TOKEN_STAR) {
556 		// dereferenced address -- assignment
557 		fTokenizer.SetTo(expressionString);
558 		value =  _ParseExpression(true);
559 		returnCode = 0;
560 	} else
561 		parse_exception("expected command or assignment", 0);
562 
563 	if (token.type != TOKEN_END_OF_LINE)
564 		parse_exception("parse error", token.position);
565 
566 	return value;
567 }
568 
569 
570 status_t
571 ExpressionParser::ParseNextCommandArgument(const char** expressionString,
572 	char* buffer, size_t bufferSize)
573 {
574 	fTokenizer.SetTo(*expressionString);
575 	fTokenizer.SetCommandMode(true);
576 
577 	if (fTokenizer.NextToken().type == TOKEN_END_OF_LINE)
578 		return B_ENTRY_NOT_FOUND;
579 
580 	fTokenizer.RewindToken();
581 
582 	char* argv[2];
583 	int argc = 0;
584 	if (!_ParseArgument(argc, argv))
585 		return B_BAD_VALUE;
586 
587 	strlcpy(buffer, argv[0], bufferSize);
588 
589 	const Token& token = fTokenizer.NextToken();
590 	if (token.type == TOKEN_END_OF_LINE)
591 		*expressionString = NULL;
592 	else
593 		*expressionString += token.position;
594 
595 	return B_OK;
596 }
597 
598 
599 uint64
600 ExpressionParser::_ParseExpression(bool expectAssignment)
601 {
602 	const Token& token = fTokenizer.NextToken();
603 	int32 position = token.position;
604 	if (token.type == TOKEN_IDENTIFIER) {
605 		char variable[MAX_DEBUG_VARIABLE_NAME_LEN];
606 		strlcpy(variable, token.string, sizeof(variable));
607 
608 		int32 assignmentType = fTokenizer.NextToken().type;
609 		if (assignmentType & TOKEN_ASSIGN_FLAG) {
610 			// an assignment
611 			uint64 rhs = _ParseExpression();
612 
613 			// handle the standard assignment separately -- the other kinds
614 			// need the variable to be defined
615 			if (assignmentType == TOKEN_ASSIGN) {
616 				if (!set_debug_variable(variable, rhs)) {
617 					snprintf(sTempBuffer, sizeof(sTempBuffer),
618 						"failed to set value for variable \"%s\"",
619 						variable);
620 					parse_exception(sTempBuffer, position);
621 				}
622 
623 				return rhs;
624 			}
625 
626 			// variable must be defined
627 			if (!is_debug_variable_defined(variable)) {
628 				snprintf(sTempBuffer, sizeof(sTempBuffer),
629 					"variable \"%s\" not defined in modifying assignment",
630 					variable);
631 				parse_exception(sTempBuffer, position);
632 			}
633 
634 			uint64 variableValue = get_debug_variable(variable, 0);
635 
636 			// check for division by zero for the respective assignment types
637 			if ((assignmentType == TOKEN_SLASH_ASSIGN
638 					|| assignmentType == TOKEN_MODULO_ASSIGN)
639 				&& rhs == 0) {
640 				parse_exception("division by zero", position);
641 			}
642 
643 			// compute the new variable value
644 			switch (assignmentType) {
645 				case TOKEN_PLUS_ASSIGN:
646 					variableValue += rhs;
647 					break;
648 				case TOKEN_MINUS_ASSIGN:
649 					variableValue -= rhs;
650 					break;
651 				case TOKEN_STAR_ASSIGN:
652 					variableValue *= rhs;
653 					break;
654 				case TOKEN_SLASH_ASSIGN:
655 					variableValue /= rhs;
656 					break;
657 				case TOKEN_MODULO_ASSIGN:
658 					variableValue %= rhs;
659 					break;
660 				default:
661 					parse_exception("internal error: unknown assignment token",
662 						position);
663 					break;
664 			}
665 
666 			set_debug_variable(variable, variableValue);
667 			return variableValue;
668 		}
669 	} else if (token.type == TOKEN_STAR) {
670 		void* address;
671 		uint32 size;
672 		uint64 value = _ParseDereference(&address, &size);
673 
674 		int32 assignmentType = fTokenizer.NextToken().type;
675 		if (assignmentType & TOKEN_ASSIGN_FLAG) {
676 			// an assignment
677 			uint64 rhs = _ParseExpression();
678 
679 			// check for division by zero for the respective assignment types
680 			if ((assignmentType == TOKEN_SLASH_ASSIGN
681 					|| assignmentType == TOKEN_MODULO_ASSIGN)
682 				&& rhs == 0) {
683 				parse_exception("division by zero", position);
684 			}
685 
686 			// compute the new value
687 			switch (assignmentType) {
688 				case TOKEN_ASSIGN:
689 					value = rhs;
690 					break;
691 				case TOKEN_PLUS_ASSIGN:
692 					value += rhs;
693 					break;
694 				case TOKEN_MINUS_ASSIGN:
695 					value -= rhs;
696 					break;
697 				case TOKEN_STAR_ASSIGN:
698 					value *= rhs;
699 					break;
700 				case TOKEN_SLASH_ASSIGN:
701 					value /= rhs;
702 					break;
703 				case TOKEN_MODULO_ASSIGN:
704 					value %= rhs;
705 					break;
706 				default:
707 					parse_exception("internal error: unknown assignment token",
708 						position);
709 					break;
710 			}
711 
712 			// convert the value for writing to the address
713 			uint64 buffer = 0;
714 			switch (size) {
715 				case 1:
716 					*(uint8*)&buffer = value;
717 					break;
718 				case 2:
719 					*(uint16*)&buffer = value;
720 					break;
721 				case 4:
722 					*(uint32*)&buffer = value;
723 					break;
724 				case 8:
725 					value = buffer;
726 					break;
727 			}
728 
729 			if (user_memcpy(address, &buffer, size) != B_OK) {
730 				snprintf(sTempBuffer, sizeof(sTempBuffer),
731 					"failed to write to address %p", address);
732 				parse_exception(sTempBuffer, position);
733 			}
734 
735 			return value;
736 		}
737 	}
738 
739 	if (expectAssignment) {
740 		parse_exception("expected assignment",
741 			fTokenizer.CurrentToken().position);
742 	}
743 
744 	// no assignment -- reset to the identifier position and parse a sum
745 	fTokenizer.SetPosition(position);
746 	return _ParseSum(false, 0);
747 }
748 
749 
750 uint64
751 ExpressionParser::_ParseCommandPipe(int& returnCode)
752 {
753 	debugger_command_pipe* pipe = (debugger_command_pipe*)allocate_temp_storage(
754 		sizeof(debugger_command_pipe));
755 
756 	pipe->segment_count = 0;
757 	pipe->broken = false;
758 
759 	do {
760 		if (pipe->segment_count >= MAX_DEBUGGER_COMMAND_PIPE_LENGTH)
761 			parse_exception("Pipe too long", fTokenizer.NextToken().position);
762 
763 		debugger_command_pipe_segment& segment
764 			= pipe->segments[pipe->segment_count];
765 		segment.index = pipe->segment_count++;
766 
767 		_ParseCommand(segment);
768 
769 	} while (fTokenizer.NextToken().type == TOKEN_PIPE);
770 
771 	fTokenizer.RewindToken();
772 
773 	// invoke the pipe
774 	returnCode = invoke_debugger_command_pipe(pipe);
775 
776 	free_temp_storage(pipe);
777 
778 	return get_debug_variable("_", 0);
779 }
780 
781 
782 void
783 ExpressionParser::_ParseCommand(debugger_command_pipe_segment& segment)
784 {
785 	fTokenizer.SetCommandMode(false);
786 	const Token& token = _EatToken(TOKEN_IDENTIFIER);
787 	fTokenizer.SetCommandMode(true);
788 
789 	bool ambiguous;
790 	debugger_command* command = find_debugger_command(token.string, true,
791 		ambiguous);
792 
793 	if (command == NULL) {
794 		if (ambiguous) {
795 			snprintf(sTempBuffer, sizeof(sTempBuffer),
796 				"Ambiguous command \"%s\". Use tab completion or enter "
797 				"\"help %s\" get a list of matching commands.\n", token.string,
798 				token.string);
799 		} else {
800 			snprintf(sTempBuffer, sizeof(sTempBuffer),
801 				"Unknown command \"%s\". Enter \"help\" to get a list of "
802 				"all supported commands.\n", token.string);
803 		}
804 
805 		parse_exception(sTempBuffer, -1);
806 	}
807 
808 	// allocate temporary buffer for the argument vector
809 	char** argv = (char**)allocate_temp_storage(
810 		kMaxArgumentCount * sizeof(char*));
811 	int argc = 0;
812 	argv[argc++] = (char*)command->name;
813 
814 	// get the arguments
815 	if ((command->flags & B_KDEBUG_DONT_PARSE_ARGUMENTS) != 0) {
816 		_GetUnparsedArgument(argc, argv);
817 	} else {
818 		while (fTokenizer.NextToken().type != TOKEN_END_OF_LINE) {
819 			fTokenizer.RewindToken();
820 			if (!_ParseArgument(argc, argv))
821 				break;
822 		}
823 	}
824 
825 	if (segment.index > 0) {
826 		if (argc >= kMaxArgumentCount)
827 			parse_exception("too many arguments for command", 0);
828 		else
829 			argc++;
830 	}
831 
832 	segment.command = command;
833 	segment.argc = argc;
834 	segment.argv = argv;
835 	segment.invocations = 0;
836 }
837 
838 
839 bool
840 ExpressionParser::_ParseArgument(int& argc, char** argv)
841 {
842 	const Token& token = fTokenizer.NextToken();
843 	switch (token.type) {
844 		case TOKEN_OPENING_PARENTHESIS:
845 		{
846 			// this starts an expression
847 			fTokenizer.SetCommandMode(false);
848 			uint64 value = _ParseExpression();
849 			fTokenizer.SetCommandMode(true);
850 			_EatToken(TOKEN_CLOSING_PARENTHESIS);
851 
852 			snprintf(sTempBuffer, sizeof(sTempBuffer), "%llu", value);
853 			_AddArgument(argc, argv, sTempBuffer);
854 			return true;
855 		}
856 
857 		case TOKEN_OPENING_BRACKET:
858 		{
859 			// this starts a sub command
860 			int returnValue;
861 			uint64 value = _ParseCommandPipe(returnValue);
862 			_EatToken(TOKEN_CLOSING_BRACKET);
863 
864 			snprintf(sTempBuffer, sizeof(sTempBuffer), "%llu", value);
865 			_AddArgument(argc, argv, sTempBuffer);
866 			return true;
867 		}
868 
869 		case TOKEN_STRING:
870 		case TOKEN_UNKNOWN:
871 			_AddArgument(argc, argv, token.string);
872 			return true;
873 
874 		case TOKEN_CLOSING_PARENTHESIS:
875 		case TOKEN_CLOSING_BRACKET:
876 		case TOKEN_PIPE:
877 			// those don't belong to us
878 			fTokenizer.RewindToken();
879 			return false;
880 
881 		default:
882 		{
883 			snprintf(sTempBuffer, sizeof(sTempBuffer), "unexpected token "
884 				"\"%s\"", token.string);
885 			parse_exception(sTempBuffer, token.position);
886 			return false;
887 		}
888 	}
889 }
890 
891 
892 void
893 ExpressionParser::_GetUnparsedArgument(int& argc, char** argv)
894 {
895 	int32 startPosition = fTokenizer.NextToken().position;
896 	fTokenizer.RewindToken();
897 
898 	// match parentheses and brackets, but otherwise skip all tokens
899 	int32 parentheses = 0;
900 	int32 brackets = 0;
901 	bool done = false;
902 	while (!done) {
903 		const Token& token = fTokenizer.NextToken();
904 		switch (token.type) {
905 			case TOKEN_OPENING_PARENTHESIS:
906 				parentheses++;
907 				break;
908 			case TOKEN_OPENING_BRACKET:
909 				brackets++;
910 				break;
911 			case TOKEN_CLOSING_PARENTHESIS:
912 				if (parentheses > 0)
913 					parentheses--;
914 				else
915 					done = true;
916 				break;
917 			case TOKEN_CLOSING_BRACKET:
918 				if (brackets > 0)
919 					brackets--;
920 				else
921 					done = true;
922 				break;
923 			case TOKEN_PIPE:
924 				if (parentheses == 0 && brackets == 0)
925 					done = true;
926 				break;
927 			case TOKEN_END_OF_LINE:
928 				done = true;
929 				break;
930 		}
931 	}
932 
933 	int32 endPosition = fTokenizer.CurrentToken().position;
934 	fTokenizer.RewindToken();
935 
936 	// add the argument only, if it's not just all spaces
937 	const char* arg = fTokenizer.String() + startPosition;
938 	int32 argLen = endPosition - startPosition;
939 	bool allSpaces = true;
940 	for (int32 i = 0; allSpaces && i < argLen; i++)
941 		allSpaces = isspace(arg[i]);
942 
943 	if (!allSpaces)
944 		_AddArgument(argc, argv, arg, argLen);
945 }
946 
947 
948 void
949 ExpressionParser::_AddArgument(int& argc, char** argv, const char* argument,
950 	int32 length)
951 {
952 	if (argc == kMaxArgumentCount)
953 		parse_exception("too many arguments for command", 0);
954 
955 	if (length < 0)
956 		length = strlen(argument);
957 	length++;
958 	char* buffer = (char*)allocate_temp_storage(length);
959 	strlcpy(buffer, argument, length);
960 
961 	argv[argc++] = buffer;
962 }
963 
964 
965 uint64
966 ExpressionParser::_ParseSum(bool useValue, uint64 value)
967 {
968 	if (!useValue)
969 		value = _ParseProduct();
970 
971 	while (true) {
972 		const Token& token = fTokenizer.NextToken();
973 		switch (token.type) {
974 			case TOKEN_PLUS:
975 				value = value + _ParseProduct();
976 				break;
977 			case TOKEN_MINUS:
978 				value = value - _ParseProduct();
979 				break;
980 
981 			default:
982 				fTokenizer.RewindToken();
983 				return value;
984 		}
985 	}
986 }
987 
988 
989 uint64
990 ExpressionParser::_ParseProduct()
991 {
992 	uint64 value = _ParseUnary();
993 
994 	while (true) {
995 		Token token = fTokenizer.NextToken();
996 		switch (token.type) {
997 			case TOKEN_STAR:
998 				value = value * _ParseUnary();
999 				break;
1000 			case TOKEN_SLASH: {
1001 				uint64 rhs = _ParseUnary();
1002 				if (rhs == 0)
1003 					parse_exception("division by zero", token.position);
1004 				value = value / rhs;
1005 				break;
1006 			}
1007 			case TOKEN_MODULO: {
1008 				uint64 rhs = _ParseUnary();
1009 				if (rhs == 0)
1010 					parse_exception("modulo by zero", token.position);
1011 				value = value % rhs;
1012 				break;
1013 			}
1014 
1015 			default:
1016 				fTokenizer.RewindToken();
1017 				return value;
1018 		}
1019 	}
1020 }
1021 
1022 
1023 uint64
1024 ExpressionParser::_ParseUnary()
1025 {
1026 	switch (fTokenizer.NextToken().type) {
1027 		case TOKEN_MINUS:
1028 			return -_ParseUnary();
1029 
1030 		case TOKEN_STAR:
1031 			return _ParseDereference(NULL, NULL);
1032 
1033 		default:
1034 			fTokenizer.RewindToken();
1035 			return _ParseAtom();
1036 	}
1037 
1038 	return 0;
1039 }
1040 
1041 
1042 uint64
1043 ExpressionParser::_ParseDereference(void** _address, uint32* _size)
1044 {
1045 	int32 starPosition = fTokenizer.CurrentToken().position;
1046 
1047 	// optional "{ ... }" specifying the size to read
1048 	uint64 size = 4;
1049 	if (fTokenizer.NextToken().type == TOKEN_OPENING_BRACE) {
1050 		int32 position = fTokenizer.CurrentToken().position;
1051 		size = _ParseExpression();
1052 
1053 		if (size != 1 && size != 2 && size != 4 && size != 8) {
1054 			snprintf(sTempBuffer, sizeof(sTempBuffer),
1055 				"invalid size (%llu) for unary * operator", size);
1056 			parse_exception(sTempBuffer, position);
1057 		}
1058 
1059 		_EatToken(TOKEN_CLOSING_BRACE);
1060 	} else
1061 		fTokenizer.RewindToken();
1062 
1063 	const void* address = (const void*)(addr_t)_ParseUnary();
1064 
1065 	// read bytes from address into a tempory buffer
1066 	uint64 buffer;
1067 	if (user_memcpy(&buffer, address, size) != B_OK) {
1068 		snprintf(sTempBuffer, sizeof(sTempBuffer),
1069 			"failed to dereference address %p", address);
1070 		parse_exception(sTempBuffer, starPosition);
1071 	}
1072 
1073 	// convert the value to uint64
1074 	uint64 value = 0;
1075 	switch (size) {
1076 		case 1:
1077 			value = *(uint8*)&buffer;
1078 			break;
1079 		case 2:
1080 			value = *(uint16*)&buffer;
1081 			break;
1082 		case 4:
1083 			value = *(uint32*)&buffer;
1084 			break;
1085 		case 8:
1086 			value = buffer;
1087 			break;
1088 	}
1089 
1090 	if (_address != NULL)
1091 		*_address = (void*)address;
1092 	if (_size != NULL)
1093 		*_size = size;
1094 
1095 	return value;
1096 }
1097 
1098 
1099 uint64
1100 ExpressionParser::_ParseAtom()
1101 {
1102 	const Token& token = fTokenizer.NextToken();
1103 	if (token.type == TOKEN_END_OF_LINE)
1104 		parse_exception("unexpected end of expression", token.position);
1105 
1106 	if (token.type == TOKEN_CONSTANT)
1107 		return token.value;
1108 
1109 	if (token.type == TOKEN_IDENTIFIER) {
1110 		if (!is_debug_variable_defined(token.string)) {
1111 			snprintf(sTempBuffer, sizeof(sTempBuffer),
1112 				"variable '%s' undefined", token.string);
1113 			parse_exception(sTempBuffer, token.position);
1114 		}
1115 
1116 		return get_debug_variable(token.string, 0);
1117 	}
1118 
1119 	if (token.type == TOKEN_OPENING_PARENTHESIS) {
1120 		uint64 value = _ParseExpression();
1121 
1122 		_EatToken(TOKEN_CLOSING_PARENTHESIS);
1123 
1124 		return value;
1125 	}
1126 
1127 	// it can only be a "[ command ]" expression now
1128 	fTokenizer.RewindToken();
1129 
1130 	_EatToken(TOKEN_OPENING_BRACKET);
1131 
1132 	fTokenizer.SetCommandMode(true);
1133 	int returnValue;
1134 	uint64 value = _ParseCommandPipe(returnValue);
1135 	fTokenizer.SetCommandMode(false);
1136 
1137 	_EatToken(TOKEN_CLOSING_BRACKET);
1138 
1139 	return value;
1140 }
1141 
1142 
1143 const Token&
1144 ExpressionParser::_EatToken(int32 type)
1145 {
1146 	const Token& token = fTokenizer.NextToken();
1147 	if (token.type != type) {
1148 		snprintf(sTempBuffer, sizeof(sTempBuffer), "expected token type '%c', "
1149 			"got token '%s'", char(type & ~TOKEN_FLAGS), token.string);
1150 		parse_exception(sTempBuffer, token.position);
1151 	}
1152 
1153 	return token;
1154 }
1155 
1156 
1157 
1158 // #pragma mark -
1159 
1160 
1161 bool
1162 evaluate_debug_expression(const char* expression, uint64* _result, bool silent)
1163 {
1164 	if (sNextJumpBufferIndex >= kJumpBufferCount) {
1165 		kprintf_unfiltered("evaluate_debug_expression(): Out of jump buffers "
1166 			"for exception handling\n");
1167 		return 0;
1168 	}
1169 
1170 	bool success;
1171 	uint64 result;
1172 	void* temporaryStorageMark = allocate_temp_storage(0);
1173 		// get a temporary storage mark, so we can cleanup everything that
1174 		// is allocated during the evaluation
1175 
1176 	if (setjmp(sJumpBuffers[sNextJumpBufferIndex++]) == 0) {
1177 		result = ExpressionParser().EvaluateExpression(expression);
1178 		success = true;
1179 	} else {
1180 		result = 0;
1181 		success = false;
1182 		if (!silent) {
1183 			if (sExceptionPosition >= 0) {
1184 				kprintf_unfiltered("%s, at position: %d, in expression: %s\n",
1185 					sExceptionMessage, sExceptionPosition, expression);
1186 			} else
1187 				kprintf_unfiltered("%s", sExceptionMessage);
1188 		}
1189 	}
1190 
1191 	sNextJumpBufferIndex--;
1192 
1193 	// cleanup temp allocations
1194 	free_temp_storage(temporaryStorageMark);
1195 
1196 	if (success && _result != NULL)
1197 		*_result = result;
1198 
1199 	return success;
1200 }
1201 
1202 
1203 int
1204 evaluate_debug_command(const char* commandLine)
1205 {
1206 	if (sNextJumpBufferIndex >= kJumpBufferCount) {
1207 		kprintf_unfiltered("evaluate_debug_command(): Out of jump buffers for "
1208 			"exception handling\n");
1209 		return 0;
1210 	}
1211 
1212 	int returnCode = 0;
1213 	void* temporaryStorageMark = allocate_temp_storage(0);
1214 		// get a temporary storage mark, so we can cleanup everything that
1215 		// is allocated during the evaluation
1216 
1217 	if (setjmp(sJumpBuffers[sNextJumpBufferIndex++]) == 0) {
1218 		ExpressionParser().EvaluateCommand(commandLine, returnCode);
1219 	} else {
1220 		if (sExceptionPosition >= 0) {
1221 			kprintf_unfiltered("%s, at position: %d, in command line: %s\n",
1222 				sExceptionMessage, sExceptionPosition, commandLine);
1223 		} else
1224 			kprintf_unfiltered("%s", sExceptionMessage);
1225 	}
1226 
1227 	sNextJumpBufferIndex--;
1228 
1229 	// cleanup temp allocations
1230 	free_temp_storage(temporaryStorageMark);
1231 
1232 	return returnCode;
1233 }
1234 
1235 
1236 status_t
1237 parse_next_debug_command_argument(const char** expressionString, char* buffer,
1238 	size_t bufferSize)
1239 {
1240 	if (sNextJumpBufferIndex >= kJumpBufferCount) {
1241 		kprintf_unfiltered("parse_next_debug_command_argument(): Out of jump "
1242 			"buffers for exception handling\n");
1243 		return B_ERROR;
1244 	}
1245 
1246 	status_t error;
1247 	void* temporaryStorageMark = allocate_temp_storage(0);
1248 		// get a temporary storage mark, so we can cleanup everything that
1249 		// is allocated during the evaluation
1250 
1251 	if (setjmp(sJumpBuffers[sNextJumpBufferIndex++]) == 0) {
1252 		error = ExpressionParser().ParseNextCommandArgument(expressionString,
1253 			buffer, bufferSize);
1254 	} else {
1255 		if (sExceptionPosition >= 0) {
1256 			kprintf_unfiltered("%s, at position: %d, in command line: %s\n",
1257 				sExceptionMessage, sExceptionPosition, *expressionString);
1258 		} else
1259 			kprintf_unfiltered("%s", sExceptionMessage);
1260 		error = B_BAD_VALUE;
1261 	}
1262 
1263 	sNextJumpBufferIndex--;
1264 
1265 	// cleanup temp allocations
1266 	free_temp_storage(temporaryStorageMark);
1267 
1268 	return error;
1269 }
1270