Skip to content
This repository has been archived by the owner on Mar 18, 2020. It is now read-only.

Commit

Permalink
Use global symbol records to detect name mangling and parameter size,…
Browse files Browse the repository at this point in the history
… and when

it is the only symbol information available

Build a vector of FunctionRecords in getGlobalFunctions, parsing the
stdcall/fastcall decorations in to determine function parameter size and
checking if the function name is C++ mangled

When global symbols is the only symbol information available, just use that
(e.g. kernel32.pdb/17D8B8C647E14C1DAF9C6FC206AAAC512), otherwise merge the name
mangling and parameter size information into the function record from module
symbol information.

For compatibility with DIA dump_syms, only emit type information when the
function is C++

XXX: Generally, perhaps we should be doing something smarter about merging the
data we have when a symbol occurs multiple times with inconsistent data
  • Loading branch information
jon-turney committed Nov 2, 2014
1 parent 68ea67f commit 3bb706e
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 49 deletions.
129 changes: 83 additions & 46 deletions PDBParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ PDBParser::FunctionRecord& PDBParser::FunctionRecord::operator =(FunctionRecord&
std::swap(lineOffset, other.lineOffset);
std::swap(typeIndex, other.typeIndex);
std::swap(paramSize, other.paramSize);
std::swap(isMangledName, other.isMangledName);

return *this;
}
Expand Down Expand Up @@ -1022,7 +1023,7 @@ PDBParser::printBreakpadSymbols(FILE* of, const char* platform, FileMod* fileMod
throw std::runtime_error("Implement me...");

// Get functions from the global stream. These have mangled names that are useful.
Globals globals;
Functions globals;
getGlobalFunctions(header->symRecordStream, sections, globals);

Functions functions;
Expand All @@ -1031,6 +1032,31 @@ PDBParser::printBreakpadSymbols(FILE* of, const char* platform, FileMod* fileMod
getModuleFunctions(mod.info.data, functions);
}

if (modules.size() == 0)
{
// No modules had symbol information, so just use the functions
// found as global symbols
for (auto i = globals.begin(); i != globals.end(); i++)
{
functions.push_back(std::move(*i));
}
} else {
// Annotate module functions with paramSize and name mangled
// information from globals
// XXX: don't do this in a terrible O(n^2) fashion!
for (auto i = functions.begin(); i != functions.end(); i++)
{
for (auto j = globals.begin(); j != globals.end(); j++)
{
if (strcmp(i->name.data, j->name.data) == 0) {
i->isMangledName = j->isMangledName;
i->paramSize = j->paramSize;
break;
}
}
}
}

Concurrency::parallel_sort(functions.begin(), functions.end());

for (auto& mod : modules)
Expand Down Expand Up @@ -1078,10 +1104,7 @@ PDBParser::printBreakpadSymbols(FILE* of, const char* platform, FileMod* fileMod
func.offset += sections[func.segment - 1].VirtualAddress;
if (!updateParamSize(func, fpov2Data))
{
if (!updateParamSize(func, fpov1Data))
{
updateParamSize(func, globals);
}
updateParamSize(func, fpov1Data);
}
}

Expand Down Expand Up @@ -1294,7 +1317,7 @@ PDBParser::getModuleFunctions(const DBIModuleInfo* module, Functions& funcs)
}

