Extended debugger language: Dereferenced addresses are now supported as

left hand side of assignments. IOW it is possible to modify memory, now.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27193 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-08-25 00:24:06 +00:00
parent 18f2a9c17d
commit b9f431f1df
+172 -75
View File
@@ -23,15 +23,17 @@
commandLine := commandPipe | ( "(" expression ")" )
expression := term | assignment
assignment := variable ( "=" | "+=" | "-=" | "*=" | "/=" | "%=" )
assignment := lhs ( "=" | "+=" | "-=" | "*=" | "/=" | "%=" )
expression
lhs := variable | dereference
term := sum
sum := product ( ( "+" | "-" ) product )*
product := unary ( ( "*" | "/" | "%" ) unary )*
unary := atom | ( ( "-" | "*" [ "{" expression "}" ] ) unary )
unary := atom | ( "-" unary ) | dereference
dereference := "*" [ "{" expression "}" ] unary
atom := variable | ( "(" expression ")" ) | ( "[" command "]" )
variable := identifier
identifier := ( "_" | "a" - "z" | "A" - "Z" )
identifier := ( "$" | "_" | "a" - "z" | "A" - "Z" )
( "_" | "a" - "z" | "A" - "Z" | "0" - "9" )*
commandPipe := command ( "|" command )*
command := identifier argument*
@@ -479,7 +481,7 @@ class ExpressionParser {
size_t bufferSize);
private:
uint64 _ParseExpression();
uint64 _ParseExpression(bool expectAssignment = false);
uint64 _ParseCommandPipe(int& returnCode);
void _ParseCommand(
debugger_command_pipe_segment& segment);
@@ -487,10 +489,12 @@ class ExpressionParser {
void _GetUnparsedArgument(int& argc, char** argv);
void _AddArgument(int& argc, char** argv,
const char* argument, int32 length = -1);
uint64 _ParseSum();
uint64 _ParseSum(bool useValue, uint64 value);
uint64 _ParseProduct();
uint64 _ParsePower();
uint64 _ParseUnary();
uint64 _ParseDereference(void** _address,
uint32* _size);
uint64 _ParseAtom();
const Token& _EatToken(int32 type);
@@ -525,28 +529,36 @@ ExpressionParser::EvaluateExpression(const char* expressionString)
uint64
ExpressionParser::EvaluateCommand(const char* expressionString,
int& returnCode)
ExpressionParser::EvaluateCommand(const char* expressionString, int& returnCode)
{
fTokenizer.SetTo(expressionString);
// Allowed is not only a command, but also an assignment. Either starts with
// an identifier.
_EatToken(TOKEN_IDENTIFIER);
uint64 value;
// Allowed are command or assignment. A command always starts with an
// identifier, an assignment either with an identifier (variable name) or
// a dereferenced address.
const Token& token = fTokenizer.NextToken();
if (token.type & TOKEN_ASSIGN_FLAG) {
// an assignment
uint64 value = 0;
if (token.type == TOKEN_IDENTIFIER) {
fTokenizer.NextToken();
if (token.type & TOKEN_ASSIGN_FLAG) {
// an assignment
fTokenizer.SetTo(expressionString);
value = _ParseExpression(true);
returnCode = 0;
} else {
// no assignment, so let's assume it's a command
fTokenizer.SetTo(expressionString);
fTokenizer.SetCommandMode(true);
value = _ParseCommandPipe(returnCode);
}
} else if (token.type == TOKEN_STAR) {
// dereferenced address -- assignment
fTokenizer.SetTo(expressionString);
value = _ParseExpression();
value = _ParseExpression(true);
returnCode = 0;
} else {
// no assignment, so let's assume it's a command
fTokenizer.SetTo(expressionString);
fTokenizer.SetCommandMode(true);
value = _ParseCommandPipe(returnCode);
}
} else
parse_exception("expected command or assignment", 0);
if (token.type != TOKEN_END_OF_LINE)
parse_exception("parse error", token.position);
@@ -585,7 +597,7 @@ ExpressionParser::ParseNextCommandArgument(const char** expressionString,
uint64
ExpressionParser::_ParseExpression()
ExpressionParser::_ParseExpression(bool expectAssignment)
{
const Token& token = fTokenizer.NextToken();
int32 position = token.position;
@@ -646,18 +658,92 @@ ExpressionParser::_ParseExpression()
variableValue %= rhs;
break;
default:
fTokenizer.SetPosition(position);
return _ParseSum();
parse_exception("internal error: unknown assignment token",
position);
break;
}
set_debug_variable(variable, variableValue);
return variableValue;
}
} else if (token.type == TOKEN_STAR) {
void* address;
uint32 size;
uint64 value = _ParseDereference(&address, &size);
int32 assignmentType = fTokenizer.NextToken().type;
if (assignmentType & TOKEN_ASSIGN_FLAG) {
// an assignment
uint64 rhs = _ParseExpression();
// check for division by zero for the respective assignment types
if ((assignmentType == TOKEN_SLASH_ASSIGN
|| assignmentType == TOKEN_MODULO_ASSIGN)
&& rhs == 0) {
parse_exception("division by zero", position);
}
// compute the new value
switch (assignmentType) {
case TOKEN_ASSIGN:
value = rhs;
break;
case TOKEN_PLUS_ASSIGN:
value += rhs;
break;
case TOKEN_MINUS_ASSIGN:
value -= rhs;
break;
case TOKEN_STAR_ASSIGN:
value *= rhs;
break;
case TOKEN_SLASH_ASSIGN:
value /= rhs;
break;
case TOKEN_MODULO_ASSIGN:
value %= rhs;
break;
default:
parse_exception("internal error: unknown assignment token",
position);
break;
}
// convert the value for writing to the address
uint64 buffer = 0;
switch (size) {
case 1:
*(uint8*)&buffer = value;
break;
case 2:
*(uint16*)&buffer = value;
break;
case 4:
*(uint32*)&buffer = value;
break;
case 8:
value = buffer;
break;
}
if (user_memcpy(address, &buffer, size) != B_OK) {
snprintf(sTempBuffer, sizeof(sTempBuffer),
"failed to write to address %p", address);
parse_exception(sTempBuffer, position);
}
return value;
}
}
if (expectAssignment) {
parse_exception("expected assignment",
fTokenizer.CurrentToken().position);
}
// no assignment -- reset to the identifier position and parse a sum
fTokenizer.SetPosition(position);
return _ParseSum();
return _ParseSum(false, 0);
}
@@ -877,9 +963,10 @@ ExpressionParser::_AddArgument(int& argc, char** argv, const char* argument,
uint64
ExpressionParser::_ParseSum()
ExpressionParser::_ParseSum(bool useValue, uint64 value)
{
uint64 value = _ParseProduct();
if (!useValue)
value = _ParseProduct();
while (true) {
const Token& token = fTokenizer.NextToken();
@@ -941,54 +1028,7 @@ ExpressionParser::_ParseUnary()
return -_ParseUnary();
case TOKEN_STAR:
{
int32 starPosition = fTokenizer.CurrentToken().position;
// optional "{ ... }" specifying the size to read
uint64 size = 4;
if (fTokenizer.NextToken().type == TOKEN_OPENING_BRACE) {
int32 position = fTokenizer.CurrentToken().position;
size = _ParseExpression();
if (size != 1 && size != 2 && size != 4 && size != 8) {
snprintf(sTempBuffer, sizeof(sTempBuffer),
"invalid size (%llu) for unary * operator", size);
parse_exception(sTempBuffer, position);
}
_EatToken(TOKEN_CLOSING_BRACE);
} else
fTokenizer.RewindToken();
const void* address = (const void*)(addr_t)_ParseUnary();
// read bytes from address into a tempory buffer
uint64 buffer;
if (user_memcpy(&buffer, address, size) != B_OK) {
snprintf(sTempBuffer, sizeof(sTempBuffer),
"failed to dereference address %p", address);
parse_exception(sTempBuffer, starPosition);
}
// convert the value to uint64
uint64 value = 0;
switch (size) {
case 1:
value = *(uint8*)&buffer;
break;
case 2:
value = *(uint16*)&buffer;
break;
case 4:
value = *(uint32*)&buffer;
break;
case 8:
value = buffer;
break;
}
return value;
}
return _ParseDereference(NULL, NULL);
default:
fTokenizer.RewindToken();
@@ -999,6 +1039,63 @@ ExpressionParser::_ParseUnary()
}
uint64
ExpressionParser::_ParseDereference(void** _address, uint32* _size)
{
int32 starPosition = fTokenizer.CurrentToken().position;
// optional "{ ... }" specifying the size to read
uint64 size = 4;
if (fTokenizer.NextToken().type == TOKEN_OPENING_BRACE) {
int32 position = fTokenizer.CurrentToken().position;
size = _ParseExpression();
if (size != 1 && size != 2 && size != 4 && size != 8) {
snprintf(sTempBuffer, sizeof(sTempBuffer),
"invalid size (%llu) for unary * operator", size);
parse_exception(sTempBuffer, position);
}
_EatToken(TOKEN_CLOSING_BRACE);
} else
fTokenizer.RewindToken();
const void* address = (const void*)(addr_t)_ParseUnary();
// read bytes from address into a tempory buffer
uint64 buffer;
if (user_memcpy(&buffer, address, size) != B_OK) {
snprintf(sTempBuffer, sizeof(sTempBuffer),
"failed to dereference address %p", address);
parse_exception(sTempBuffer, starPosition);
}
// convert the value to uint64
uint64 value = 0;
switch (size) {
case 1:
value = *(uint8*)&buffer;
break;
case 2:
value = *(uint16*)&buffer;
break;
case 4:
value = *(uint32*)&buffer;
break;
case 8:
value = buffer;
break;
}
if (_address != NULL)
*_address = (void*)address;
if (_size != NULL)
*_size = size;
return value;
}
uint64
ExpressionParser::_ParseAtom()
{