int main(int argc, char *argv[]) { std::ios::sync_with_stdio(); argv0 = argv[0]; { size_t slash = argv0.rfind('/'); argv0 = slash==std::string::npos ? argv0 : argv0.substr(slash+1); if (0==argv0.substr(0, 3).compare("lt-")) argv0 = argv0.substr(3); } // Parse switches int argno = 1; for (/*void*/; argno<argc && '-'==argv[argno][0]; ++argno) { if (!strcmp(argv[argno], "--")) { ++argno; break; } else if (!strcmp(argv[argno], "--help") || !strcmp(argv[argno], "-h")) { usage(0); } else { std::cerr <<argv0 <<": unrecognized switch: " <<argv[argno] <<"\n" "see \"" <<argv0 <<" --help\" for usage info.\n"; exit(1); } } if (argno+1!=argc) { std::cerr <<argv0 <<": missing database URL\n" <<"see \"" <<argv0 <<" --help\" for usage info.\n"; exit(1); } SqlDatabase::TransactionPtr tx = SqlDatabase::Connection::create(argv[argno])->transaction(); // Get the set of commands that created these inputs. This set is pretty small (usually just one command), so we make no // attempt to optimize it. size_t ncmds = 0; SqlDatabase::StatementPtr stmt0 = tx->statement("select distinct cmd from semantic_inputvalues"); for (SqlDatabase::Statement::iterator row=stmt0->begin(); row!=stmt0->end(); ++row, ++ncmds) { SqlDatabase::StatementPtr stmt1 = tx->statement("select hashkey, begin_time, end_time, notation, command" " from semantic_history where hashkey = ?"); stmt1->bind(0, row.get<uint64_t>(0)); SqlDatabase::Statement::iterator cmd = stmt1->begin(); assert(cmd!=stmt1->end()); std::cout <<"insert into semantic_history (hashkey, begin_time, end_time, notation, command) values (" <<cmd.get<int64_t>(0) <<", " // hashkey <<cmd.get<int64_t>(1) <<", " // begin_time <<cmd.get<int64_t>(2) <<", " // end_time <<SqlDatabase::escape(cmd.get<std::string>(3), tx->driver()) <<", " // notation <<SqlDatabase::escape(cmd.get<std::string>(4), tx->driver()) <<");\n"; // command } // Get the input values size_t nivalues = 0; std::cout <<"copy semantic_inputvalues (igroup_id, queue_id, pos, val, cmd) from stdin;\n"; SqlDatabase::StatementPtr stmt2 = tx->statement("select igroup_id, queue_id, pos, val, cmd from semantic_inputvalues"); for (SqlDatabase::Statement::iterator row=stmt2->begin(); row!=stmt2->end(); ++row, ++nivalues) { std::cout <<row.get<int32_t>(0) <<"\t" // igroup_id <<row.get<int32_t>(1) <<"\t" // queue_id <<row.get<int32_t>(2) <<"\t" // pos <<row.get<int64_t>(3) <<"\t" // val <<row.get<int64_t>(4) <<"\n"; // cmd } std::cout <<"\\.\n"; std::cerr <<argv0 <<": dumped " <<StringUtility::plural(nivalues, "input values") <<" from " <<StringUtility::plural(ncmds, "commands") <<".\n"; return 0; }
static int find_function_or_exit(const SqlDatabase::TransactionPtr &tx, char *func_spec) { char *rest; errno = 0; int func_id = -1; int func_spec_i = strtol(func_spec, &rest, 0); if (errno || rest==func_spec || *rest) func_spec_i = -1; if (-1==func_id && -1!=func_spec_i && 1==tx->statement("select count(*) from semantic_functions where id = ?")->bind(0, func_spec_i)->execute_int()) func_id = func_spec_i; if (-1==func_id) { SqlDatabase::StatementPtr stmt1a = tx->statement("select func.id, func.entry_va, func.name, func.ninsns, file.name" " from semantic_functions as func" " join semantic_files as file on func.file_id = file.id" " where entry_va = ?")->bind(0, func_spec_i); SqlDatabase::StatementPtr stmt1b = tx->statement("select func.id, func.entry_va, func.name, func.ninsns, file.name" " from semantic_functions as func" " join semantic_files as file on func.file_id = file.id" " where func.name = ?")->bind(0, func_spec); SqlDatabase::StatementPtr stmt1c = tx->statement("select func.id, func.entry_va, func.name, func.ninsns, file.name" " from semantic_functions as func" " join semantic_files as file on func.file_id = file.id" " where file.name like" " '%/"+SqlDatabase::escape(func_spec, tx->driver(), false)+"'"); SqlDatabase::Table<int, rose_addr_t, std::string, size_t, std::string> functions; if (func_spec_i!=-1) functions.insert(stmt1a); functions.insert(stmt1b); functions.insert(stmt1c); functions.headers("ID", "Entry VA", "Function Name", "NInsns", "Specimen Name"); functions.renderers().r1 = &SqlDatabase::addr32Renderer; if (functions.empty()) { std::cout <<argv0 <<": no function found by ID, address, or name: " <<func_spec <<"\n"; exit(0); } else if (1==functions.size()) { func_id = functions[0].v0; } else { std::cout <<argv0 <<": function specification is ambiguous: " <<func_spec <<"\n"; functions.print(std::cout); exit(0); } } assert(func_id>=0); return func_id; }
int main(int argc, char *argv[]) { std::ios::sync_with_stdio(); argv0 = argv[0]; { size_t slash = argv0.rfind('/'); argv0 = slash==std::string::npos ? argv0 : argv0.substr(slash+1); if (0==argv0.substr(0, 3).compare("lt-")) argv0 = argv0.substr(3); } Switches opt; int argno = 1; for (/*void*/; argno<argc && '-'==argv[argno][0]; ++argno) { if (!strcmp(argv[argno], "--")) { ++argno; break; } else if (!strcmp(argv[argno], "--help") || !strcmp(argv[argno], "-h")) { ::usage(0); } else if (!strncmp(argv[argno], "--entry=", 8)) { opt.entry_vas.insert(strtoull(argv[argno]+8, NULL, 0)); } else if (!strcmp(argv[argno], "--file=list") || !strcmp(argv[argno], "--files=list")) { opt.list_files = true; } else if (!strncmp(argv[argno], "--file=", 7) || !strncmp(argv[argno], "--files=", 8)) { std::vector<std::string> ids = StringUtility::split(",", strchr(argv[argno], '=')+1, (size_t)-1, true); for (size_t i=0; i<ids.size(); ++i) { const char *s = ids[i].c_str(); char *rest; errno = 0; int id = strtoul(s, &rest, 0); if (errno || rest==s || *rest) { std::cerr <<argv0 <<": invalid file ID: " <<ids[i] <<"\n"; exit(1); } opt.files.insert(id); } } else if (!strncmp(argv[argno], "--function=", 11) || !strncmp(argv[argno], "--functions=", 12)) { std::vector<std::string> ids = StringUtility::split(",", strchr(argv[argno], '=')+1, (size_t)-1, true); if (ids.size()==1 && isalpha(ids[0][0]) && ids[0].find_first_of('.')!=std::string::npos) { std::vector<std::string> words = StringUtility::split(".", ids[0]); if (words.size()!=2 || !SqlDatabase::is_valid_table_name(words[0]) || !SqlDatabase::is_valid_table_name(words[1])) { std::cerr <<argv0 <<": --function switch needs either IDs or a database TABLE.COLUMN\n"; exit(1); } opt.function_table = words[0]; opt.function_column = words[1]; } else { for (size_t i=0; i<ids.size(); ++i) { const char *s = ids[i].c_str(); char *rest; errno = 0; int id = strtoul(s, &rest, 0); if (errno || rest==s || *rest) { std::cerr <<argv0 <<": invalid function ID: " <<ids[i] <<"\n"; exit(1); } opt.functions.insert(id); } } } else if (!strncmp(argv[argno], "--first-fuzz=", 13)) { opt.first_fuzz = strtoul(argv[argno]+13, NULL, 0); } else if (!strncmp(argv[argno], "--name=", 7)) { opt.names.insert(argv[argno]+7); } else if (!strncmp(argv[argno], "--nfuzz=", 8)) { opt.nfuzz = strtoul(argv[argno]+8, NULL, 0); opt.nfuzz_set = true; } else if (!strncmp(argv[argno], "--size=", 7)) { opt.ninsns = strtoul(argv[argno]+7, NULL, 0); } else if (!strcmp(argv[argno], "--specimen=list") || !strcmp(argv[argno], "--specimens=list")) { opt.list_specimens = true; } else if (!strncmp(argv[argno], "--specimen=", 11) || !strncmp(argv[argno], "--specimens=", 12)) { std::vector<std::string> ids = StringUtility::split(",", strchr(argv[argno], '=')+1, (size_t)-1, true); for (size_t i=0; i<ids.size(); ++i) { const char *s = ids[i].c_str(); char *rest; errno = 0; int id = strtoul(s, &rest, 0); if (errno || rest==s || *rest) { std::cerr <<argv0 <<": invalid specimen ID: " <<ids[i] <<"\n"; exit(1); } opt.specimens.insert(id); } } else { std::cerr <<argv0 <<": unrecognized switch: " <<argv[argno] <<"\n" <<"see \"" <<argv0 <<" --help\" for usage info.\n"; exit(1); } } if (argno+1!=argc) ::usage(1); SqlDatabase::TransactionPtr tx = SqlDatabase::Connection::create(argv[argno++])->transaction(); // List the ID numbers and names for all specimen files if (opt.list_specimens) { SqlDatabase::Table<int, std::string> specimens; specimens.insert(tx->statement("select file.id, file.name" " from (select distinct specimen_id as id from semantic_functions) as specimen" " join semantic_files as file on specimen.id = file.id" " order by file.name")); specimens.headers("File ID", "Specimen Name"); specimens.print(std::cout); return 0; } // List the ID numbers and names for all files containing functions if (opt.list_files) { SqlDatabase::Table<int, std::string> files; files.insert(tx->statement("select file.id, file.name" " from (select distinct file_id as id from semantic_functions) as used" " join semantic_files as file on used.id = file.id" " order by file.name")); files.headers("File ID", "Binary File Name"); files.print(std::cout); return 0; } // Sanity checks if (!opt.functions.empty() && !opt.function_table.empty()) { std::cerr <<argv0 <<": --function=ID and --function=TABLE are mutually exclusive\n"; exit(1); } if (0==tx->statement("select count(*) from semantic_functions")->execute_int()) { std::cerr <<argv0 <<": database has no functions; nothing to test\n"; return 0; } if (0==tx->statement("select count(*) from semantic_inputvalues")->execute_int()) { std::cerr <<argv0 <<": database has no input groups; nothing to test\n"; return 0; } // Create table tmp_functions containing IDs for selected functions and their specimen IDs std::vector<std::string> constraints; if (!opt.entry_vas.empty()) constraints.push_back("func.entry_va " + SqlDatabase::in(opt.entry_vas)); if (!opt.names.empty()) constraints.push_back("func.name " + SqlDatabase::in_strings(opt.names, tx->driver())); if (!opt.specimens.empty()) constraints.push_back("func.specimen_id " + SqlDatabase::in(opt.specimens)); if (!opt.files.empty()) constraints.push_back("func.file_id " + SqlDatabase::in(opt.files)); if (!opt.functions.empty()) constraints.push_back("func.id " + SqlDatabase::in(opt.functions)); if (opt.ninsns>0) constraints.push_back("func.ninsns >= " + StringUtility::numberToString(opt.ninsns)); std::string sql1 = "select func.id, func.specimen_id from semantic_functions as func"; if (!opt.function_table.empty()) sql1 += " join "+opt.function_table+" as flist on func.id = flist."+opt.function_column; if (!constraints.empty()) sql1 += " where " + StringUtility::join(" and ", constraints); tx->execute("create temporary table tmp_functions as " + sql1); // Create table tmp_inputgroups containing IDs for selected input groups std::string sql2 = "select distinct igroup_id from semantic_inputvalues where igroup_id >= " + StringUtility::numberToString(opt.first_fuzz); if (opt.nfuzz_set) sql2 += " and igroup_id < " + StringUtility::numberToString(opt.first_fuzz+opt.nfuzz); tx->execute("create temporary table tmp_inputgroups as " + sql2); // Create tmp_pending as the cross product of functions and inputgroups except for those already tested tx->execute("create temporary table tmp_pending as" " select func.specimen_id as specimen_id, func.id as func_id, igroup.igroup_id as igroup_id" " from tmp_functions as func" " join tmp_inputgroups as igroup" " on igroup.igroup_id is not null" // "on" clause and "is not null" (rather than "true") for portability " except" " select func.specimen_id, func.id, fio.igroup_id" " from semantic_fio as fio" " join semantic_functions as func on fio.func_id=func.id"); SqlDatabase::StatementPtr stmt = tx->statement("select distinct specimen_id, func_id, igroup_id" " from tmp_pending" " order by specimen_id, igroup_id, func_id"); for (SqlDatabase::Statement::iterator row=stmt->begin(); row!=stmt->end(); ++row) std::cout <<row.get<int>(0) <<"\t" <<row.get<int>(1) <<"\t" <<row.get<int>(2) <<"\n"; // no need to commit, but if we change this in the future, be sure to add begin_command()/finish_command() return 0; }