tid_t idaapi merge_types(qvector<qstring> types_to_merge, qstring type_name) { tid_t struct_type_id = BADADDR; std::set<ea_t> offsets; if (types_to_merge.size() != 0) { struct_type_id = add_struc(BADADDR, type_name.c_str()); if (struct_type_id != 0 || struct_type_id != BADADDR) { struc_t * struc = get_struc(struct_type_id); if (struc != NULL) { qvector<qstring>::iterator types_iter; for (types_iter = types_to_merge.begin(); types_iter != types_to_merge.end(); types_iter++) { tid_t type_id = get_struc_id((*types_iter).c_str()); if (type_id != BADADDR) { struc_t * struc_type = get_struc(type_id); if (struc_type != NULL) { // enumerate members for (ea_t offset = get_struc_first_offset(struc_type); offset != BADADDR; offset = get_struc_next_offset(struc_type, offset)) { member_t * member_info = get_member(struc_type, offset); if (member_info != NULL) { if (offsets.count(member_info->soff) == 0) { qstring member_name = get_member_name2(member_info->id); asize_t member_size = get_member_size(member_info); if (member_name.find("vftbl_", 0) != -1) { tinfo_t tif; if (get_member_tinfo2(member_info, &tif)) { add_struc_member(struc, member_name.c_str(), member_info->soff, dwrdflag(), NULL, member_size); member_t * membr = get_member(struc, member_info->soff); if (membr != NULL) { set_member_tinfo2(struc, membr, 0, tif, SET_MEMTI_COMPATIBLE); } } } else { add_struc_member(struc, member_name.c_str(), member_info->soff, member_info->flag, NULL, member_size); } offsets.insert(member_info->soff); } } } } } } } } } return struct_type_id; }
tid_t idaapi merge_types(const qvector<qstring>& types_to_merge, const qstring& type_name) { tid_t struct_type_id = BADADDR; if (types_to_merge.empty()) return struct_type_id; std::set<ea_t> offsets; struct_type_id = add_struc(BADADDR, type_name.c_str()); if (struct_type_id == BADADDR) return struct_type_id; struc_t * struc = get_struc(struct_type_id); if (!struc) return struct_type_id; for (auto types_iter = types_to_merge.begin(), end = types_to_merge.end(); types_iter != end; ++types_iter) { struc_t * struc_type = get_struc(get_struc_id(types_iter->c_str())); if (!struc_type) continue; // enumerate members for ( ea_t offset = get_struc_first_offset(struc_type) ; offset != BADADDR ; offset = get_struc_next_offset(struc_type, offset)) { member_t * member_info = get_member(struc_type, offset); if (!member_info) continue; if (offsets.count(member_info->soff) == 0) { qstring member_name = get_member_name(member_info->id); asize_t member_size = get_member_size(member_info); if (member_name.find("vftbl_", 0) != -1) { tinfo_t tif; if (get_member_tinfo(&tif, member_info)) { add_struc_member(struc, member_name.c_str(), member_info->soff, dword_flag(), NULL, member_size); if (member_t * membr = get_member(struc, member_info->soff)) { set_member_tinfo(struc, membr, 0, tif, SET_MEMTI_COMPATIBLE); } } } else { add_struc_member(struc, member_name.c_str(), member_info->soff, member_info->flag, NULL, member_size); } offsets.insert(member_info->soff); } } } return struct_type_id; }
/* * === FUNCTION ====================================================================== * Name: map_over_members * Description: Calls the function referred to by pointer 'func' on each * member of an archive file. * * Pre: The file referred to by fd is open and has the necessary permissions * and read/write attributes to perform 'func' on its contents. * It's ugly, but it (mostly) works. Once I had gotten down the basics of iterating * over the archive file, I didn't want to have to repeat the logic separately for * append, print, and delete. That's why the function pointer is so darn hideous. I'm * sure there's better way to do this, but I haven't learned it yet --- obviously :). * ===================================================================================== */ static off_t map_over_members(int fd, void (*func)(int, struct ar_hdr *, char **, int, int), char **files, int count, int temp_fd) { struct ar_hdr hdr; off_t hdr_off, member_off, member_size; off_t ar_size = get_file_size(fd); /* First member header should be just * past archive magic header */ if((hdr_off = seek_past_armag(fd)) == -1) return -1; while((member_off = get_hdr(fd, hdr_off, SEEK_SET, &hdr)) != -1) { /* Get member file's size in preparation * for next jump */ member_size = get_member_size(&hdr); /* Here to help with diagnostics */ /* print_member_name(&hdr); printf("member offset: %lld\n", (long long)member_off); printf("archive size: %lld\n", (long long)ar_size); */ func(fd, &hdr, files, count, temp_fd); /* Make sure we're just before the member * file's contents */ lseek(fd, member_off, SEEK_SET); /* Align jump to even bit size */ member_size = member_size % 2 ? member_size + 1 : member_size; /* Set hdr_off to next header's offset; * exit loop if we're going to hit the * archive's boundary */ if((hdr_off = member_off + member_size) >= ar_size) break; } /* Return to the beginning of the archive */ return lseek(fd, 0, SEEK_SET); }
/* * === FUNCTION ====================================================================== * Name: retain_member * Description: Function to be passed to map_over_members from delete_files. * NULLs out a filename in 'files' and returns if there is a match to an * archive member. Otherwise, copies the ar_hdr struct and the subsequent * file data to the temporary file referred to by 'temp_fd'. * * Pre: 'temp_fd' refers to a file that exists and is writable; 'arch' refers * to a file that exists and is readable. * ===================================================================================== */ static void retain_member(int arch, struct ar_hdr *hdr, char **files, int count, int temp_fd) { char fname[SARFNAME+1]; get_hdr_attr(hdr, name_attr, fname, SARFNAME+1); int match = match_fnames(fname, files, count, strcmp); /* If there was no match, set * files to NULL so that delete_files * can tell user that no file was found. * Otherwise, return so that we don't copy * the file. */ if(match != -1) { files[match] = NULL; return; } /* Write header to temporary file */ if(write(temp_fd, hdr, SARFHDR) == -1) { fprintf(stderr, "error writing to file\n"); perror("write"); goto cleanup; } size_t to_write = get_member_size(hdr); write_to_arch(arch, temp_fd, to_write); return; cleanup: if(close(arch) == -1) { perror("close"); fprintf(stderr, "error closing archive file\n"); } if(close(temp_fd) == -1) { perror("close"); fprintf(stderr, "error closing temporary file\n"); } return; }
void get_struct_key(struc_t * struc_type, const VTBL_info_t& vtbl_info, qstring &file_entry_key, bool &filtered, const std::map<ea_t, VTBL_info_t>& vtbl_map) { qstring sub_key; qstring vtables_sub_key; int vftbales_num = 0; int members_count = 0; for ( ea_t offset = get_struc_first_offset(struc_type) ; offset != BADADDR ; offset = get_struc_next_offset(struc_type, offset)) { member_t * member_info = get_member(struc_type, offset); if (member_info != NULL) { qstring member_name = get_member_name(member_info->id); asize_t member_size = get_member_size(member_info); if (member_name.find("vftbl_", 0) != -1) { ea_t vtable_addr = 0; int i; if (qsscanf(member_name.c_str(), "vftbl_%d_%" FMT_EA "x", &i, &vtable_addr) > 0) { if (vtbl_map.count(vtable_addr) != 0) { vtables_sub_key.cat_sprnt("_%d", vtbl_map.at(vtable_addr).methods); } } vftbales_num ++; } sub_key.cat_sprnt("_%d", member_size); members_count ++; } } file_entry_key.sprnt("t_%d_%d", vtbl_info.methods, vftbales_num); file_entry_key += vtables_sub_key; file_entry_key += sub_key; if (members_count < STRUCT_DUMP_MIN_MEMBER_COUNT) filtered = true; }
std::vector<IDAStructure> GetStructsFromDb() { std::vector<IDAStructure> structures; constexpr size_t bufferSize = 256; std::array<char, bufferSize> buffer; for (auto i = get_first_struc_idx(); i != -1; i = get_next_struc_idx(i)) { IDAStructure newStruct; const struc_t* idaStruct = get_struc(get_struc_by_idx(i)); get_struc_name(idaStruct->id, buffer.data(), bufferSize); newStruct.m_name = std::string(buffer.data()); get_struc_cmt(idaStruct->id, true, buffer.data(), bufferSize); newStruct.m_comment = std::string(buffer.data()); newStruct.m_size = get_struc_size(idaStruct->id); msg("Struct %d = %s (%s) [%d bytes]\n", i, newStruct.m_name.c_str(), newStruct.m_comment.c_str(), newStruct.m_size); size_t offset = 0; member_t* idaStructMember = get_member(idaStruct, offset); while (idaStructMember != nullptr) { IDAStructure::Member newMember; get_member_fullname(idaStructMember->id, buffer.data(), bufferSize); newMember.m_name = std::string(buffer.data()); { tinfo_t typeInfo; get_member_tinfo2(idaStructMember, &typeInfo); qstring typeName; if (typeInfo.get_type_name(&typeName)) { newMember.m_type = std::string(typeName.c_str()); } else { newMember.m_type = "undefined"; } } get_member_cmt(idaStructMember->id, true, buffer.data(), bufferSize); newMember.m_comment = std::string(buffer.data()); newMember.m_size = get_member_size(idaStructMember); offset += newMember.m_size; msg(" %s {%s} (%s) [%d bytes]\n", newMember.m_name.c_str(), newMember.m_type.c_str(), newMember.m_comment.c_str(), newMember.m_size); newStruct.m_members.push_back(std::move(newMember)); idaStructMember = get_member(idaStruct, offset); } structures.push_back(std::move(newStruct)); } return std::move(structures); }
static void structprobe(Dwarf *dw, Dwarf_Die *structdie) { Dwarf_Die memdie; Dwarf_Word lastoff = 0, structsize; unsigned cline, members, nholes; size_t memsz, holesz; int x; (void)dw; cline = members = nholes = 0; memsz = holesz = 0; printf("struct %s {\n", dwarf_diename(structdie)); if (dwarf_aggregate_size(structdie, &structsize) == -1) dwarf_err(EX_DATAERR, "dwarf_aggregate_size"); if (dwarf_child(structdie, &memdie)) { printf("XXX ???\n"); exit(EX_DATAERR); } do { Dwarf_Attribute type_attr, base_type_attr; Dwarf_Die type_die, base_type_die; char type_name[128], mem_name[128], ptr_suffix[32] = { '\0' }; const char *type_tag = ""; const char *type = NULL; unsigned type_ptrlevel = 0; Dwarf_Word msize, off; if (dwarf_tag(&memdie) != DW_TAG_member) continue; members++; /* * TODO: Handle bitfield members. DW_AT_bit_offset, * DW_AT_bit_size; */ /* Chase down the type die of this member */ get_dwarf_attr(&memdie, DW_AT_type, &type_attr, &type_die); /* Member offset ... */ if (get_member_offset(&memdie, &off) == -1) dwarf_err(EX_DATAERR, "%s", dwarf_diename(&memdie)); /* Member size. */ if (get_member_size(&type_die, &msize) == -1) dwarf_err(EX_DATAERR, "get_member_size"); /* Format name; 'struct foo', 'enum bar', 'char **', etc. */ if (isstruct(dwarf_tag(&type_die))) { type_tag = "struct "; type = dwarf_diename(&type_die); } else if (dwarf_tag(&type_die) == DW_TAG_enumeration_type) { type_tag = "enum "; type = dwarf_diename(&type_die); } else if (dwarf_tag(&type_die) == DW_TAG_pointer_type) { unsigned i; do { if (dwarf_tag(&type_die) == DW_TAG_pointer_type) type_ptrlevel++; else if (isstruct(dwarf_tag(&type_die))) type_tag = "struct "; else if (dwarf_tag(&type_die) == DW_TAG_enumeration_type) type_tag = "enum "; else printf("!!! XXX ignored pointer qualifier TAG %#x\n", dwarf_tag(&type_die)); /* * Pointers to basic types still need some * work. Clang doesn't emit an AT_TYPE for * 'void*,' for example. */ if (!dwarf_hasattr(&type_die, DW_AT_type)) break; get_dwarf_attr(&type_die, DW_AT_type, &base_type_attr, &base_type_die); type_die = base_type_die; type_attr = base_type_attr; } while (dwarf_tag(&type_die) != DW_TAG_base_type); type = dwarf_diename(&type_die); if (type_ptrlevel > sizeof(ptr_suffix) - 2) type_ptrlevel = sizeof(ptr_suffix) - 2; ptr_suffix[0] = ' '; for (i = 1; i <= type_ptrlevel; i++) ptr_suffix[i] = '*'; ptr_suffix[i] = '\0'; } else type = dwarf_diename(&type_die); if (type == NULL) type = "<anonymous>"; snprintf(type_name, sizeof(type_name), "%s%s%s", type_tag, type, ptr_suffix); if (off != lastoff) { printf("\n\t/* XXX %ld bytes hole, try to pack */\n\n", off - lastoff); nholes++; holesz += (off - lastoff); } snprintf(mem_name, sizeof(mem_name), "%s;", dwarf_diename(&memdie)); printf("\t%-27s%-21s /* %5ld %5ld */\n", type_name, mem_name, (long)off, (long)msize); memsz += msize; lastoff = off + msize; if (lastoff / cachelinesize > cline) { int ago = lastoff % cachelinesize; cline = lastoff / cachelinesize; if (ago) printf("\t/* --- cacheline %u boundary (%ld " "bytes) was %d bytes ago --- */\n", cline, (long)cline * cachelinesize, ago); else printf("\t/* --- cacheline %u boundary (%ld " "bytes) --- */\n", cline, (long)cline * cachelinesize); } } while ((x = dwarf_siblingof(&memdie, &memdie)) == 0); if (x == -1) dwarf_err(EX_DATAERR, "dwarf_siblingof"); printf("\n\t/* size: %lu, cachelines: %u, members: %u */\n", structsize, cline + 1, members); printf("\t/* sum members: %zu, holes: %u, sum holes: %zu */\n", memsz, nholes, holesz); printf("\t/* last cacheline: %lu bytes */\n", lastoff % cachelinesize); printf("};\n"); }
void enum_members2(struc_t *st) { char buf[MAXSTR]; type_t type[MAXSTR] = {0}; int gap_cnt = 1; asize_t ofs = 0, gapend = BADADDR, gapstart = BADADDR; for (size_t i=0;i<st->memqty;i++) { member_t &mem = st->members[i]; // unexpected beginning of member? if (mem.soff != ofs) { // msg("gap detected @ %a!\n", ofs); gapstart = ofs; } if (gapstart != BADADDR) { gapend = mem.soff; msg("char pad%d[%d]\n", gap_cnt, gapend - gapstart); //msg("gap size=%a\n", gapend - gapstart); gapend = gapstart = BADADDR; gap_cnt++; } typeinfo_t mem_ti; retrieve_member_info(&mem, &mem_ti); // data type size of member asize_t dt_mem_size = get_data_type_size(mem.flag, &mem_ti); // member size asize_t mem_size = get_member_size(&mem); // get the member's name get_member_name(mem.id, buf, sizeof(buf)); char dtype[MAXSTR]; char arraystr[MAXSTR]; char typemod[10]; arraystr[0] = 0; typemod[0] = 0; if (isWord(mem.flag)) strcpy(dtype, "unsigned short"); else if (isDwrd(mem.flag)) strcpy(dtype, "unsigned long"); else if (isByte(mem.flag)) strcpy(dtype, "char"); else if (isStruct(mem.flag)) { struc_t *nested_st = get_sptr(&mem); get_struc_name(nested_st->id, dtype, MAXSTR); } else strcpy(dtype, "user_type"); if (isOff0(mem.flag)) { strcpy(typemod, "*"); } if (isEnum0(mem.flag)) { get_enum_name(mem_ti.ec.tid, dtype, sizeof(dtype)); } asize_t ar_size = mem_size / dt_mem_size; // an array? if (ar_size > 1) { sprintf(arraystr, "[%d]", ar_size); } char out[100]; sprintf(out, "%s " /* type */ "%s" /* typemodif */ "%s" /* varname */ "%s" /*array*/ ";", dtype, typemod, buf, arraystr); msg("%s\n", out); /* inline bool idaapi isByte (flags_t F) { return isData(F) && (F & DT_TYPE) == FF_BYTE; } inline bool idaapi isWord (flags_t F) { return isData(F) && (F & DT_TYPE) == FF_WORD; } inline bool idaapi isDwrd (flags_t F) { return isData(F) && (F & DT_TYPE) == FF_DWRD; } inline bool idaapi isQwrd (flags_t F) { return isData(F) && (F & DT_TYPE) == FF_QWRD; } inline bool idaapi isOwrd (flags_t F) { return isData(F) && (F & DT_TYPE) == FF_OWRD; } inline bool idaapi isTbyt (flags_t F) { return isData(F) && (F & DT_TYPE) == FF_TBYT; } inline bool idaapi isFloat (flags_t F) { return isData(F) && (F & DT_TYPE) == FF_FLOAT; } inline bool idaapi isDouble(flags_t F) { return isData(F) && (F & DT_TYPE) == FF_DOUBLE; } inline bool idaapi isPackReal(flags_t F) { return isData(F) && (F & DT_TYPE) == FF_PACKREAL; } inline bool idaapi isASCII (flags_t F) { return isData(F) && (F & DT_TYPE) == FF_ASCI; } inline bool idaapi isStruct(flags_t F) { return isData(F) && (F & DT_TYPE) == FF_STRU; } inline bool idaapi is3byte (flags_t F) { return isData(F) && (F & DT_TYPE) == FF_3BYTE; } */ /* msg("member[%d], name=%s; %a-%a ; id=%d; flags=%x type=%s dt_mem_size=%a mem_size=%a\n", i, buf, mem.soff, mem.eoff, mem.id, mem.flag, type, dt_mem_size, mem_size); */ // we expect next member to begin @ end of last member ofs = mem.eoff; } }