/* ### * IP: GHIDRA * NOTE: flex skeletons are NOT bound by flex's BSD license * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ %{ #include "slgh_compile.hh" #include "slghparse.hh" #define yywrap() 1 #define YY_SKIP_YYWRAP /* If we are building don't include unistd.h */ /* flex provides us with this macro for turning it off */ #ifdef _WIN32 #define YY_NO_UNISTD_H static int isatty (int fildes) { return 0; } #endif struct FileStreamState { YY_BUFFER_STATE lastbuffer; // Last lex buffer corresponding to the stream FILE *file; // The NEW file stream }; extern SleighCompile *slgh; int4 last_preproc; // lex state before last preprocessing erasure int4 actionon; // whether '&' '|' and '^' are treated as actionon in pattern section int4 withsection = 0; // whether we are between the 'with' keyword and its open brace '{' vector filebuffers; vector ifstack; int4 negative_if = -1; void preproc_error(const string &err) { slgh->reportError((const Location *)0, err); cerr << "Terminating due to error in preprocessing" << endl; exit(1); } void check_to_endofline(istream &s) { // Make sure there is nothing to the end of the line s >> ws; if (!s.eof()) if (s.peek() != '#') preproc_error("Extra characters in preprocessor directive"); } string read_identifier(istream &s) { // Read a proper identifier from the stream s >> ws; // Skip any whitespace string res; while(!s.eof()) { char tok = s.peek(); if (isalnum(tok) || (tok == '_')) { s >> tok; res += tok; } else break; } return res; } void preprocess_string(istream &s,string &res) { // Grab string surrounded by double quotes from stream or call preprocess_error int4 val; s >> ws; // Skip any whitespace val = s.get(); if (val != '\"') preproc_error("Expecting double quoted string"); val = s.get(); while((val != '\"')&&(val>=0)) { res += (char)val; val = s.get(); } if (val != '\"') preproc_error("Missing terminating double quote"); } extern int4 preprocess_if(istream &s); // Forward declaration for recursion int4 read_defined_operator(istream &s) { // We have seen a -defined- keyword in an if or elif // Read macro name used as input, return 1 if it is defined char tok = ' '; string macroname; s >> ws >> tok; if (tok != '(') preproc_error("Badly formed \"defined\" operator"); macroname = read_identifier(s); int4 res = slgh->getPreprocValue(macroname,macroname) ? 1 : 0; s >> ws >> tok; if (tok != ')') preproc_error("Badly formed \"defined\" operator"); return res; } int4 read_boolean_clause(istream &s) { // We have seen an if or elif // return 1 if condition is true or else 0 s >> ws; if (s.peek()=='(') { // Parenthetical expression spawns recursion int4 val = s.get(); int4 res = preprocess_if(s); s >> ws; val = s.get(); if (val != ')') preproc_error("Unbalanced parentheses"); return res; } // Otherwise we must have a normal comparison operator string lhs,rhs,comp; if (s.peek()=='\"') // Read left-hand side string preprocess_string(s,lhs); else { lhs = read_identifier(s); if (lhs == "defined") return read_defined_operator(s); if (!slgh->getPreprocValue(lhs,lhs)) preproc_error("Could not find preprocessor macro "+lhs); } char tok; s >> tok; // Read comparison symbol comp += tok; s >> tok; comp += tok; s >> ws; if (s.peek()=='\"') // Read right-hand side string preprocess_string(s,rhs); else { rhs = read_identifier(s); if (!slgh->getPreprocValue(rhs,rhs)) preproc_error("Could not find preprocessor macro "+rhs); } if (comp == "==") return (lhs == rhs) ? 1 : 0; else if (comp=="!=") return (lhs != rhs) ? 1 : 0; else preproc_error("Syntax error in condition"); return 0; } int4 preprocess_if(istream &s) { int4 res = read_boolean_clause(s); s >> ws; while((!s.eof())&&(s.peek()!=')')) { string boolop; char tok; s >> tok; boolop += tok; s >> tok; boolop += tok; int4 res2 = read_boolean_clause(s); if (boolop == "&&") res = res & res2; else if (boolop == "||") res = res | res2; else if (boolop == "^^") res = res ^ res2; else preproc_error("Syntax error in expression"); s >> ws; } return res; } void expand_preprocmacros(string &str) { string::size_type pos; string::size_type lastpos = 0; pos = str.find("$(",lastpos); if (pos == string::npos) return; string res; for(;;) { if (pos == string::npos) { res += str.substr(lastpos); str = res; return; } else { res += str.substr(lastpos,(pos-lastpos)); string::size_type endpos = str.find(')',pos+2); if (endpos == string::npos) { preproc_error("Unterminated macro in string"); break; } string macro = str.substr(pos+2, endpos - (pos+2)); string value; if (!slgh->getPreprocValue(macro,value)) { preproc_error("Unknown preprocessing macro "+macro); break; } res += value; lastpos = endpos + 1; } pos = str.find("$(",lastpos); } } int4 preprocess(int4 cur_state,int4 blank_state) { string str(yytext); string::size_type pos = str.find('#'); if (pos != string::npos) str.erase(pos); istringstream s(str); string type; if (cur_state != blank_state) last_preproc = cur_state; s.get(); // Skip the preprocessor marker s >> type; if (type == "include") { if (negative_if == -1) { // Not in the middle of a false if clause filebuffers.push_back(FileStreamState()); // Save state of current file filebuffers.back().lastbuffer = YY_CURRENT_BUFFER; filebuffers.back().file = (FILE *)0; s >> ws; string fname; preprocess_string(s,fname); expand_preprocmacros(fname); slgh->parseFromNewFile(fname); fname = slgh->grabCurrentFilePath(); yyin = fopen(fname.c_str(),"r"); if (yyin == (FILE *)0) preproc_error("Could not open included file "+fname); filebuffers.back().file = yyin; yy_switch_to_buffer( yy_create_buffer(yyin, YY_BUF_SIZE) ); check_to_endofline(s); } } else if (type == "define") { if (negative_if == -1) { string varname; string value; varname = read_identifier(s); // Get name of variable being defined s >> ws; if (s.peek() == '\"') preprocess_string(s,value); else value = read_identifier(s); if (varname.size()==0) preproc_error("Error in preprocessor definition"); slgh->setPreprocValue(varname,value); check_to_endofline(s); } } else if (type == "undef") { if (negative_if == -1) { string varname; varname = read_identifier(s); // Name of variable to undefine if (varname.size()==0) preproc_error("Error in preprocessor undef"); slgh->undefinePreprocValue(varname); check_to_endofline(s); } } else if (type=="ifdef") { string varname; varname = read_identifier(s); if (varname.size()==0) preproc_error("Error in preprocessor ifdef"); string value; int4 truth = (slgh->getPreprocValue(varname,value)) ? 1 : 0; ifstack.push_back(truth); check_to_endofline(s); } else if (type=="ifndef") { string varname; varname = read_identifier(s); if (varname.size()==0) preproc_error("Error in preprocessor ifndef"); string value; int4 truth = (slgh->getPreprocValue(varname,value)) ? 0 : 1; // flipped from ifdef ifstack.push_back(truth); check_to_endofline(s); } else if (type=="if") { int4 truth = preprocess_if(s); if (!s.eof()) preproc_error("Unbalanced parentheses"); ifstack.push_back(truth); } else if (type=="elif") { if (ifstack.empty()) preproc_error("elif without preceding if"); if ((ifstack.back()&2)!=0) // We have already seen an else clause preproc_error("elif follows else"); if ((ifstack.back()&4)!=0) // We have already seen a true elif clause ifstack.back() = 4; // don't include any other elif clause else if ((ifstack.back()&1)!=0) // Last clause was a true if ifstack.back() = 4; // don't include this elif else { int4 truth = preprocess_if(s); if (!s.eof()) preproc_error("Unbalanced parentheses"); if (truth==0) ifstack.back() = 0; else ifstack.back() = 5; } } else if (type=="endif") { if (ifstack.empty()) preproc_error("preprocessing endif without matching if"); ifstack.pop_back(); check_to_endofline(s); } else if (type=="else") { if (ifstack.empty()) preproc_error("preprocessing else without matching if"); if ((ifstack.back()&2)!=0) preproc_error("second else for one if"); if ((ifstack.back()&4)!=0) // Seen a true elif clause before ifstack.back() = 6; else if (ifstack.back()==0) ifstack.back() = 3; else ifstack.back() = 2; check_to_endofline(s); } else preproc_error("Unknown preprocessing directive: "+type); if (negative_if >= 0) { // We were in a false state if (negative_if+1 < ifstack.size()) return blank_state; // false state is still deep in stack else // false state is popped off or is current and changed negative_if = -1; } if (ifstack.empty()) return last_preproc; if ((ifstack.back()&1)==0) { negative_if = ifstack.size()-1; return blank_state; } return last_preproc; } void preproc_macroexpand(void) { filebuffers.push_back(FileStreamState()); filebuffers.back().lastbuffer = YY_CURRENT_BUFFER; filebuffers.back().file = (FILE *)0; string macro(yytext); macro.erase(0,2); macro.erase(macro.size()-1,1); string value; if (!slgh->getPreprocValue(macro,value)) preproc_error("Unknown preprocessing macro "+macro); yy_switch_to_buffer( yy_scan_string( value.c_str() ) ); slgh->parsePreprocMacro(); } int4 find_symbol(void) { string * newstring = new string(yytext); SleighSymbol *sym = slgh->findSymbol(*newstring); if (sym == (SleighSymbol *)0) { yylval.str = newstring; return STRING; } delete newstring; switch(sym->getType()) { case SleighSymbol::section_symbol: yylval.sectionsym = (SectionSymbol *)sym; return SECTIONSYM; case SleighSymbol::space_symbol: yylval.spacesym = (SpaceSymbol *)sym; return SPACESYM; case SleighSymbol::token_symbol: yylval.tokensym = (TokenSymbol *)sym; return TOKENSYM; case SleighSymbol::userop_symbol: yylval.useropsym = (UserOpSymbol *)sym; return USEROPSYM; case SleighSymbol::value_symbol: yylval.valuesym = (ValueSymbol *)sym; return VALUESYM; case SleighSymbol::valuemap_symbol: yylval.valuemapsym = (ValueMapSymbol *)sym; return VALUEMAPSYM; case SleighSymbol::name_symbol: yylval.namesym = (NameSymbol *)sym; return NAMESYM; case SleighSymbol::varnode_symbol: yylval.varsym = (VarnodeSymbol *)sym; return VARSYM; case SleighSymbol::bitrange_symbol: yylval.bitsym = (BitrangeSymbol *)sym; return BITSYM; case SleighSymbol::varnodelist_symbol: yylval.varlistsym = (VarnodeListSymbol *)sym; return VARLISTSYM; case SleighSymbol::operand_symbol: yylval.operandsym = (OperandSymbol *)sym; return OPERANDSYM; case SleighSymbol::start_symbol: yylval.startsym = (StartSymbol *)sym; return STARTSYM; case SleighSymbol::end_symbol: yylval.endsym = (EndSymbol *)sym; return ENDSYM; case SleighSymbol::subtable_symbol: yylval.subtablesym = (SubtableSymbol *)sym; return SUBTABLESYM; case SleighSymbol::macro_symbol: yylval.macrosym = (MacroSymbol *)sym; return MACROSYM; case SleighSymbol::label_symbol: yylval.labelsym = (LabelSymbol *)sym; return LABELSYM; case SleighSymbol::epsilon_symbol: yylval.specsym = (SpecificSymbol *)sym; return SPECSYM; case SleighSymbol::context_symbol: yylval.contextsym = (ContextSymbol *)sym; return CONTEXTSYM; case SleighSymbol::dummy_symbol: break; } return -1; // Should never reach here } int4 scan_number(char *numtext,YYSTYPE *lval,bool signednum) { uintb val; if (numtext[0] == '0' && numtext[1] == 'b') { val = 0; numtext += 2; while ((*numtext) != 0) { val <<= 1; if (*numtext == '1') { val |= 1; } ++numtext; } } else { istringstream s(numtext); s.unsetf(ios::dec | ios::hex | ios::oct); s >> val; if (!s) return BADINTEGER; } if (signednum) { lval->big = new intb(val); return INTB; } lval->i = new uintb(val); return INTEGER; } %} %x defblock %x macroblock %x print %x pattern %x sem %x preproc %% ^@[^\n]*\n? { slgh->nextLine(); BEGIN( preprocess(INITIAL,preproc) ); } \$\([a-zA-Z0-9_.][a-zA-Z0-9_.]*\) { preproc_macroexpand(); } [(),\-] { yylval.ch = yytext[0]; return yytext[0]; } \: { BEGIN(print); slgh->calcContextLayout(); yylval.ch = yytext[0]; return yytext[0]; } \{ { BEGIN(sem); yylval.ch = yytext[0]; return yytext[0]; } #.* [\r\ \t\v]+ \n { slgh->nextLine(); } macro { BEGIN(macroblock); return MACRO_KEY; } define { BEGIN(defblock); return DEFINE_KEY; } attach { BEGIN(defblock); slgh->calcContextLayout(); return ATTACH_KEY; } with { BEGIN(pattern); withsection = 1; slgh->calcContextLayout(); return WITH_KEY; } [a-zA-Z_.][a-zA-Z0-9_.]* { return find_symbol(); } . { return yytext[0]; } ^@[^\n]*\n? { slgh->nextLine(); BEGIN( preprocess(macroblock,preproc) ); } \$\([a-zA-Z0-9_.][a-zA-Z0-9_.]*\) { preproc_macroexpand(); } [(),] { yylval.ch = yytext[0]; return yytext[0]; } \{ { BEGIN(sem); return yytext[0]; } [a-zA-Z_.][a-zA-Z0-9_.]* { yylval.str = new string(yytext); return STRING; } [\r\ \t\v]+ \n { slgh->nextLine(); } . { return yytext[0]; } ^@[^\n]*\n? { slgh->nextLine(); BEGIN( preprocess(defblock,preproc) ); } \$\([a-zA-Z0-9_.][a-zA-Z0-9_.]*\) { preproc_macroexpand(); } [(),=:\[\]] { yylval.ch = yytext[0]; return yytext[0]; } \; { BEGIN(INITIAL); yylval.ch = yytext[0]; return yytext[0]; } space { return SPACE_KEY; } type { return TYPE_KEY; } ram_space { return RAM_KEY; } default { return DEFAULT_KEY; } register_space { return REGISTER_KEY; } token { return TOKEN_KEY; } context { return CONTEXT_KEY; } bitrange { return BITRANGE_KEY; } signed { return SIGNED_KEY; } noflow { return NOFLOW_KEY; } hex { return HEX_KEY; } dec { return DEC_KEY; } endian { return ENDIAN_KEY; } alignment { return ALIGN_KEY; } big { return BIG_KEY; } little { return LITTLE_KEY; } size { return SIZE_KEY; } wordsize { return WORDSIZE_KEY; } offset { return OFFSET_KEY; } names { return NAMES_KEY; } values { return VALUES_KEY; } variables { return VARIABLES_KEY; } pcodeop { return PCODEOP_KEY; } #.* [a-zA-Z_.][a-zA-Z0-9_.]* { return find_symbol(); } [0-9]|[1-9][0-9]+ { return scan_number(yytext,&yylval,false); } 0x[0-9a-fA-F]+ { return scan_number(yytext,&yylval,false); } 0b[01]+ { return scan_number(yytext,&yylval,false); } \"([^\"[:cntrl:]]|\"\")*\" { yylval.str = new string(yytext+1,strlen(yytext)-2); return STRING; } [\r\ \t\v]+ \n { slgh->nextLine(); } . { return yytext[0]; } ^@[^\n]*\n? { slgh->nextLine(); BEGIN( preprocess(print,preproc) ); } \$\([a-zA-Z0-9_.][a-zA-Z0-9_.]*\) { preproc_macroexpand(); } [~!@#$%&*()\-=+\[\]{}|;:<>?,/0-9] { yylval.ch = yytext[0]; return CHAR; } \^ { yylval.ch = '^'; return '^'; } is { BEGIN(pattern); actionon=0; return IS_KEY; } [a-zA-Z_.][a-zA-Z0-9_.]* { yylval.str = new string(yytext); return SYMBOLSTRING; } \"([^\"[:cntrl:]]|\"\")*\" { yylval.str = new string(yytext+1,strlen(yytext)-2); return STRING; } [\r\ \t\v]+ { yylval.ch = ' '; return ' '; } \n { slgh->nextLine(); return ' '; } . { return yytext[0]; } ^@[^\n]*\n? { slgh->nextLine(); BEGIN( preprocess(pattern,preproc) ); } \$\([a-zA-Z0-9_.][a-zA-Z0-9_.]*\) { preproc_macroexpand(); } \{ { BEGIN((withsection==1) ? INITIAL:sem); withsection=0; yylval.ch = yytext[0]; return yytext[0]; } unimpl { BEGIN(INITIAL); return OP_UNIMPL; } globalset { return GLOBALSET_KEY; } \>\> { return OP_RIGHT; } \<\< { return OP_LEFT; } \!\= { return OP_NOTEQUAL; } \<\= { return OP_LESSEQUAL; } \>\= { return OP_GREATEQUAL; } \$and { return OP_AND; } \$or { return OP_OR; } \$xor { return OP_XOR; } \.\.\. { return ELLIPSIS_KEY; } \[ { actionon = 1; yylval.ch = yytext[0]; return yytext[0]; } \] { actionon = 0; yylval.ch = yytext[0]; return yytext[0]; } \& { yylval.ch = yytext[0]; return (actionon==0) ? yytext[0] : OP_AND; } \| { yylval.ch = yytext[0]; return (actionon==0) ? yytext[0] : OP_OR; } \^ { return OP_XOR; } [=(),:;+\-*/~<>] { yylval.ch = yytext[0]; return yytext[0]; } #.* [a-zA-Z_.][a-zA-Z0-9_.]* { return find_symbol(); } [0-9]|[1-9][0-9]+ { return scan_number(yytext,&yylval,true); } 0x[0-9a-fA-F]+ { return scan_number(yytext,&yylval,true); } 0b[01]+ { return scan_number(yytext,&yylval,true); } [\r\ \t\v]+ \n { slgh->nextLine(); } . { return yytext[0]; } ^@[^\n]*\n? { slgh->nextLine(); BEGIN( preprocess(sem,preproc) ); } \$\([a-zA-Z0-9_.][a-zA-Z0-9_.]*\) { preproc_macroexpand(); } \} { BEGIN(INITIAL); yylval.ch = yytext[0]; return yytext[0]; } \|\| { return OP_BOOL_OR; } \&\& { return OP_BOOL_AND; } \^\^ { return OP_BOOL_XOR; } \>\> { return OP_RIGHT; } \<\< { return OP_LEFT; } \=\= { return OP_EQUAL; } \!\= { return OP_NOTEQUAL; } \<\= { return OP_LESSEQUAL; } \>\= { return OP_GREATEQUAL; } s\/ { return OP_SDIV; } s\% { return OP_SREM; } s\>\> { return OP_SRIGHT; } s\< { return OP_SLESS; } s\> { return OP_SGREAT; } s\<\= { return OP_SLESSEQUAL; } s\>\= { return OP_SGREATEQUAL; } f\+ { return OP_FADD; } f\- { return OP_FSUB; } f\* { return OP_FMULT; } f\/ { return OP_FDIV; } f\=\= { return OP_FEQUAL; } f\!\= { return OP_FNOTEQUAL; } f\< { return OP_FLESS; } f\> { return OP_FGREAT; } f\<\= { return OP_FLESSEQUAL; } f\>\= { return OP_FGREATEQUAL; } zext { return OP_ZEXT; } carry { return OP_CARRY; } borrow { return OP_BORROW; } sext { return OP_SEXT; } scarry { return OP_SCARRY; } sborrow { return OP_SBORROW; } nan { return OP_NAN; } abs { return OP_ABS; } sqrt { return OP_SQRT; } ceil { return OP_CEIL; } floor { return OP_FLOOR; } round { return OP_ROUND; } int2float { return OP_INT2FLOAT; } float2float { return OP_FLOAT2FLOAT; } trunc { return OP_TRUNC; } cpool { return OP_CPOOLREF; } newobject { return OP_NEW; } popcount { return OP_POPCOUNT; } if { return IF_KEY; } goto { return GOTO_KEY; } call { return CALL_KEY; } return { return RETURN_KEY; } delayslot { return DELAYSLOT_KEY; } crossbuild { return CROSSBUILD_KEY; } export { return EXPORT_KEY; } build { return BUILD_KEY; } local { return LOCAL_KEY; } [=(),:\[\];!&|^+\-*/%~<>] { yylval.ch = yytext[0]; return yytext[0]; } #.* [a-zA-Z_.][a-zA-Z0-9_.]* { return find_symbol(); } [0-9]|[1-9][0-9]+ { return scan_number(yytext,&yylval,false); } 0x[0-9a-fA-F]+ { return scan_number(yytext,&yylval,false); } 0b[01]+ { return scan_number(yytext,&yylval,false); } [\r\ \t\v]+ \n { slgh->nextLine(); } . { return yytext[0]; } ^@.*\n? { slgh->nextLine(); BEGIN( preprocess(preproc,preproc) ); } ^.*\n { slgh->nextLine(); } <> { yy_delete_buffer( YY_CURRENT_BUFFER ); if (filebuffers.empty()) yyterminate(); yy_switch_to_buffer( filebuffers.back().lastbuffer ); FILE *curfile = filebuffers.back().file; if (curfile != (FILE *)0) fclose(curfile); filebuffers.pop_back(); slgh->parseFileFinished(); }