mirror of https://github.com/x64dbg/btparser
Start supporting function pointer types
This commit is contained in:
parent
c7ad8a7f7f
commit
eaecaf942b
|
@ -68,6 +68,7 @@ namespace Types
|
||||||
|
|
||||||
enum CallingConvention
|
enum CallingConvention
|
||||||
{
|
{
|
||||||
|
DefaultDecl,
|
||||||
Cdecl,
|
Cdecl,
|
||||||
Stdcall,
|
Stdcall,
|
||||||
Thiscall,
|
Thiscall,
|
||||||
|
@ -79,7 +80,7 @@ namespace Types
|
||||||
std::string owner; //Function owner
|
std::string owner; //Function owner
|
||||||
std::string name; //Function identifier
|
std::string name; //Function identifier
|
||||||
std::string rettype; //Function return type
|
std::string rettype; //Function return type
|
||||||
CallingConvention callconv = Cdecl; //Function calling convention
|
CallingConvention callconv = DefaultDecl; //Function calling convention
|
||||||
bool noreturn = false; //Function does not return (ExitProcess, _exit)
|
bool noreturn = false; //Function does not return (ExitProcess, _exit)
|
||||||
std::vector<Member> args; //Function arguments
|
std::vector<Member> args; //Function arguments
|
||||||
};
|
};
|
||||||
|
|
|
@ -107,10 +107,22 @@ bool ParseTypes(const std::string& parse, const std::string& owner, std::vector<
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (i + 1 == memToks.size() || memToks[i + 1].Token == Lexer::tok_subopen) //last = name
|
else if (i + 1 == memToks.size() ||
|
||||||
|
memToks[i + 1].Token == Lexer::tok_subopen ||
|
||||||
|
memToks[i+1].Token == Lexer::tok_comma)
|
||||||
{
|
{
|
||||||
m.name = lexer.TokString(memToks[i]);
|
m.name = lexer.TokString(memToks[i]);
|
||||||
}
|
}
|
||||||
|
else if (t.Token == Lexer::tok_comma) //uint32_t a,b;
|
||||||
|
{
|
||||||
|
// Flush the current member, inherit the type and continue
|
||||||
|
su.members.push_back(m);
|
||||||
|
auto cm = Member();
|
||||||
|
cm.type = m.type;
|
||||||
|
while (!cm.type.empty() && cm.type.back() == '*')
|
||||||
|
cm.type.pop_back();
|
||||||
|
m = cm;
|
||||||
|
}
|
||||||
else if (!t.IsType() &&
|
else if (!t.IsType() &&
|
||||||
t.Token != Lexer::tok_op_mul &&
|
t.Token != Lexer::tok_op_mul &&
|
||||||
t.Token != Lexer::tok_identifier &&
|
t.Token != Lexer::tok_identifier &&
|
||||||
|
@ -140,10 +152,16 @@ bool ParseTypes(const std::string& parse, const std::string& owner, std::vector<
|
||||||
StructUnion su;
|
StructUnion su;
|
||||||
su.isunion = isToken(Lexer::tok_union);
|
su.isunion = isToken(Lexer::tok_union);
|
||||||
index++;
|
index++;
|
||||||
if (isTokenList({ Lexer::tok_identifier, Lexer::tok_bropen }))
|
if (!isToken(Lexer::tok_identifier))
|
||||||
{
|
{
|
||||||
su.name = lexer.TokString(curToken());
|
errLine(curToken(), "expected identifier after struct");
|
||||||
index += 2;
|
return false;
|
||||||
|
}
|
||||||
|
su.name = lexer.TokString(curToken());
|
||||||
|
index++;
|
||||||
|
if (isToken(Lexer::tok_bropen))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
while (!isToken(Lexer::tok_brclose))
|
while (!isToken(Lexer::tok_brclose))
|
||||||
{
|
{
|
||||||
if (isToken(Lexer::tok_eof))
|
if (isToken(Lexer::tok_eof))
|
||||||
|
@ -170,6 +188,13 @@ bool ParseTypes(const std::string& parse, const std::string& owner, std::vector<
|
||||||
eatSemic();
|
eatSemic();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if (isToken(Lexer::tok_semic))
|
||||||
|
{
|
||||||
|
// Forward declaration
|
||||||
|
model.structUnions.push_back(su);
|
||||||
|
eatSemic();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
errLine(curToken(), "invalid struct token sequence!");
|
errLine(curToken(), "invalid struct token sequence!");
|
||||||
|
@ -188,6 +213,8 @@ bool ParseTypes(const std::string& parse, const std::string& owner, std::vector<
|
||||||
{
|
{
|
||||||
e.name = lexer.TokString(curToken());
|
e.name = lexer.TokString(curToken());
|
||||||
index += 2;
|
index += 2;
|
||||||
|
if (e.name == "BNFunctionGraphType")
|
||||||
|
__debugbreak();
|
||||||
while (!isToken(Lexer::tok_brclose))
|
while (!isToken(Lexer::tok_brclose))
|
||||||
{
|
{
|
||||||
if (isToken(Lexer::tok_eof))
|
if (isToken(Lexer::tok_eof))
|
||||||
|
@ -206,6 +233,11 @@ bool ParseTypes(const std::string& parse, const std::string& owner, std::vector<
|
||||||
if (isToken(Lexer::tok_comma))
|
if (isToken(Lexer::tok_comma))
|
||||||
{
|
{
|
||||||
index++;
|
index++;
|
||||||
|
if (isToken(Lexer::tok_brclose))
|
||||||
|
{
|
||||||
|
// Support final comma
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -222,10 +254,34 @@ bool ParseTypes(const std::string& parse, const std::string& owner, std::vector<
|
||||||
|
|
||||||
EnumValue v;
|
EnumValue v;
|
||||||
v.name = lexer.TokString(curToken());
|
v.name = lexer.TokString(curToken());
|
||||||
v.value = e.values.empty() ? 0 : e.values.back().value + 1;
|
|
||||||
e.values.push_back(v);
|
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
|
if (isToken(Lexer::tok_assign))
|
||||||
|
{
|
||||||
|
bool negative = false;
|
||||||
|
index++;
|
||||||
|
if (isToken(Lexer::tok_op_min))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
negative = true;
|
||||||
|
}
|
||||||
|
if (!isToken(Lexer::tok_number))
|
||||||
|
{
|
||||||
|
errLine(curToken(), "expected number after = in enum");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
v.value = curToken().NumberVal;
|
||||||
|
if (negative)
|
||||||
|
{
|
||||||
|
v.value = -(int64_t)v.value;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v.value = e.values.empty() ? 0 : e.values.back().value + 1;
|
||||||
|
}
|
||||||
|
e.values.push_back(v);
|
||||||
}
|
}
|
||||||
index++; //eat tok_brclose
|
index++; //eat tok_brclose
|
||||||
|
|
||||||
|
@ -249,18 +305,192 @@ bool ParseTypes(const std::string& parse, const std::string& owner, std::vector<
|
||||||
};
|
};
|
||||||
auto parseTypedef = [&]()
|
auto parseTypedef = [&]()
|
||||||
{
|
{
|
||||||
// TODO: support "typedef struct"
|
// TODO: support "typedef struct foo { members... };"
|
||||||
|
// TODO: support "typedef enum foo { members... };"
|
||||||
if (isToken(Lexer::tok_typedef))
|
if (isToken(Lexer::tok_typedef))
|
||||||
{
|
{
|
||||||
index++;
|
index++;
|
||||||
std::vector<Lexer::TokenState> tdefToks;
|
|
||||||
while (!isToken(Lexer::tok_semic))
|
std::vector<std::string> tdList;
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
if (isToken(Lexer::tok_eof))
|
if (isToken(Lexer::tok_eof))
|
||||||
{
|
{
|
||||||
errLine(curToken(), "unexpected eof in typedef");
|
errLine(curToken(), "unexpected eof in typedef");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (isToken(Lexer::tok_semic))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
__debugbreak();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_enum))
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
__debugbreak();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& t = curToken();
|
||||||
|
if (t.IsType() || t.Token == Lexer::tok_identifier || t.Token == Lexer::tok_void)
|
||||||
|
{
|
||||||
|
// Primitive type
|
||||||
|
index++;
|
||||||
|
tdList.push_back(lexer.TokString(t));
|
||||||
|
}
|
||||||
|
else if (t.Token == Lexer::tok_op_mul)
|
||||||
|
{
|
||||||
|
// Pointer to the type on the left
|
||||||
|
if (tdList.empty())
|
||||||
|
{
|
||||||
|
errLine(curToken(), "unexpected * in function typedef");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
tdList.back().push_back('*');
|
||||||
|
}
|
||||||
|
else if (t.Token == Lexer::tok_paropen)
|
||||||
|
{
|
||||||
|
// Function pointer type
|
||||||
|
if (tdList.empty())
|
||||||
|
{
|
||||||
|
errLine(curToken(), "expected return type before function typedef");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO: calling conventions
|
||||||
|
index++;
|
||||||
|
if (!isToken(Lexer::tok_op_mul))
|
||||||
|
{
|
||||||
|
errLine(curToken(), "expected * in function typedef");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
if (!isToken(Lexer::tok_identifier))
|
||||||
|
{
|
||||||
|
errLine(curToken(), "expected identifier in function typedef");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Function fn;
|
||||||
|
fn.name = lexer.TokString(curToken());
|
||||||
|
index++;
|
||||||
|
|
||||||
|
if (!isToken(Lexer::tok_parclose))
|
||||||
|
{
|
||||||
|
errLine(curToken(), "expected ) after function typedef name");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
if (!isToken(Lexer::tok_paropen))
|
||||||
|
{
|
||||||
|
errLine(curToken(), "expected ( for start of parameter list in function typedef");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
|
||||||
|
for (const auto& type : tdList)
|
||||||
|
{
|
||||||
|
if (!fn.rettype.empty())
|
||||||
|
fn.rettype += ' ';
|
||||||
|
fn.rettype += type;
|
||||||
|
}
|
||||||
|
|
||||||
|
Member arg;
|
||||||
|
while (!isToken(Lexer::tok_parclose))
|
||||||
|
{
|
||||||
|
if (!fn.args.empty())
|
||||||
|
{
|
||||||
|
if (isToken(Lexer::tok_comma))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
fn.args.push_back(arg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errLine(curToken(), "expected comma in function typedef argument list");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& t = curToken();
|
||||||
|
if (t.Token == Lexer::tok_void)
|
||||||
|
{
|
||||||
|
// empty argument list
|
||||||
|
index++;
|
||||||
|
if (!fn.args.empty())
|
||||||
|
{
|
||||||
|
errLine(t, "void only allowed in an empty function typedef argument list");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!isToken(Lexer::tok_parclose))
|
||||||
|
{
|
||||||
|
errLine(curToken(), "expected ) after void in function typedef argument list");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (t.IsType() || t.Token == Lexer::tok_identifier)
|
||||||
|
{
|
||||||
|
// Primitive type
|
||||||
|
index++;
|
||||||
|
if (!arg.type.empty())
|
||||||
|
{
|
||||||
|
if (arg.type.back() == '*')
|
||||||
|
{
|
||||||
|
errLine(t, "unexpected type after * in function typedef argument list");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
arg.type.push_back(' ');
|
||||||
|
}
|
||||||
|
arg.type += lexer.TokString(t);
|
||||||
|
}
|
||||||
|
else if (t.Token == Lexer::tok_op_mul)
|
||||||
|
{
|
||||||
|
// Pointer to the type on the left
|
||||||
|
if (arg.type.empty())
|
||||||
|
{
|
||||||
|
errLine(curToken(), "unexpected * in function typedef argument list");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
fn.args.back().type.push_back('*');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errLine(curToken(), "unsupported token in function typedef argument list");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
|
||||||
|
if (!arg.type.empty())
|
||||||
|
{
|
||||||
|
fn.args.push_back(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isToken(Lexer::tok_semic))
|
||||||
|
{
|
||||||
|
errLine(curToken(), "expected ; after function typedef");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
eatSemic();
|
||||||
|
|
||||||
|
// TODO: put the fn somewhere
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__debugbreak();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__debugbreak();
|
||||||
|
|
||||||
|
std::vector<Lexer::TokenState> tdefToks;
|
||||||
|
while (!isToken(Lexer::tok_semic))
|
||||||
|
{
|
||||||
|
|
||||||
tdefToks.push_back(curToken());
|
tdefToks.push_back(curToken());
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
@ -276,6 +506,7 @@ bool ParseTypes(const std::string& parse, const std::string& owner, std::vector<
|
||||||
tm.name = lexer.TokString(tdefToks[tdefToks.size() - 1]);
|
tm.name = lexer.TokString(tdefToks[tdefToks.size() - 1]);
|
||||||
tdefToks.pop_back();
|
tdefToks.pop_back();
|
||||||
for (auto& t : tdefToks)
|
for (auto& t : tdefToks)
|
||||||
|
{
|
||||||
if (!t.IsType() &&
|
if (!t.IsType() &&
|
||||||
t.Token != Lexer::tok_op_mul &&
|
t.Token != Lexer::tok_op_mul &&
|
||||||
t.Token != Lexer::tok_identifier &&
|
t.Token != Lexer::tok_identifier &&
|
||||||
|
@ -290,6 +521,7 @@ bool ParseTypes(const std::string& parse, const std::string& owner, std::vector<
|
||||||
tm.type.push_back(' ');
|
tm.type.push_back(' ');
|
||||||
tm.type += lexer.TokString(t);
|
tm.type += lexer.TokString(t);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//dprintf("typedef %s:%s\n", tm.type.c_str(), tm.name.c_str());
|
//dprintf("typedef %s:%s\n", tm.type.c_str(), tm.name.c_str());
|
||||||
model.types.push_back(tm);
|
model.types.push_back(tm);
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in New Issue