src/HexRaysCodeXplorer/MSVCObjectFormatParser.cpp
/* Copyright (c) 2013-2020
REhints <info@rehints.com>
All rights reserved.
==============================================================================
This file is part of HexRaysCodeXplorer
HexRaysCodeXplorer is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
==============================================================================
*/
#include "MSVCObjectFormatParser.h"
#include "ObjectExplorer.h"
#include "Utility.h"
#if !defined (__LINUX__) && !defined (__MAC__)
#include <tchar.h>
#else
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
//---------------------------------------------------------------------------
// MSVC VTBL parsing
//
// Based on some impressions and code from ClassInformer plugin
// http://sourceforge.net/projects/classinformer/
//---------------------------------------------------------------------------
// Attempt to get information of and fix vftable at address
// Return TRUE along with info if valid vftable parsed at address
bool vftable::getTableInfo(ea_t ea, vtinfo &info)
{
ZeroMemory(&info, sizeof(vtinfo));
// Start of a vft should have an xref and a name (auto, or user, etc).
// Ideal flags 32bit: FF_DWRD, FF_0OFF, FF_REF, FF_NAME, FF_DATA, FF_IVL
//dumpFlags(ea);
flags_t flags = get_flags(ea);
if (has_xref(flags) && has_any_name(flags) && (isEa(flags) || is_unknown(flags)))
{
// Get raw (auto-generated mangled, or user named) vft name
//if (!get_name(BADADDR, ea, info.name, SIZESTR(info.name)))
// logmsg(DEBUG, EAFORMAT" ** vftable::getTableInfo(): failed to get raw name!\n", ea);
// Determine the vft's method count
ea_t start = info.start = ea;
while (TRUE)
{
// Should be an ea_t offset to a function here (could be unknown if dirty IDB)
// Ideal flags for 32bit: FF_DWRD, FF_0OFF, FF_REF, FF_NAME, FF_DATA, FF_IVL
//dumpFlags(ea);
flags_t indexFlags = get_flags(ea);
if (!(isEa(indexFlags) || is_unknown(indexFlags)))
{
break;
}
// Look at what this (assumed vftable index) points too
ea_t memberPtr = getEa(ea);
if (!(memberPtr && (memberPtr != BADADDR)))
{
// vft's often have a zero ea_t (NULL pointer?) following, fix it
if (memberPtr == 0)
fixEa(ea);
break;
}
// Should see code for a good vft method here, but it could be dirty
flags_t flags = get_flags(memberPtr);
if (!(is_code(flags) || is_unknown(flags)))
{
break;
}
if (ea != start)
{
// If we see a ref after first index it's probably the beginning of the next vft or something else
if (has_xref(indexFlags))
{
break;
}
// If we see a COL here it must be the start of another vftable
if (RTTI::_RTTICompleteObjectLocator::isValid(memberPtr))
{
break;
}
}
// As needed fix ea_t pointer, and, or, missing code and function def here
fixEa(ea);
fixFunction(memberPtr);
ea += sizeof(ea_t);
};
// Reached the presumed end of it
if ((info.methodCount = ((ea - start) / sizeof(ea_t))) > 0)
{
info.end = ea;
return true;
}
}
return false;
}
//---------------------------------------------------------------------------
// MSVC RTTI parsing
//
// Based on some impressions and code from ClassInformer plugin
// http://sourceforge.net/projects/classinformer/
//---------------------------------------------------------------------------
// Skip type_info tag for class/struct mangled name strings
#define SKIP_TD_TAG(_str) ((_str) + _countof(".?Ax") - 1)
// Class name list container
struct bcdInfo
{
qstring m_name;
UINT m_attribute;
RTTI::PMD m_pmd;
};
typedef qvector<bcdInfo> bcdList;
namespace RTTI
{
static bool getBCDInfo(ea_t col, bcdList &nameList, OUT UINT &numBaseClasses);
};
typedef std::map<ea_t, qstring> stringMap;
static stringMap stringCache;
static eaSet tdSet;
static eaSet chdSet;
static eaSet bcdSet;
void RTTI::freeWorkingData()
{
stringCache.clear();
tdSet.clear();
chdSet.clear();
bcdSet.clear();
}
// Return a short label indicating the CHD inheritance type by attributes
// TODO: Consider CHD_AMBIGUOUS?
static LPCSTR attributeLabel(UINT attributes)
{
if ((attributes & 3) == RTTI::CHD_MULTINH)
return((char *) "[MI]");
else
if ((attributes & 3) == RTTI::CHD_VIRTINH)
return((char *) "[VI]");
else
if ((attributes & 3) == (RTTI::CHD_MULTINH | RTTI::CHD_VIRTINH))
return((char *) "[MI VI]");
else
return((char *) "");
}
// Read a string from IDB at address
static size_t readIdaString(ea_t ea, qstring& rv)
{
// Return cached name if it exists
auto it = stringCache.find(ea);
if (it != stringCache.end())
{
rv = it->second;
return rv.length();
}
// Read string at ea if it exists
auto len = get_max_strlit_length(ea, STRTYPE_C, ALOPT_IGNHEADS);
if (!len)
return 0;
rv.reserve(len + 4);
if (get_strlit_contents(&rv, ea, len, STRTYPE_C) <= 0)
return 0;
// Cache it
stringCache[ea] = rv;
return rv.length();
}
// --------------------------- Type descriptor ---------------------------
// Get type name into a buffer
// type_info assumed to be valid
bool RTTI::type_info::getName(ea_t typeInfo, qstring& outName)
{
return readIdaString(typeInfo + offsetof(type_info, _M_d_name), outName) > 0;
}
// A valid type_info/TypeDescriptor at pointer?
bool RTTI::type_info::isValid(ea_t typeInfo)
{
// TRUE if we've already seen it
if (tdSet.find(typeInfo) != tdSet.end())
return true;
if (is_loaded(typeInfo))
{
// Verify what should be a vftable
ea_t ea = getEa(typeInfo + offsetof(type_info, vfptr));
if (is_loaded(ea))
{
// _M_data should be NULL statically
ea_t _M_data = BADADDR;
if (getVerifyEa((typeInfo + offsetof(type_info, _M_data)), _M_data))
{
if (_M_data == 0)
return(isTypeName(typeInfo + offsetof(type_info, _M_d_name)));
}
}
}
return false;
}
// Returns TRUE if known typename at address
bool RTTI::type_info::isTypeName(ea_t name)
{
// char demangledStr[MAXSTR];
// Should start with a period
if (get_byte(name) == '.')
{
// Read the rest of the possible name string
qstring buffer;
if (readIdaString(name, buffer) && buffer.length() > 3)
{
// Should be valid if it properly demangles
// if (demangle_name(demangledStr, (MAXSTR), buffer, (MT_MSCOMP | MNG_NODEFINIT)) >= 0)
//if (LPSTR s = __unDName(NULL, buffer + 1 /*skip the '.'*/, 0, malloc, free, (UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY)))
if ((buffer[0] == '.') && (buffer[1] == '?') && (buffer[2] == 'A') && (buffer[3] == 'V'))
{
// free(s);
return true;
}
}
}
return false;
}
// --------------------------- Complete Object Locator ---------------------------
// Return TRUE if address is a valid RTTI structure
bool RTTI::_RTTICompleteObjectLocator::isValid(ea_t col)
{
if (!is_loaded(col))
return false;
// Check signature
UINT signature = -1;
if (!getVerify32_t(col + ea_t(offsetof(_RTTICompleteObjectLocator, signature)), signature) || signature != 0)
return false;
// Check valid type_info
ea_t typeInfo = getEa(col + ea_t(offsetof(_RTTICompleteObjectLocator, typeDescriptor)));
if (!RTTI::type_info::isValid(typeInfo))
return false;
ea_t classDescriptor = getEa(col + ea_t(offsetof(_RTTICompleteObjectLocator, classDescriptor)));
return RTTI::_RTTIClassHierarchyDescriptor::isValid(classDescriptor, 0);
}
// Same as above but from an already validated type_info perspective
bool RTTI::_RTTICompleteObjectLocator::isValid2(ea_t col)
{
// 'signature' should be zero
UINT signature = -1;
if (!getVerify32_t((col + ea_t(offsetof(_RTTICompleteObjectLocator, signature))), signature) || signature != 0)
return false;
// Verify CHD
ea_t classDescriptor = getEa(col + offsetof(_RTTICompleteObjectLocator, classDescriptor));
if (classDescriptor && (classDescriptor != BADADDR))
return RTTI::_RTTIClassHierarchyDescriptor::isValid(classDescriptor, 0);
return false;
}
// --------------------------- Base Class Descriptor ---------------------------
// Return TRUE if address is a valid BCD
bool RTTI::_RTTIBaseClassDescriptor::isValid(ea_t bcd, ea_t colBase64)
{
// TRUE if we've already seen it
if (bcdSet.find(bcd) != bcdSet.end())
return true;
if (!is_loaded(bcd))
return false;
// Check attributes flags first
UINT attributes = -1;
if (getVerify32_t(bcd + ea_t(offsetof(_RTTIBaseClassDescriptor, attributes)), attributes))
{
// Valid flags are the lower byte only
if ((attributes & 0xFFFFFF00) == 0)
{
// Check for valid type_info
#ifndef __EA64__
return RTTI::type_info::isValid(getEa(bcd + ea_t(offsetof(_RTTIBaseClassDescriptor, typeDescriptor))));
#else
UINT tdOffset = get_32bit(bcd + ea_t(offsetof(_RTTIBaseClassDescriptor, typeDescriptor)));
ea_t typeInfo = colBase64 + (UINT64)tdOffset;
return RTTI::type_info::isValid(typeInfo);
#endif
}
}
return false;
}
// --------------------------- Class Hierarchy Descriptor ---------------------------
// Return true if address is a valid CHD structure
bool RTTI::_RTTIClassHierarchyDescriptor::isValid(ea_t chd, ea_t colBase64)
{
// TRUE if we've already seen it
if (chdSet.find(chd) != chdSet.end())
return true;
if (!is_loaded(chd))
return false;
// signature should be zero statically
UINT signature = -1;
if (!getVerify32_t((chd + offsetof(_RTTIClassHierarchyDescriptor, signature)), signature) || signature != 0)
return false;
// Check attributes flags
UINT attributes = -1;
if (!getVerify32_t(chd + offsetof(_RTTIClassHierarchyDescriptor, attributes), attributes))
return false;
// Valid flags are the lower nibble only
if (attributes & 0xFFFFFFF0)
return false;
// Should have at least one base class
UINT numBaseClasses = 0;
if (!getVerify32_t((chd + offsetof(_RTTIClassHierarchyDescriptor, numBaseClasses)), numBaseClasses))
return false;
if (!numBaseClasses)
return false;
// Check the first BCD entry
#ifndef __EA64__
ea_t baseClassArray = getEa(chd + offsetof(_RTTIClassHierarchyDescriptor, baseClassArray));
#else
UINT baseClassArrayOffset = get_32bit(chd + offsetof(_RTTIClassHierarchyDescriptor, baseClassArray));
ea_t baseClassArray = colBase64 + (UINT64)baseClassArrayOffset;
#endif
if (!is_loaded(baseClassArray))
return false;
#ifndef __EA64__
ea_t baseClassDescriptor = getEa(baseClassArray);
return RTTI::_RTTIBaseClassDescriptor::isValid(baseClassDescriptor, 0);
#else
ea_t baseClassDescriptor = colBase64 + (UINT64)get_32bit(baseClassArray);
return RTTI::_RTTIBaseClassDescriptor::isValid(baseClassDescriptor, colBase64);
#endif
return false;
}
// Get list of base class descriptor info
static bool RTTI::getBCDInfo(ea_t col, bcdList &list, OUT UINT &numBaseClasses)
{
numBaseClasses = 0;
#ifndef __EA64__
ea_t chd = getEa(col + offsetof(_RTTICompleteObjectLocator, classDescriptor));
#else
UINT cdOffset = get_32bit(col + offsetof(RTTI::_RTTICompleteObjectLocator, classDescriptor));
UINT objectLocator = get_32bit(col + offsetof(RTTI::_RTTICompleteObjectLocator, objectBase));
ea_t colBase = (col - (UINT64)objectLocator);
ea_t chd = (colBase + (UINT64)cdOffset);
#endif
if (!chd)
return false;
if (!(numBaseClasses = get_32bit(chd + offsetof(_RTTIClassHierarchyDescriptor, numBaseClasses))))
return true;
list.resize(numBaseClasses);
// Get pointer
#ifndef __EA64__
ea_t baseClassArray = getEa(chd + offsetof(_RTTIClassHierarchyDescriptor, baseClassArray));
#else
UINT bcaOffset = get_32bit(chd + offsetof(_RTTIClassHierarchyDescriptor, baseClassArray));
ea_t baseClassArray = (colBase + (UINT64)bcaOffset);
#endif
if (!::is_mapped(baseClassArray))
return false;
for (UINT i = 0; i < numBaseClasses; ++i, baseClassArray += sizeof(UINT)) // sizeof(ea_t)
{
#ifndef __EA64__
// Get next BCD
ea_t bcd = getEa(baseClassArray);
if (!is_mapped(bcd))
continue;
// Get type name
ea_t typeInfo = getEa(bcd + offsetof(_RTTIBaseClassDescriptor, typeDescriptor));
#else
UINT bcdOffset = get_32bit(baseClassArray);
ea_t bcd = (colBase + (UINT64)bcdOffset);
UINT tdOffset = get_32bit(bcd + offsetof(_RTTIBaseClassDescriptor, typeDescriptor));
ea_t typeInfo = (colBase + (UINT64)tdOffset);
#endif
if (!is_mapped(typeInfo))
continue;
bcdInfo& bi = list[i];
type_info::getName(typeInfo, bi.m_name);
// Add info to list
UINT mdisp = get_32bit(bcd + (offsetof(_RTTIBaseClassDescriptor, pmd) + offsetof(PMD, mdisp)));
UINT pdisp = get_32bit(bcd + (offsetof(_RTTIBaseClassDescriptor, pmd) + offsetof(PMD, pdisp)));
UINT vdisp = get_32bit(bcd + (offsetof(_RTTIBaseClassDescriptor, pmd) + offsetof(PMD, vdisp)));
// As signed int
bi.m_pmd.mdisp = *((PINT)&mdisp);
bi.m_pmd.pdisp = *((PINT)&pdisp);
bi.m_pmd.vdisp = *((PINT)&vdisp);
bi.m_attribute = get_32bit(bcd + offsetof(_RTTIBaseClassDescriptor, attributes));
}
return true;
}
// Process RTTI vftable info
bool RTTI::processVftable(ea_t vft, ea_t col, vftable::vtinfo &vi)
{
// Get vftable info
if (!vftable::getTableInfo(vft, vi))
return false;
bool sucess = false;
qstring plainName;
ea_t typeInfo = getEa(col + offsetof(_RTTICompleteObjectLocator, typeDescriptor));
ea_t chd = get_32bit(col + offsetof(_RTTICompleteObjectLocator, classDescriptor));
qstring colName;
type_info::getName(typeInfo, colName);
qstring demangledColName;
getPlainTypeName(colName, demangledColName);
UINT chdAttributes = get_32bit(chd + offsetof(_RTTIClassHierarchyDescriptor, attributes));
UINT offset = get_32bit(col + offsetof(_RTTICompleteObjectLocator, offset));
// Parse BCD info
bcdList list;
UINT numBaseClasses = 0;
if (!getBCDInfo(col, list, numBaseClasses))
return false;
bool isTopLevel = false;
qstring cmt;
// ======= Simple or no inheritance
if (offset == 0 && (chdAttributes & (CHD_MULTINH | CHD_VIRTINH)) == 0) {
// Build object hierarchy string
int placed = 0;
if (numBaseClasses > 1) {
// Parent
getPlainTypeName(list[0].m_name, plainName);
cmt.sprnt("%s%s: ", list[0].m_name.length() < 4 || list[0].m_name[3] == 'V' ? "" : "struct ", plainName.c_str());
placed++;
isTopLevel = list[0].m_name == colName;
// Child object hierarchy
for (UINT i = 1; i < numBaseClasses; i++)
{
// Append name
getPlainTypeName(list[i].m_name, plainName);
cmt.cat_sprnt("%s%s, ", list[i].m_name.length() < 4 || list[i].m_name[3] == 'V' ? "" : "struct ", plainName.c_str());
placed++;
}
// Nix the ending ',' for the last one
if (placed > 1)
cmt.remove(cmt.length() - 2, 2);
}
else {
// Plain, no inheritance object(s)
cmt.sprnt("%s%s", colName.length() < 4 || colName[3] == 'V' ? "" : "struct ", demangledColName.c_str());
isTopLevel = true;
}
vi.type_info = cmt;
return true;
}
// ======= Multiple inheritance, and, or, virtual inheritance hierarchies
bcdInfo *bi = nullptr;
int index = 0;
// Must be the top level object for the type
if (offset == 0)
{
//_ASSERT(strcmp(colName, list[0].m_name) == 0);
bi = &list[0];
isTopLevel = true;
}
else
{
// Get our object BCD level by matching COL offset to displacement
for (UINT i = 0; i < numBaseClasses; i++)
{
if (list[i].m_pmd.mdisp == offset)
{
bi = &list[i];
index = i;
break;
}
}
// If not found in list, use the first base object instead
if (!bi)
{
//logmsg(DEBUG, "** "EAFORMAT" MI COL class offset: %X(%d) not in BCD.\n", vft, offset, offset);
for (UINT i = 0; i < numBaseClasses; i++)
{
if (list[i].m_pmd.pdisp != -1)
{
bi = &list[i];
index = i;
break;
}
}
}
}
if (bi)
{
// Top object level layout
int placed = 0;
if (isTopLevel)
{
// Build hierarchy string starting with parent
getPlainTypeName(list[0].m_name, plainName);
cmt.sprnt("%s%s: ", list[0].m_name.length() < 4 || list[0].m_name[3] == 'V' ? "" : "struct ", plainName.c_str());
placed++;
// Concatenate forward child hierarchy
for (UINT i = 1; i < numBaseClasses; i++)
{
getPlainTypeName(list[i].m_name, plainName);
cmt.cat_sprnt("%s%s, ", list[i].m_name.length() < 4 || list[i].m_name[3] == 'V' ? "" : "struct ", plainName.c_str());
placed++;
}
if (placed > 1)
cmt.remove(cmt.length() - 2, 2);
}
else
{
// Combine COL and CHD name
// char combinedName[MAXSTR] = {};
// _snprintf(combinedName, _countof(combinedName) - 1, "%s6B%s@", SKIP_TD_TAG(colName), SKIP_TD_TAG(bi->m_name));
// Build hierarchy string starting with parent
getPlainTypeName(bi->m_name, plainName);
cmt.sprnt("%s%s: ", bi->m_name.length() < 4 || bi->m_name[3] == 'V' ? "" : "struct ", plainName.c_str());
placed++;
// Concatenate forward child hierarchy
if (++index < (int)numBaseClasses)
{
for (; index < (int)numBaseClasses; index++)
{
getPlainTypeName(list[index].m_name, plainName);
cmt.cat_sprnt("%s%s, ", list[index].m_name.length() < 4 || list[index].m_name[3] == 'V' ? "" : "struct ", plainName.c_str());
placed++;
}
if (placed > 1)
cmt.remove(cmt.length() - 2, 2);
}
}
// if (placed > 1)
// cmt += ';';
// cmt.cat_sprnt(" %s", attributeLabel(chdAttributes)); vi.type_info = cmt;
return true;
}
return false;
}
//---------------------------------------------------------------------------
// MSVC parsing core
//---------------------------------------------------------------------------
#if defined (__LINUX__) || defined (__MAC__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
namespace {
static eaList colList;
static std::map<ea_t, vftable::vtinfo> rtti_vftables;
} // anonymous
static void freeWorkingData() {
RTTI::freeWorkingData();
colList.clear();
rtti_vftables.clear();
}
// Return TRUE if address as a anterior comment
inline BOOL hasAnteriorComment(ea_t ea)
{
return(get_first_free_extra_cmtidx(ea, E_PREV) != E_PREV);
}
// Delete any anterior comment(s) at address if there is some
inline void killAnteriorComments(ea_t ea)
{
delete_extra_cmts(ea, E_PREV);
}
// Force a memory location to be DWORD size
void fixDword(ea_t ea)
{
if (!is_dword(get_flags(ea)))
{
setUnknown(ea, sizeof(DWORD));
create_dword(ea, sizeof(DWORD));
}
}
// Force memory location to be ea_t size
void fixEa(ea_t ea)
{
#ifndef __EA64__
if (!is_dword(get_flags(ea)))
#else
if (!is_qword(get_flags(ea)))
#endif
{
setUnknown(ea, sizeof(ea_t));
#ifndef __EA64__
create_dword(ea, sizeof(ea_t));
#else
create_qword(ea, sizeof(ea_t));
#endif
}
}
// Make address a function
void fixFunction(ea_t ea)
{
flags_t flags = get_flags(ea);
if (!is_code(flags))
{
create_insn(ea);
add_func(ea, BADADDR);
}
else
if (!is_func(flags))
add_func(ea, BADADDR);
}
// Get IDA EA bit value with verification
bool getVerifyEa(ea_t ea, ea_t &rValue)
{
// Location valid?
if (is_loaded(ea))
{
// Get ea_t value
rValue = getEa(ea);
return true;
}
return false;
}
// Undecorate to minimal class name
// typeid(T).name()
// http://en.wikipedia.org/wiki/Name_mangling
// http://en.wikipedia.org/wiki/Visual_C%2B%2B_name_mangling
// http://www.agner.org/optimize/calling_conventions.pdf
bool getPlainTypeName(const qstring& mangled, qstring& outStr)
{
outStr.clear();
// Use CRT function for type names
if (!mangled.empty() && mangled[0] == '.')
{
/*
__unDName(outStr, mangled + 1, MAXSTR, malloc, free, (UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY | UNDNAME_NO_ECSU));
if ((outStr[0] == 0) || (strcmp((mangled + 1), outStr) == 0))
{
logmsg(ERROR, "** getPlainClassName:__unDName() failed to unmangle! input: \"%s\"\n", mangled);
return(FALSE);
}
*/
outStr = mangled;
}
else
// IDA demangler for everything else
{
int result = demangle_name(&outStr, mangled.c_str(), (MT_MSCOMP | MNG_NODEFINIT));
if (result < 0)
return false;
// No inhibit flags will drop this
if (auto p = outStr.find("::`vftable'"))
outStr.resize(p);
}
return true;
}
// Scan segment for COLs
void idaapi scanSeg4Cols(segment_t *seg)
{
unsigned int found = 0;
if (seg->size() < sizeof(RTTI::_RTTICompleteObjectLocator))
return;
ea_t startEA = ((seg->start_ea + sizeof(UINT)) & ~((ea_t)(sizeof(UINT) - 1)));
ea_t endEA = (seg->end_ea - sizeof(RTTI::_RTTICompleteObjectLocator));
for (ea_t ptr = startEA; ptr < endEA;)
{
// TypeDescriptor address here?
ea_t ea = getEa(ptr);
if (ea >= 0x10000)
{
if (RTTI::type_info::isValid(ea))
{
// yes, a COL here?
ea_t col = (ptr - offsetof(RTTI::_RTTICompleteObjectLocator, typeDescriptor));
if (RTTI::_RTTICompleteObjectLocator::isValid2(col))
{
// yes
colList.push_front(col);
ptr += sizeof(RTTI::_RTTICompleteObjectLocator);
continue;
}
}
}
ptr += sizeof(unsigned int);
}
}
//
// Locate COL by descriptor list
void idaapi findCols()
{
// Usually in ".rdata" seg, try it first
std::set<segment_t *> segSet;
if (segment_t *seg = get_segm_by_name(".rdata"))
{
segSet.insert(seg);
scanSeg4Cols(seg);
}
// And ones named ".data"
int segCount = get_segm_qty();
for (int i = 0; i < segCount; ++i)
{
segment_t *seg = getnseg(i);
if (!seg)
continue;
if (seg->type != SEG_DATA)
continue;
if (segSet.find(seg) == segSet.end())
{
qstring name;
if (get_segm_name(&name, seg) <= 0)
continue;
if (name == ".data" || name == "_data")
{
segSet.insert(seg);
scanSeg4Cols(seg);
}
}
}
// If still none found, try any remaining data type segments
if (colList.empty())
{
for (int i = 0; i < segCount; i++)
{
segment_t *seg = getnseg(i);
if (!seg || seg->type != SEG_DATA)
continue;
if (segSet.find(seg) == segSet.end())
{
segSet.insert(seg);
scanSeg4Cols(seg);
}
}
}
return;
}
// Locate vftables
void idaapi scanSeg4Vftables(segment_t *seg, eaRefMap &colMap)
{
//UINT found = 0;
if (seg->size() <= sizeof(ea_t))
return;
ea_t startEA = ((seg->start_ea + sizeof(ea_t)) & ~((ea_t)(sizeof(ea_t) - 1)));
ea_t endEA = (seg->end_ea - sizeof(ea_t));
if (startEA >= endEA)
return;
eaRefMap::iterator colEnd = colMap.end();
for (ea_t ptr = startEA; ptr < endEA; ptr += sizeof(UINT))
{
// COL here?
ea_t ea = getEa(ptr);
eaRefMap::iterator it = colMap.find(ea);
if (it == colEnd)
continue;
// yes, look for vftable one ea_t below
ea_t vfptr = ptr + sizeof(ea_t);
ea_t method = getEa(vfptr);
// Points to code?
if (segment_t *s = getseg(method))
{
// yes,
if (s->type == SEG_CODE)
{
vftable::vtinfo vi;
if (RTTI::processVftable(vfptr, it->first, vi)) {
rtti_vftables[vfptr] = vi;
}
it->second++;
//found++;
}
}
}
}
//
void idaapi findVftables()
{
// COLs in a hash map for speed, plus match counts
eaRefMap colMap;
for (ea_t ea : colList)
colMap[ea] = 0;
// Usually in ".rdata", try first.
std::set<segment_t *> segSet;
if (segment_t *seg = get_segm_by_name(".rdata"))
{
segSet.insert(seg);
scanSeg4Vftables(seg, colMap);
}
// And ones named ".data"
int segCount = get_segm_qty();
for (int i = 0; i < segCount; i++)
{
segment_t *seg = getnseg(i);
if (!seg || seg->type != SEG_DATA)
continue;
if (segSet.find(seg) == segSet.end())
{
qstring name;
if (get_segm_name(&name, seg) > 0 && name == ".data")
{
segSet.insert(seg);
scanSeg4Vftables(seg, colMap);
}
}
}
// If still none found, try any remaining data type segments
if (colList.empty())
{
for (int i = 0; i < segCount; i++)
{
segment_t *seg = getnseg(i);
if (!seg || seg->type == SEG_DATA)
continue;
if (segSet.find(seg) == segSet.end())
{
segSet.insert(seg);
scanSeg4Vftables(seg, colMap);
}
}
}
// Rebuild 'colList' with any that were not located
if (!colList.empty())
{
colList.clear();
for (eaRefMap::const_iterator it = colMap.begin(), end = colMap.end(); it != end; ++it)
{
if (it->second == 0)
colList.push_front(it->first);
}
}
}
static void buildReconstructableTypes() {
}
MSVCObjectFormatParser::~MSVCObjectFormatParser()
{
}
void MSVCObjectFormatParser::get_rtti_info()
{
freeWorkingData();
findCols();
findVftables();
buildReconstructableTypes();
}
void MSVCObjectFormatParser::clear_info()
{
freeWorkingData();
}