////////////////////////////////////////////////////////////////////////////// // This file create IDA Enums by parsing C/C++ .H include file // // Version: 1.05 // // History of changes: // // v1.00 28.09.1998 Started by Leonid Lisovsky . // v1.01 02.12.1998 Bugfix & corrections to get more universality. // v1.02 04.12.1998 First step to resolve expressions. // v1.03 04.08.1999 More smart error messages, // second approach to resolve arithmetic expressions. // v1.04 08.08.1999 Arithmetic evaluator ready to use. // v1.05 05.10.1999 Corrections due to changes in IDA 3.85, // the right total counter was made. Constants // will not more be cuted off on the first blank. // // TODO: 1. GetAtom() - Smart constant recognizing. ////////////////////////////////////////////////////////////////////////////// #include #define DEFINE_TOKEN "#define" #define XREF_ARRAY "h2enum_xrefs" #define EXPR_ARRAY "h2enum_expr" ////////////////////////////////////////////////////////////////////////////// // returns -1 if symbol is NOT 'space' static is_space(c) { return strstr(" \t\r\n\b",c); } // strip leading blank characters from string. static ltrim(str) { auto pos,c,l; l = strlen(str); pos = 0; while (pos < l) { c = substr(str,pos,pos+1); if (is_space(c) == -1) break; pos++; } return substr(str,pos,-1); } // strip trailing blank characters from string. static rtrim(str) { auto pos,c; pos = strlen(str); while (pos > 0) { c = substr(str,pos-1,pos); if (is_space(c) == -1) break; pos--; } return substr(str,0,pos); } static trim(str) { return rtrim( ltrim(str) ); } // Find delimiter position in string (SPACE or TAB). static FindDelim(str) { auto pos; pos = strstr(str," "); if (pos == -1) return strstr(str,"\t"); else return pos; } // Find C/C++ comment start position in string ( // or /* ). static FindCcomment(str) { auto pos; pos = strstr(str,"//"); if (pos == -1) return strstr(str,"/*"); else return pos; } // Add Constant with custom error messages static My_AddConst(enum_ID,enum_elem_name,enum_elem_val,str_no) { auto v_idx, dupe_elem_name; v_idx = AddConst(enum_ID,enum_elem_name,enum_elem_val); if (v_idx == CONST_ERROR_NAME) { Message("*DUPE* (line:%d) %s %0Xh\n",str_no,enum_elem_name, enum_elem_val); } else if (v_idx == CONST_ERROR_VALUE) { dupe_elem_name=GetConstName(GetConst(enum_ID,enum_elem_val,-1)); Message("*DUPE VALUE* (line:%d) %s == %s %0Xh\n", str_no,enum_elem_name,dupe_elem_name,enum_elem_val); } } //---------------------------------------------------------------------------- // Arithmetic evaluator functions #define TOK_NONE -1 #define TOK_VAR 0 #define TOK_PLUS 1 #define TOK_MINUS 2 #define TOK_OR 3 #define TOK_AND 4 #define TOK_XOR 5 #define TOK_MULT 10 #define TOK_DIV 11 #define TOK_MOD 12 #define TOK_NOT 20 #define TOK_L_PAR 30 #define TOK_R_PAR 31 // Parse and evaluate arithmetic expression static ParseExpr(str) { auto expr_ID; auto startpos,pos,v_idx; auto c,is_token,token1,value; if ((expr_ID=GetArrayId(EXPR_ARRAY)) == -1) if ((expr_ID=CreateArray(EXPR_ARRAY)) == -1) { Warning("Couldn't create array '%s' for evaluating expressions !",EXPR_ARRAY); return; } // Fill array with tokens v_idx = 2; startpos = 0; is_token = 0; for(pos=0; pos 2) value = eval_1(expr_ID,0); else value = 0; DeleteArray(expr_ID); return value; } // Add, Subtract, OR, AND , XOR static eval_1(expr_ID, prev_val) { auto value,op; value = eval_2(expr_ID, prev_val); while ( ((op=tok_type(expr_ID))==TOK_PLUS) || (op==TOK_MINUS) || (op==TOK_OR) || (op==TOK_AND) || (op==TOK_XOR) ) { SetArrayLong(expr_ID,0,GetArrayElement(AR_LONG,expr_ID,0)+1); if (op == TOK_PLUS) value = value + eval_2(expr_ID, value); else if (op == TOK_MINUS) value = value - eval_2(expr_ID, value); else if (op == TOK_OR) value = value | eval_2(expr_ID, value); else if (op == TOK_AND) value = value & eval_2(expr_ID, value); else if (op == TOK_XOR) value = value ^ eval_2(expr_ID, value); } return value; } // Multiply, Divide, Mod static eval_2(expr_ID, prev_val) { auto value,op; value = eval_3(expr_ID, prev_val); while ( ((op=tok_type(expr_ID))==TOK_MULT) || (op==TOK_DIV) || (op==TOK_MOD) ) { SetArrayLong(expr_ID,0,GetArrayElement(AR_LONG,expr_ID,0)+1); if (op == TOK_MULT) value = value * eval_3(expr_ID, value); else if (op == TOK_DIV) value = value / eval_3(expr_ID, value); else if (op == TOK_MOD) value = value % eval_3(expr_ID, value); } return value; } // Unary -, NOT static eval_3(expr_ID, prev_val) { auto value,op; op = tok_type(expr_ID); if ( (op==TOK_MINUS) || (op==TOK_NOT)) { SetArrayLong(expr_ID,0,GetArrayElement(AR_LONG,expr_ID,0)+1); if (op==TOK_MINUS) value = - eval_4(expr_ID, 0); else if (op==TOK_NOT) value = ~ eval_4(expr_ID, 0); } else value = eval_4(expr_ID, prev_val); return value; } // Parentheses, constants static eval_4(expr_ID, prev_val) { auto value,op,ind; op = tok_type(expr_ID); if (op==TOK_L_PAR) { SetArrayLong(expr_ID,0,GetArrayElement(AR_LONG,expr_ID,0)+1); value = eval_1(expr_ID,prev_val); if (tok_type(expr_ID) == TOK_R_PAR) SetArrayLong(expr_ID,0,GetArrayElement(AR_LONG,expr_ID,0)+1); else Message("*** Right parenthess missing!\n"); } else { if (op!=TOK_NONE) { ind = GetArrayElement(AR_LONG,expr_ID,0); value = GetAtom(GetArrayElement(AR_STR,expr_ID,ind)); SetArrayLong(expr_ID,0,GetArrayElement(AR_LONG,expr_ID,0)+1); } else value = 0; } return value; } // return token type static tok_type(expr_ID) { auto ind,tok; ind = GetArrayElement(AR_LONG,expr_ID,0); if (ind >= GetArrayElement(AR_LONG,expr_ID,1)) return TOK_NONE; // Out of bounds tok = GetArrayElement(AR_STR,expr_ID,ind); if ( tok == "+" ) return TOK_PLUS; if ( tok == "-" ) return TOK_MINUS; if ( tok == "|" ) return TOK_OR; if ( tok == "&" ) return TOK_AND; if ( tok == "^" ) return TOK_XOR; if ( tok == "*" ) return TOK_MULT; if ( tok == "/" ) return TOK_DIV; if ( tok == "%" ) return TOK_MOD; if ( tok == "~" ) return TOK_NOT; if ( tok == "(" ) return TOK_L_PAR; if ( tok == ")" ) return TOK_R_PAR; return TOK_VAR; } // return value of constant or variable static GetAtom(token) { auto val; val = atol(token); // try Decimal convert if (val == 0) val = xtol(token); // try HEX convert if (val == 0) val = GetConstValue(GetConstByName(token)); return val; } ////////////////////////////////////////////////////////////////////////////// static main() { auto enum_ID,xref_ID,v_idx,total; auto enum_name,enum_St_tok,enum_elem_name,enum_elem_val; auto fil_nam,h,in_str,pos,wrk_str,str_no,c; fil_nam = AskFile(0,"*.h","Choose a header(.H) file to parse:"); if (fil_nam == "") return; if ((h=fopen(fil_nam,"r")) == 0) { Warning("Couldn't open file '%s'!",fil_nam); return; } enum_name = AskStr("WinMsg","Enter name for enumeration (alphas only):"); enum_St_tok = AskIdent("WM_","Enter partial name for filtering defines:"); if ((enum_ID=GetEnum(enum_name)) == -1) // New enum if ((enum_ID=AddEnum(GetEnumQty() + 1, enum_name, FF_0NUMH)) == -1) { Warning("Couldn't create enumeration '%s'!",enum_name); return; } if ((xref_ID=GetArrayId(XREF_ARRAY)) == -1) if ((xref_ID=CreateArray(XREF_ARRAY)) == -1) { Warning("Couldn't create array '%s' for xrefs !",XREF_ARRAY); return; } Message("Conversion started...\n"); total = GetEnumSize(enum_ID); //Pass 1 - import definitions str_no = 0; while ((in_str=readstr(h)) != -1) { str_no++; if ((pos=strstr(in_str,DEFINE_TOKEN)) == -1 ) continue; // NO required token on line in_str = ltrim(substr(in_str,pos+strlen(DEFINE_TOKEN),-1)); if (substr(in_str,0,strlen(enum_St_tok)) == enum_St_tok) { if ((pos=FindDelim(in_str))==-1) continue; // only 2 tokens i.e. "#define SOME" enum_elem_name = rtrim(substr(in_str,0,pos)); in_str = ltrim(substr(in_str,pos,-1)); pos = FindCcomment(in_str); wrk_str = rtrim(substr(in_str,0,pos)); enum_elem_val = GetAtom(wrk_str); if (enum_elem_val == 0) { // Possible regular expression - resolving later if (SetHashString(xref_ID,enum_elem_name,wrk_str)==0) Message("*** Cannot Add xref %s = '%s'\n",enum_elem_name,wrk_str); continue; } My_AddConst(enum_ID,enum_elem_name,enum_elem_val,str_no); } } fclose(h); // Pass 2 - resolving regular expressions // for (enum_elem_name=GetFirstHashKey(xref_ID);enum_elem_name!=""; enum_elem_name=GetNextHashKey(xref_ID,enum_elem_name)) { wrk_str = GetHashString(xref_ID,enum_elem_name); enum_elem_val = ParseExpr(wrk_str); My_AddConst(enum_ID,enum_elem_name,enum_elem_val,-1); } DeleteArray(xref_ID); total = GetEnumSize(enum_ID) - total; Message("Successful %d elements imported.\n",total); }