void
PDBParser::getGlobalFunctions(uint16_t symRecStream, const SectionHeaders& headers, Globals& globals)
PDBParser::getGlobalFunctions(uint16_t symRecStream, const SectionHeaders& headers, Functions& globals)
{
DEBUG("symbol records stream %d\n", symRecStream);

Expand All @@ -1316,7 +1339,58 @@ PDBParser::getGlobalFunctions(uint16_t symRecStream, const SectionHeaders& heade
{
DEBUG("leaftype %04x, symbol type %d, address %08x (offset %08x, segment %04x), name %s\n", rec->leafType, rec->symType,
rec->offset + headers[rec->segment - 1].VirtualAddress, rec->offset, rec->segment, name.data);
globals.insert(std::make_pair(rec->offset + headers[rec->segment - 1].VirtualAddress, std::move(name)));

int paramSize = 0;
std::string trimmed_name = name.data;

// stdcall and fastcall functions have their param size embedded in the decorated name
if ((trimmed_name[0] == '_') || (trimmed_name[0] == '@'))
{
char prefix = trimmed_name[0];
trimmed_name.erase(0, 1);

const char* p = strrchr(trimmed_name.c_str(), '@');
if (p)
{
char* end;
long val = strtol(p + 1, &end, 10);
if (*end == '\0')
{
// stdcall function
paramSize = val;
// fastcall functions accept up to 8 bytes of parameters in registers
if (prefix == '@')
{
if (val > 8)
{
paramSize -= 8;
}
else
{
paramSize = 0;
}
}
}
trimmed_name.erase(p - trimmed_name.c_str());
}
}
// extract function name from C++ mangled name
else if (trimmed_name[0] == '?')
{
trimmed_name.erase(0, 1);
const char* p = strchr(trimmed_name.c_str(), '@');
if (p)
trimmed_name.erase(p - trimmed_name.c_str());
}

FunctionRecord f(std::move(DataPtr<char>(strdup(trimmed_name.c_str()),true)));
f.typeIndex = 0;
f.offset = rec->offset;
f.segment = rec->segment;
f.paramSize = paramSize;
f.isMangledName = (name.data[0] == '?');
globals.push_back(std::move(f));

}
}
else
Expand Down Expand Up @@ -1390,7 +1464,8 @@ PDBParser::printFunctions(Functions& funcs, const TypeMap& tm, FILE* of)

if (func.typeIndex)
{
stringizeType(func.typeIndex, str, tm, IsTopLevel);
if (func.isMangledName)
stringizeType(func.typeIndex, str, tm, IsTopLevel);

temp.assign(func.name.data);
std::string::size_type pos;
Expand Down Expand Up @@ -1475,44 +1550,6 @@ PDBParser::updateParamSize(FunctionRecord& func, std::map<std::pair<uint32_t, ui
return false;
}

bool
PDBParser::updateParamSize(FunctionRecord& func, Globals& globals)
{
auto g = globals.find(func.offset);
if (g != globals.end())
{
const char* name = g->second.data;
// stdcall and fastcall functions have their param size embedded in the decorated name
if (name[0] == '@' || name[0] == '_')
{
const char* p = strrchr(name, '@');
if (p && p != name)
{
char* end;
long val = strtol(p + 1, &end, 10);
if (*end == '\0')
{
func.paramSize = val;
// fastcall functions accept up to 8 bytes of parameters in registers
if (name[0] == '@')
{
if (val > 8)
{
func.paramSize -= 8;
}
else
{
func.paramSize = 0;
}
}
return true;
}
}
}
}
return false;
}

void
PDBParser::updateParamSize(FunctionRecord& func, const FPO_DATA& fpoData)
{
Expand Down
7 changes: 4 additions & 3 deletions PDBParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ class PDBParser
uint32_t lineOffset;
uint32_t typeIndex; // If this is non-zero, the function is a procedure, not a thunk (I don't know how to read thunk type info...)
uint32_t paramSize;
bool isMangledName;

FunctionRecord(uint32_t offset, uint32_t segment)
: segment(segment)
Expand All @@ -200,6 +201,7 @@ class PDBParser
, lineOffset(0)
, typeIndex(0)
, paramSize(0)
, isMangledName(false)
{}

bool operator <(const FunctionRecord& other) const
Expand Down Expand Up @@ -283,7 +285,6 @@ class PDBParser
typedef std::vector<FunctionRecord> Functions;
typedef std::unordered_map<uint32_t, TypeInfo> TypeMap;
typedef std::vector<SectionHeader> SectionHeaders;
typedef std::unordered_map<uint32_t, DataPtr<char>> Globals;
// If we decide to only support VC2013 we can use this.
//template<typename T>
//using FPODataMap = std::map<std::pair<uint32_t, uint32_t>, DataPtr<T>>;
Expand Down Expand Up @@ -318,14 +319,14 @@ class PDBParser
void getModuleFiles(const DBIModuleInfo* module, uint32_t& id, UniqueSrcFiles& unique, SrcFileIndex& fileIndex);
void printFiles(const SrcFileIndex& fileIndex, FILE* of);
void getModuleFunctions(const DBIModuleInfo* module, Functions& funcs);
void getGlobalFunctions(uint16_t symRecStream, const SectionHeaders& headers, Globals& globals);
void getGlobalFunctions(uint16_t symRecStream, const SectionHeaders& headers, Functions& globals);
void resolveFunctionLines(const DBIModuleInfo* module, Functions& funcs, const UniqueSrcFiles& unique, const SrcFileIndex& fileIndex);
void printFunctions(Functions& funcs, const TypeMap& tm, FILE* of);
template<typename T>
void readFPO(uint32_t fpoStream, std::map<std::pair<uint32_t, uint32_t>, DataPtr<T>>& fpoData);
template<typename T>
bool updateParamSize(FunctionRecord& func, std::map<std::pair<uint32_t, uint32_t>, DataPtr<T>>& fpoData);
bool updateParamSize(FunctionRecord& func, Globals& globals);
bool updateParamSize(FunctionRecord& func, Functions& globals);
void updateParamSize(FunctionRecord& func, const FPO_DATA& fpoData);
void updateParamSize(FunctionRecord& func, const FPO_DATA_V2& fpoData);
template<typename T>
Expand Down

0 comments on commit 3bb706e

Please sign in to comment.