mirror of https://github.com/x64dbg/btparser
Add support for parsing jni.h
This commit is contained in:
parent
7b2e382f37
commit
e17068c4d6
|
@ -52,3 +52,5 @@ DEF_KEYWORD(public)
|
||||||
DEF_KEYWORD(protected)
|
DEF_KEYWORD(protected)
|
||||||
DEF_KEYWORD(override)
|
DEF_KEYWORD(override)
|
||||||
DEF_KEYWORD(class)
|
DEF_KEYWORD(class)
|
||||||
|
|
||||||
|
DEF_KEYWORD(__attribute__)
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
typedef struct {
|
||||||
|
int member1;
|
||||||
|
int member2;
|
||||||
|
} JNINativeMethod;
|
||||||
|
|
||||||
|
typedef struct JNINativeMethod2 {
|
||||||
|
int member1;
|
||||||
|
int member2;
|
||||||
|
} JNINativeMethod2;
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct Parser
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
Model model;
|
Model model;
|
||||||
std::unordered_map<std::string, size_t> structUnions;
|
std::unordered_map<std::string, size_t> structUnions;
|
||||||
|
int anonymousId = 0;
|
||||||
|
|
||||||
Parser(const std::string& code, const std::string& owner, std::vector<std::string>& errors)
|
Parser(const std::string& code, const std::string& owner, std::vector<std::string>& errors)
|
||||||
: owner(owner), errors(errors)
|
: owner(owner), errors(errors)
|
||||||
|
@ -466,7 +467,7 @@ struct Parser
|
||||||
|
|
||||||
if (isStructLike())
|
if (isStructLike())
|
||||||
{
|
{
|
||||||
if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier)
|
if (getToken(index + 1).Token == Lexer::tok_identifier)
|
||||||
{
|
{
|
||||||
kind = curToken().Token;
|
kind = curToken().Token;
|
||||||
index++;
|
index++;
|
||||||
|
@ -565,7 +566,7 @@ struct Parser
|
||||||
subfn.name = typeToken.IdentifierStr;
|
subfn.name = typeToken.IdentifierStr;
|
||||||
model.functions.push_back(subfn);
|
model.functions.push_back(subfn);
|
||||||
|
|
||||||
return true;
|
return finalizeMember();
|
||||||
}
|
}
|
||||||
else if (t.Is(Lexer::tok_comma))
|
else if (t.Is(Lexer::tok_comma))
|
||||||
{
|
{
|
||||||
|
@ -621,7 +622,7 @@ struct Parser
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parseStructUnion()
|
bool parseStructUnion(bool inTypedef, std::string* outName = nullptr)
|
||||||
{
|
{
|
||||||
auto startToken = curToken();
|
auto startToken = curToken();
|
||||||
if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_class) || isToken(Lexer::tok_union))
|
if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_class) || isToken(Lexer::tok_union))
|
||||||
|
@ -629,13 +630,20 @@ struct Parser
|
||||||
StructUnion su;
|
StructUnion su;
|
||||||
su.isunion = isToken(Lexer::tok_union);
|
su.isunion = isToken(Lexer::tok_union);
|
||||||
index++;
|
index++;
|
||||||
if (!isToken(Lexer::tok_identifier))
|
if (isToken(Lexer::tok_identifier))
|
||||||
{
|
{
|
||||||
errLine(curToken(), "expected identifier after struct");
|
su.name = curToken().IdentifierStr;
|
||||||
return false;
|
index++;
|
||||||
}
|
}
|
||||||
su.name = lexer.TokString(curToken());
|
else
|
||||||
index++;
|
{
|
||||||
|
su.name = "__anonymous_" + std::to_string(anonymousId++);
|
||||||
|
}
|
||||||
|
if(outName != nullptr)
|
||||||
|
{
|
||||||
|
*outName = su.name;
|
||||||
|
}
|
||||||
|
|
||||||
if (isToken(Lexer::tok_bropen))
|
if (isToken(Lexer::tok_bropen))
|
||||||
{
|
{
|
||||||
index++;
|
index++;
|
||||||
|
@ -675,15 +683,18 @@ struct Parser
|
||||||
model.structUnions.push_back(su);
|
model.structUnions.push_back(su);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isToken(Lexer::tok_semic))
|
if(!inTypedef)
|
||||||
{
|
{
|
||||||
errLine(curToken(), "expected semicolon!");
|
if (!isToken(Lexer::tok_semic))
|
||||||
return false;
|
{
|
||||||
|
errLine(curToken(), "expected semicolon!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
eatSemic();
|
||||||
}
|
}
|
||||||
eatSemic();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (isToken(Lexer::tok_semic))
|
else if (isToken(Lexer::tok_semic) && !su.name.empty())
|
||||||
{
|
{
|
||||||
// Forward declaration
|
// Forward declaration
|
||||||
su.size = -1;
|
su.size = -1;
|
||||||
|
@ -693,7 +704,8 @@ struct Parser
|
||||||
structUnions.emplace(su.name, model.structUnions.size());
|
structUnions.emplace(su.name, model.structUnions.size());
|
||||||
model.structUnions.push_back(su);
|
model.structUnions.push_back(su);
|
||||||
}
|
}
|
||||||
eatSemic();
|
if(!inTypedef)
|
||||||
|
eatSemic();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -705,19 +717,33 @@ struct Parser
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parseEnum()
|
bool parseEnum(bool inTypedef, std::string* outName = nullptr)
|
||||||
{
|
{
|
||||||
if (isToken(Lexer::tok_enum))
|
if (isToken(Lexer::tok_enum))
|
||||||
{
|
{
|
||||||
Enum e;
|
Enum e;
|
||||||
std::string etype;
|
std::string etype;
|
||||||
index++;
|
index++;
|
||||||
if (isTokenList({ Lexer::tok_identifier, Lexer::tok_bropen }))
|
if(curToken().Is(Lexer::tok_identifier))
|
||||||
{
|
{
|
||||||
e.name = lexer.TokString(curToken());
|
e.name = curToken().IdentifierStr;
|
||||||
index += 2;
|
index++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
e.name = "__anonymous_" + std::to_string(anonymousId++);
|
||||||
|
}
|
||||||
|
if(outName != nullptr)
|
||||||
|
{
|
||||||
|
*outName = e.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: support custom enum types (: type)
|
||||||
|
|
||||||
|
if (curToken().Is(Lexer::tok_bropen))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
|
||||||
// TODO: support custom enum types (: type)
|
|
||||||
etype = "int";
|
etype = "int";
|
||||||
|
|
||||||
while (!isToken(Lexer::tok_brclose))
|
while (!isToken(Lexer::tok_brclose))
|
||||||
|
@ -791,12 +817,15 @@ struct Parser
|
||||||
index++; //eat tok_brclose
|
index++; //eat tok_brclose
|
||||||
|
|
||||||
model.enums.emplace_back(e, etype);
|
model.enums.emplace_back(e, etype);
|
||||||
if (!isToken(Lexer::tok_semic))
|
if(!inTypedef)
|
||||||
{
|
{
|
||||||
errLine(curToken(), "expected semicolon!");
|
if (!isToken(Lexer::tok_semic))
|
||||||
return false;
|
{
|
||||||
|
errLine(curToken(), "expected semicolon!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
eatSemic();
|
||||||
}
|
}
|
||||||
eatSemic();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -831,17 +860,50 @@ struct Parser
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isToken(Lexer::tok_comma))
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
errLine(curToken(), "unsupported comma in typedef");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (isStructLike())
|
if (isStructLike())
|
||||||
{
|
{
|
||||||
if (tlist.empty() && getToken(index + 1).Is(Lexer::tok_identifier))
|
// typedef struct/enum/union
|
||||||
|
// Consume the 'struct'-like token
|
||||||
|
kind = curToken().Token;
|
||||||
|
index++;
|
||||||
|
|
||||||
|
if(curToken().Is(Lexer::tok_bropen) || isTokenList({ Lexer::tok_identifier, Lexer::tok_bropen }))
|
||||||
{
|
{
|
||||||
kind = curToken().Token;
|
// 'typedef struct {' OR 'typedef struct Name {'
|
||||||
index++;
|
index--;
|
||||||
|
std::string structName;
|
||||||
|
if(kind == Lexer::tok_enum)
|
||||||
|
{
|
||||||
|
if(!parseEnum(true, &structName))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!parseStructUnion(true, &structName))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tlist.push_back({ Lexer::tok_identifier, structName });
|
||||||
|
}
|
||||||
|
else if(isTokenList({Lexer::tok_identifier, Lexer::tok_identifier}))
|
||||||
|
{
|
||||||
|
// typedef struct Name Name
|
||||||
|
// NOTE: fallthrough
|
||||||
|
}
|
||||||
|
else if(isTokenList({Lexer::tok_identifier, Lexer::tok_op_mul}))
|
||||||
|
{
|
||||||
|
// typedef struct Name1 *
|
||||||
|
// NOTE: fallthrough
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
errLine(curToken(), "unsupported struct/union/enum in typedef");
|
errLine(curToken(), "unsupported typedef struct");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1053,6 +1115,53 @@ struct Parser
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if(t.Is(Lexer::tok___attribute__))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
|
||||||
|
if(!isTokenList({Lexer::tok_paropen, Lexer::tok_paropen}))
|
||||||
|
{
|
||||||
|
errLine(curToken(), "expected (( after __attribute__");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
index += 2;
|
||||||
|
|
||||||
|
std::vector<Lexer::TokenState> attrTokens;
|
||||||
|
|
||||||
|
int parStack = 0;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
attrTokens.push_back(curToken());
|
||||||
|
|
||||||
|
if(curToken().Is(Lexer::tok_paropen))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
parStack++;
|
||||||
|
}
|
||||||
|
else if(curToken().Is(Lexer::tok_parclose))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
if(parStack == 0 && curToken().Is(Lexer::tok_parclose))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
attrTokens.pop_back();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
parStack--;
|
||||||
|
if(parStack < 0)
|
||||||
|
{
|
||||||
|
errLine(curToken(), "mismatched parens");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: attach attribute tokens to the function?
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
|
@ -1183,9 +1292,9 @@ struct Parser
|
||||||
auto curIndex = index;
|
auto curIndex = index;
|
||||||
if (!parseTypedef())
|
if (!parseTypedef())
|
||||||
return false;
|
return false;
|
||||||
if (!parseStructUnion())
|
if (!parseStructUnion(false))
|
||||||
return false;
|
return false;
|
||||||
if (!parseEnum())
|
if (!parseEnum(false))
|
||||||
return false;
|
return false;
|
||||||
eatSemic();
|
eatSemic();
|
||||||
if (curIndex == index)
|
if (curIndex == index)
|
||||||
|
|
Loading…
Reference in New Issue