| // 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, §ion, §ion_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 |