blob: 5089ef04722c4bd93d8061cc90b5a0dc18d837f2 [file] [log] [blame]
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "syzygy/pdb/pdb_symbol_record.h"
#include <string>
#include "base/strings/stringprintf.h"
#include "syzygy/common/align.h"
#include "syzygy/experimental/pdb_dumper/pdb_dump_util.h"
#include "syzygy/experimental/pdb_dumper/pdb_leaf.h"
#include "syzygy/pdb/pdb_reader.h"
#include "syzygy/pdb/pdb_util.h"
#include "syzygy/pe/cvinfo_ext.h"
namespace pdb {
namespace cci = Microsoft_Cci_Pdb;
namespace {
template <typename SymbolType>
bool ReadSymbolAndName(PdbStream* stream,
uint16 len,
SymbolType* symbol_out,
std::string* name_out) {
DCHECK(stream != NULL);
DCHECK(len > 0);
DCHECK(symbol_out != NULL);
DCHECK(name_out != NULL);
// Note the zero-terminated name field must be the trailing field
// of the symbol.
size_t to_read = offsetof(SymbolType, name);
size_t bytes_read = 0;
if (!stream->ReadBytes(symbol_out, to_read, &bytes_read) ||
!ReadString(stream, name_out) ||
bytes_read != to_read) {
LOG(ERROR) << "Unable to read symbol record.";
return false;
}
return true;
}
// Return the string value associated with a symbol type.
const char* SymbolTypeName(uint16 symbol_type) {
switch (symbol_type) {
// Just return the name of the enum.
#define SYM_TYPE_NAME(sym_type, unused) \
case cci::sym_type: { \
return #sym_type; \
}
SYM_TYPE_CASE_TABLE(SYM_TYPE_NAME)
#undef SYM_TYPE_NAME
default :
return NULL;
}
}
// Dump a symbol record using RefSym2 struct to out.
bool DumpRefSym2(FILE* out, PdbStream* stream, uint16 len, uint8 indent_level) {
cci::RefSym2 symbol_info = {};
std::string symbol_name;
if (!ReadSymbolAndName(stream, len, &symbol_info, &symbol_name))
return false;
DumpIndentedText(out, indent_level, "Name: %s\n", symbol_name.c_str());
DumpIndentedText(out, indent_level, "SUC: %d\n", symbol_info.sumName);
DumpIndentedText(out, indent_level, "Offset: 0x%08X\n", symbol_info.ibSym);
DumpIndentedText(out, indent_level, "Module: %d\n", symbol_info.imod);
return true;
}
// Dump a symbol record using DatasSym32 struct to out.
bool DumpDatasSym32(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
cci::DatasSym32 symbol_info = {};
std::string symbol_name;
if (!ReadSymbolAndName(stream, len, &symbol_info, &symbol_name))
return false;
DumpIndentedText(out, indent_level, "Name: %s\n", symbol_name.c_str());
DumpIndentedText(out, indent_level, "Type index: %d\n", symbol_info.typind);
DumpIndentedText(out, indent_level, "Offset: 0x%08X\n", symbol_info.off);
DumpIndentedText(out, indent_level, "Segment: 0x%04X\n", symbol_info.seg);
return true;
}
bool DumpOemSymbol(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpVpathSym32(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpFrameProcSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpAnnotationSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
cci::AnnotationSym symbol_info = {};
size_t to_read = offsetof(cci::AnnotationSym, rgsz);
size_t bytes_read = 0;
if (!stream->ReadBytes(&symbol_info, to_read, &bytes_read) ||
bytes_read != to_read) {
LOG(ERROR) << "Unable to read symbol record.";
return false;
}
DumpIndentedText(out, indent_level, "Offset: 0x%08X\n", symbol_info.off);
DumpIndentedText(out, indent_level, "Segment: 0x%04X\n", symbol_info.seg);
DumpIndentedText(out, indent_level, "Number of strings: %d\n",
symbol_info.csz);
for (int i = 0; i < symbol_info.csz; ++i) {
std::string annotation;
if (!ReadString(stream, &annotation)) {
LOG(ERROR) << "Unable to read an annotation.";
return false;
}
DumpIndentedText(out, indent_level + 1, "%d: %s\n", i, annotation.c_str());
}
return true;
}
bool DumpManyTypRef(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpObjNameSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
DCHECK_NE(reinterpret_cast<FILE*>(NULL), out);
DCHECK_NE(reinterpret_cast<PdbStream*>(NULL), stream);
cci::ObjNameSym sym = {};
std::string name;
if (!ReadSymbolAndName(stream, len, &sym, &name))
return false;
DumpIndentedText(out, indent_level, "Signature: 0x%08X\n", sym.signature);
DumpIndentedText(out, indent_level, "Name : %s\n", name.c_str());
return true;
}
bool DumpThunkSym32(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpBlockSym32(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpWithSym32(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpLabelSym32(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpRegSym(FILE* out, PdbStream* stream, uint16 len, uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpConstSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
size_t to_read = offsetof(cci::ConstSym, name);
size_t bytes_read = 0;
cci::ConstSym symbol_info = {};
if (!stream->ReadBytes(&symbol_info, to_read, &bytes_read) ||
bytes_read != to_read) {
LOG(ERROR) << "Unable to read symbol record.";
return false;
}
// If the value field is less than LF_NUMERIC then the value data is the value
// of that symbol. Otherwise it refers to the value data and the actual value
// is located after this field.
size_t name_start_offset = 0;
const char* value_type = GetNumericLeafNameAndSize(symbol_info.value,
&name_start_offset);
if (value_type == NULL) {
DumpIndentedText(out, indent_level, "Value: 0x%04X\n", symbol_info.value);
} else {
DumpIndentedText(out, indent_level, "Value: type=%s, value=", value_type);
DumpNumericLeaf(out, symbol_info.value, stream);
::fprintf(out, "\n");
}
std::string symbol_name;
if (!ReadString(stream, &symbol_name)) {
LOG(ERROR) << "Unable to read the name of a symbol record.";
return false;
}
DumpIndentedText(out, indent_level, "Name: %s\n", symbol_name.c_str());
DumpIndentedText(out, indent_level, "Type index: 0x%08X\n",
symbol_info.typind);
return true;
}
bool DumpUdtSym(FILE* out, PdbStream* stream, uint16 len, uint8 indent_level) {
cci::UdtSym symbol_info = {};
std::string symbol_name;
if (!ReadSymbolAndName(stream, len, &symbol_info, &symbol_name))
return false;
DumpIndentedText(out, indent_level, "Name: %s\n", symbol_name.c_str());
DumpIndentedText(out, indent_level, "Type index: %d\n", symbol_info.typind);
return true;
}
bool DumpManyRegSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpBpRelSym32(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpProcSym32(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
DCHECK_NE(reinterpret_cast<FILE*>(NULL), out);
DCHECK_NE(reinterpret_cast<PdbStream*>(NULL), stream);
cci::ProcSym32 sym = {};
std::string name;
if (!ReadSymbolAndName(stream, len, &sym, &name))
return false;
DumpIndentedText(out, indent_level, "Parent : 0x%08X\n", sym.parent);
DumpIndentedText(out, indent_level, "End : 0x%08X\n", sym.end);
DumpIndentedText(out, indent_level, "Next : 0x%08X\n", sym.next);
DumpIndentedText(out, indent_level, "Length : %d\n", sym.len);
DumpIndentedText(out, indent_level, "Debug start: %d\n", sym.dbgStart);
DumpIndentedText(out, indent_level, "Debug end : %d\n", sym.dbgEnd);
DumpIndentedText(out, indent_level, "Type index : 0x%08X\n", sym.typind);
DumpIndentedText(out, indent_level, "Offset : 0x%08X\n", sym.off);
DumpIndentedText(out, indent_level, "Segment : %d\n", sym.seg);
DumpIndentedText(out, indent_level, "Flags:\n");
DumpIndentedText(out, indent_level + 1, "No FPO : %d\n",
(sym.flags & cci::CV_PFLAG_NOFPO) > 0);
DumpIndentedText(out, indent_level + 1, "Interrupt return : %d\n",
(sym.flags & cci::CV_PFLAG_INT) > 0);
DumpIndentedText(out, indent_level + 1, "Far return : %d\n",
(sym.flags & cci::CV_PFLAG_FAR) > 0);
DumpIndentedText(out, indent_level + 1, "No return : %d\n",
(sym.flags & cci::CV_PFLAG_NEVER) > 0);
DumpIndentedText(out, indent_level + 1, "Not reached : %d\n",
(sym.flags & cci::CV_PFLAG_NOTREACHED) > 0);
DumpIndentedText(out, indent_level + 1, "Custom call : %d\n",
(sym.flags & cci::CV_PFLAG_CUST_CALL) > 0);
DumpIndentedText(out, indent_level + 1, "No inline : %d\n",
(sym.flags & cci::CV_PFLAG_NOINLINE) > 0);
DumpIndentedText(out, indent_level + 1, "Optimized debug info: %d\n",
(sym.flags & cci::CV_PFLAG_OPTDBGINFO) > 0);
DumpIndentedText(out, indent_level, "Name: %s\n", name.c_str());
return true;
}
bool DumpRegRel32(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpThreadSym32(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
cci::ThreadSym32 symbol_info = {};
std::string symbol_name;
if (!ReadSymbolAndName(stream, len, &symbol_info, &symbol_name))
return false;
DumpIndentedText(out, indent_level, "Name: %s\n", symbol_name.c_str());
DumpIndentedText(out, indent_level, "Offset: %d\n", symbol_info.off);
DumpIndentedText(out, indent_level, "Segment: %d\n", symbol_info.seg);
DumpIndentedText(out, indent_level, "Type index: %d\n", symbol_info.typind);
return true;
}
bool DumpProcSymMips(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpCompileSymFlags(FILE* out,
const CompileSymFlags& flags,
uint8 indent_level) {
DCHECK_NE(reinterpret_cast<FILE*>(NULL), out);
DumpIndentedText(out, indent_level, "Flags:\n");
DumpIndentedText(out, indent_level + 1, "Language : %d\n",
flags.iLanguage);
DumpIndentedText(out, indent_level + 1, "Edit and continue: %d\n",
flags.fEC);
DumpIndentedText(out, indent_level + 1, "No debug info : %d\n",
flags.fNoDbgInfo);
DumpIndentedText(out, indent_level + 1, "LTCG : %d\n",
flags.fLTCG);
DumpIndentedText(out, indent_level + 1, "No data align : %d\n",
flags.fNoDataAlign);
DumpIndentedText(out, indent_level + 1, "Managed present : %d\n",
flags.fManagedPresent);
DumpIndentedText(out, indent_level + 1, "Security checks : %d\n",
flags.fSecurityChecks);
DumpIndentedText(out, indent_level + 1, "Hot patch : %d\n",
flags.fHotPatch);
return true;
}
// Dumps a CompileSym or a CompileSym2. Care must be taken to ensure that
// |CompileSymType| and |symbol_version| agree.
template <typename CompileSymType>
bool DumpCompileSymImpl(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level,
int symbol_version) {
DCHECK_NE(reinterpret_cast<FILE*>(NULL), out);
DCHECK_NE(reinterpret_cast<PdbStream*>(NULL), stream);
std::vector<char> data(len, 0);
size_t bytes_read = 0;
if (!stream->ReadBytes(data.data(), len, &bytes_read) ||
bytes_read != len) {
return false;
}
// Dump the flags. These are the same in both structures.
const CompileSymFlags* cf =
reinterpret_cast<const CompileSymFlags*>(data.data());
if (!DumpCompileSymFlags(out, *cf, indent_level))
return false;
// Dump the rest of the fields.
const CompileSymType* cs =
reinterpret_cast<const CompileSymType*>(data.data());
const CompileSym2* cs2 =
reinterpret_cast<const CompileSym2*>(data.data());
DumpIndentedText(out, indent_level, "Machine : %d\n",
cs->machine);
DumpIndentedText(out, indent_level, "Front-end major version: %d\n",
cs->verFEMajor);
DumpIndentedText(out, indent_level, "Front-end minor version: %d\n",
cs->verFEMinor);
DumpIndentedText(out, indent_level, "Front-end build number : %d\n",
cs->verFEBuild);
if (symbol_version == 2) {
DumpIndentedText(out, indent_level, "Front-end revision : %d\n",
cs2->verFERevision);
}
DumpIndentedText(out, indent_level, "Back-end major version : %d\n",
cs->verMajor);
DumpIndentedText(out, indent_level, "Back-end minor version : %d\n",
cs->verMinor);
DumpIndentedText(out, indent_level, "Back-end build number : %d\n",
cs->verBuild);
if (symbol_version == 2) {
DumpIndentedText(out, indent_level, "Back-end revision : %d\n",
cs2->verRevision);
}
size_t version_string = offsetof(CompileSymType, verSt);
// Dump the compiler version string.
const char* str = data.data() + version_string;
size_t max_len = data.size() - version_string;
size_t str_len = ::strnlen(str, max_len);
DumpIndentedText(out, indent_level, "Version string : %.*s\n",
str_len, str);
str += str_len + 1;
max_len -= str_len + 1;
// Dump any arguments.
if (max_len > 0 && str[0] != 0) {
DumpIndentedText(out, indent_level, "Version string arguments:\n");
size_t i = 0;
while (str[0] != NULL) {
str_len = ::strnlen(str, max_len);
DumpIndentedText(out, indent_level + 1, "%d: %.*s\n", i, str);
++i;
str += str_len + 1;
max_len -= str_len + 1;
}
}
return true;
}
bool DumpCompileSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
DCHECK_NE(reinterpret_cast<FILE*>(NULL), out);
DCHECK_NE(reinterpret_cast<PdbStream*>(NULL), stream);
if (!DumpCompileSymImpl<cci::CompileSym>(out, stream, len, indent_level, 1))
return false;
return true;
}
bool DumpCompileSym2(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
DCHECK_NE(reinterpret_cast<FILE*>(NULL), out);
DCHECK_NE(reinterpret_cast<PdbStream*>(NULL), stream);
if (!DumpCompileSymImpl<CompileSym2>(out, stream, len, indent_level, 2))
return false;
return true;
}
bool DumpManyRegSym2(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpProcSymIa64(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpSlotSym32(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpFrameRelSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpAttrRegSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpAttrSlotSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpAttrManyRegSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpAttrRegRel(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpAttrManyRegSym2(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpUnamespaceSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpManProcSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpTrampolineSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpSepCodSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpLocalSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpDefRangeSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpDefRangeSym2(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpSectionSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
cci::SectionSym section = {};
std::string section_name;
if (!ReadSymbolAndName(stream, len, &section, &section_name))
return false;
DumpIndentedText(out, indent_level, "isec: %d\n", section.isec);
DumpIndentedText(out, indent_level, "align: %d\n", section.align);
DumpIndentedText(out, indent_level, "bReserved: %d\n", section.bReserved);
DumpIndentedText(out, indent_level, "rva: 0x%08X\n", section.rva);
DumpIndentedText(out, indent_level, "cb: %d\n", section.cb);
DumpIndentedText(out, indent_level, "characteristics: 0x%08X\n",
section.characteristics);
DumpIndentedText(out, indent_level, "name: %s\n", section_name.c_str());
return true;
}
bool DumpCoffGroupSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
cci::CoffGroupSym coff_group = {};
std::string coff_group_name;
if (!ReadSymbolAndName(stream, len, &coff_group, &coff_group_name))
return false;
DumpIndentedText(out, indent_level, "cb: %d\n", coff_group.cb);
DumpIndentedText(out, indent_level, "characteristics: 0x%08X\n",
coff_group.characteristics);
DumpIndentedText(out, indent_level, "off: %d\n", coff_group.off);
DumpIndentedText(out, indent_level, "seg: %d\n", coff_group.seg);
DumpIndentedText(out, indent_level, "name: %s\n", coff_group_name.c_str());
return true;
}
bool DumpExportSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpCallsiteInfo(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
cci::CallsiteInfo symbol_info = {};
if (!stream->Read(&symbol_info, 1)) {
LOG(ERROR) << "Unable to read symbol record.";
return false;
}
DumpIndentedText(out, indent_level, "Offset: 0x%08X\n", symbol_info.off);
DumpIndentedText(out, indent_level, "Section index: 0x%04X\n",
symbol_info.ect);
DumpIndentedText(out, indent_level,
"Type index describing function signature: 0x%08X\n", symbol_info.typind);
return true;
}
bool DumpFrameCookie(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpDiscardedSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
// TODO(sebmarchand): Implement this function if we encounter this symbol.
return false;
}
bool DumpMSToolEnvV3(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
MSToolEnvV3 environment;
// Read the structure header.
size_t to_read = offsetof(MSToolEnvV3, key_values);
size_t bytes_read = 0;
if (!stream->ReadBytes(&environment, to_read, &bytes_read) ||
bytes_read != to_read ||
environment.leading_zero != 0) {
LOG(ERROR) << "Unable to read symbol record.";
return false;
}
DumpIndentedText(out, indent_level, "Tool Environment (V3):\n");
// Read an array of key-value pairs of string until key is empty.
// The remaining padding must be ignored.
std::string key;
std::string value;
while (true) {
if (!ReadString(stream, &key)) {
LOG(ERROR) << "Invalid MS Tool format.";
return false;
}
if (key.empty())
return true;
if (!ReadString(stream, &value)) {
LOG(ERROR) << "Invalid MS Tool format.";
return false;
}
DumpIndentedText(out, indent_level + 1, "%s: %s\n",
key.c_str(), value.c_str());
}
}
// Hexdump the data of the undeciphered symbol records.
bool DumpUnknown(FILE* out, PdbStream* stream, uint16 len, uint8 indent_level) {
if (len == 0)
return true;
DumpIndentedText(out, indent_level, "Unsupported symbol type.\n");
DumpIndentedText(out, indent_level + 1, "Length: %d\n", len);
DumpIndentedText(out, indent_level + 1, "Data:\n");
return DumpUnknownBlock(out, stream, len, indent_level + 2);
}
// TODO(chrisha|sebmarchand): Implement these! These are simple stubs so that
// this compiles cleanly.
bool DumpCompileSymCV2(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
return DumpUnknown(out, stream, len, indent_level);
}
bool DumpSearchSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
return DumpUnknown(out, stream, len, indent_level);
}
bool DumpEndArgSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
return DumpUnknown(out, stream, len, indent_level);
}
bool DumpReturnSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
return DumpUnknown(out, stream, len, indent_level);
}
bool DumpEntryThisSym(FILE* out,
PdbStream* stream,
uint16 len,
uint8 indent_level) {
return DumpUnknown(out, stream, len, indent_level);
}
} // namespace
void DumpSymbolRecords(FILE* out,
PdbStream* stream,
const SymbolRecordVector& sym_record_vector,
uint8 indent_level) {
DCHECK(stream != NULL);
SymbolRecordVector::const_iterator symbol_iter =
sym_record_vector.begin();
// Dump each symbol contained in the vector.
for (; symbol_iter != sym_record_vector.end(); ++symbol_iter) {
if (!stream->Seek(symbol_iter->start_position)) {
LOG(ERROR) << "Unable to seek to symbol record at position "
<< base::StringPrintf("0x%08X.", symbol_iter->start_position);
return;
}
const char* symbol_type_text = SymbolTypeName(symbol_iter->type);
if (symbol_type_text != NULL) {
DumpIndentedText(out,
indent_level,
"Symbol Type: 0x%04X %s (offset 0x%08X)\n",
symbol_iter->type,
symbol_type_text,
symbol_iter->start_position - 4);
} else {
DumpIndentedText(out,
indent_level,
"Unknown symbol Type: 0x%04X (offset 0x%08X)\n",
symbol_iter->type,
symbol_iter->start_position - 4);
}
bool success = false;
switch (symbol_iter->type) {
// Call a function to dump a specific (struct_type) kind of structure.
#define SYM_TYPE_DUMP(sym_type, struct_type) \
case cci::sym_type: { \
success = Dump ## struct_type(out, \
stream, \
symbol_iter->len, \
indent_level + 1); \
break; \
}
SYM_TYPE_CASE_TABLE(SYM_TYPE_DUMP)
#undef SYM_TYPE_DUMP
}
if (!success) {
// In case of failure we just dump the hex data of this symbol.
if (!stream->Seek(symbol_iter->start_position)) {
LOG(ERROR) << "Unable to seek to symbol record at position "
<< base::StringPrintf("0x%08X.",
symbol_iter->start_position);
return;
}
DumpUnknown(out, stream, symbol_iter->len, indent_level + 1);
}
stream->Seek(common::AlignUp(stream->pos(), 4));
if (stream->pos() != symbol_iter->start_position + symbol_iter->len) {
LOG(ERROR) << "Symbol record stream is not valid.";
return;
}
}
}
} // namespace pdb