godot/tools/pe_bliss/pe_debug.cpp

866 lines
26 KiB
C++

/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* Permission is hereby granted, free of charge, to any person */
/* obtaining a copy of this software and associated documentation */
/* files (the "Software"), to deal in the Software without */
/* restriction, including without limitation the rights to use, */
/* copy, modify, merge, publish, distribute, sublicense, and/or */
/* sell copies of the Software, and to permit persons to whom the */
/* Software is furnished to do so, subject to the following conditions: */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include <string.h>
#include "pe_debug.h"
#include "utils.h"
namespace pe_bliss
{
using namespace pe_win;
//DEBUG
//Default constructor
debug_info::debug_info()
:characteristics_(0),
time_stamp_(0),
major_version_(0), minor_version_(0),
type_(0),
size_of_data_(0),
address_of_raw_data_(0),
pointer_to_raw_data_(0),
advanced_info_type_(advanced_info_none)
{}
//Constructor from data
debug_info::debug_info(const image_debug_directory& debug)
:characteristics_(debug.Characteristics),
time_stamp_(debug.TimeDateStamp),
major_version_(debug.MajorVersion), minor_version_(debug.MinorVersion),
type_(debug.Type),
size_of_data_(debug.SizeOfData),
address_of_raw_data_(debug.AddressOfRawData),
pointer_to_raw_data_(debug.PointerToRawData),
advanced_info_type_(advanced_info_none)
{}
//Returns debug characteristics
uint32_t debug_info::get_characteristics() const
{
return characteristics_;
}
//Returns debug datetimestamp
uint32_t debug_info::get_time_stamp() const
{
return time_stamp_;
}
//Returns major version
uint32_t debug_info::get_major_version() const
{
return major_version_;
}
//Returns minor version
uint32_t debug_info::get_minor_version() const
{
return minor_version_;
}
//Returns type of debug info (unchecked)
uint32_t debug_info::get_type_raw() const
{
return type_;
}
//Returns type of debug info from debug_info_type enumeration
debug_info::debug_info_type debug_info::get_type() const
{
//Determine debug type
switch(type_)
{
case image_debug_type_coff:
return debug_type_coff;
case image_debug_type_codeview:
return debug_type_codeview;
case image_debug_type_fpo:
return debug_type_fpo;
case image_debug_type_misc:
return debug_type_misc;
case image_debug_type_exception:
return debug_type_exception;
case image_debug_type_fixup:
return debug_type_fixup;
case image_debug_type_omap_to_src:
return debug_type_omap_to_src;
case image_debug_type_omap_from_src:
return debug_type_omap_from_src;
case image_debug_type_borland:
return debug_type_borland;
case image_debug_type_clsid:
return debug_type_clsid;
case image_debug_type_reserved10:
return debug_type_reserved10;
}
return debug_type_unknown;
}
//Returns size of debug data (internal, .pdb or other file doesn't count)
uint32_t debug_info::get_size_of_data() const
{
return size_of_data_;
}
//Returns RVA of debug info when mapped to memory or zero, if info is not mapped
uint32_t debug_info::get_rva_of_raw_data() const
{
return address_of_raw_data_;
}
//Returns raw file pointer to raw data
uint32_t debug_info::get_pointer_to_raw_data() const
{
return pointer_to_raw_data_;
}
//Copy constructor
debug_info::debug_info(const debug_info& info)
:characteristics_(info.characteristics_),
time_stamp_(info.time_stamp_),
major_version_(info.major_version_), minor_version_(info.minor_version_),
type_(info.type_),
size_of_data_(info.size_of_data_),
address_of_raw_data_(info.address_of_raw_data_),
pointer_to_raw_data_(info.pointer_to_raw_data_),
advanced_info_type_(info.advanced_info_type_)
{
copy_advanced_info(info);
}
//Copy assignment operator
debug_info& debug_info::operator=(const debug_info& info)
{
copy_advanced_info(info);
characteristics_ = info.characteristics_;
time_stamp_ = info.time_stamp_;
major_version_ = info.major_version_;
minor_version_ = info.minor_version_;
type_ = info.type_;
size_of_data_ = info.size_of_data_;
address_of_raw_data_ = info.address_of_raw_data_;
pointer_to_raw_data_ = info.pointer_to_raw_data_;
advanced_info_type_ = info.advanced_info_type_;
return *this;
}
//Default constructor
debug_info::advanced_info::advanced_info()
:adv_pdb_7_0_info(0) //Zero pointer to advanced data
{}
//Returns true if advanced debug info is present
bool debug_info::advanced_info::is_present() const
{
return adv_pdb_7_0_info != 0;
}
//Helper for advanced debug information copying
void debug_info::copy_advanced_info(const debug_info& info)
{
free_present_advanced_info();
switch(info.advanced_info_type_)
{
case advanced_info_pdb_7_0:
advanced_debug_info_.adv_pdb_7_0_info = new pdb_7_0_info(*info.advanced_debug_info_.adv_pdb_7_0_info);
break;
case advanced_info_pdb_2_0:
advanced_debug_info_.adv_pdb_2_0_info = new pdb_2_0_info(*info.advanced_debug_info_.adv_pdb_2_0_info);
break;
case advanced_info_misc:
advanced_debug_info_.adv_misc_info = new misc_debug_info(*info.advanced_debug_info_.adv_misc_info);
break;
case advanced_info_coff:
advanced_debug_info_.adv_coff_info = new coff_debug_info(*info.advanced_debug_info_.adv_coff_info);
break;
default:
break;
}
advanced_info_type_ = info.advanced_info_type_;
}
//Helper for clearing any present advanced debug information
void debug_info::free_present_advanced_info()
{
switch(advanced_info_type_)
{
case advanced_info_pdb_7_0:
delete advanced_debug_info_.adv_pdb_7_0_info;
break;
case advanced_info_pdb_2_0:
delete advanced_debug_info_.adv_pdb_2_0_info;
break;
case advanced_info_misc:
delete advanced_debug_info_.adv_misc_info;
break;
case advanced_info_coff:
delete advanced_debug_info_.adv_coff_info;
break;
default:
break;
}
advanced_debug_info_.adv_pdb_7_0_info = 0;
advanced_info_type_ = advanced_info_none;
}
//Destructor
debug_info::~debug_info()
{
free_present_advanced_info();
}
//Sets advanced debug information
void debug_info::set_advanced_debug_info(const pdb_7_0_info& info)
{
free_present_advanced_info();
advanced_debug_info_.adv_pdb_7_0_info = new pdb_7_0_info(info);
advanced_info_type_ = advanced_info_pdb_7_0;
}
void debug_info::set_advanced_debug_info(const pdb_2_0_info& info)
{
free_present_advanced_info();
advanced_debug_info_.adv_pdb_2_0_info = new pdb_2_0_info(info);
advanced_info_type_ = advanced_info_pdb_2_0;
}
void debug_info::set_advanced_debug_info(const misc_debug_info& info)
{
free_present_advanced_info();
advanced_debug_info_.adv_misc_info = new misc_debug_info(info);
advanced_info_type_ = advanced_info_misc;
}
void debug_info::set_advanced_debug_info(const coff_debug_info& info)
{
free_present_advanced_info();
advanced_debug_info_.adv_coff_info = new coff_debug_info(info);
advanced_info_type_ = advanced_info_coff;
}
//Returns advanced debug information type
debug_info::advanced_info_type debug_info::get_advanced_info_type() const
{
return advanced_info_type_;
}
//Returns advanced debug information or throws an exception,
//if requested information type is not contained by structure
template<>
const pdb_7_0_info debug_info::get_advanced_debug_info<pdb_7_0_info>() const
{
if(advanced_info_type_ != advanced_info_pdb_7_0)
throw pe_exception("Debug info structure does not contain PDB 7.0 data", pe_exception::advanced_debug_information_request_error);
return *advanced_debug_info_.adv_pdb_7_0_info;
}
template<>
const pdb_2_0_info debug_info::get_advanced_debug_info<pdb_2_0_info>() const
{
if(advanced_info_type_ != advanced_info_pdb_2_0)
throw pe_exception("Debug info structure does not contain PDB 2.0 data", pe_exception::advanced_debug_information_request_error);
return *advanced_debug_info_.adv_pdb_2_0_info;
}
template<>
const misc_debug_info debug_info::get_advanced_debug_info<misc_debug_info>() const
{
if(advanced_info_type_ != advanced_info_misc)
throw pe_exception("Debug info structure does not contain MISC data", pe_exception::advanced_debug_information_request_error);
return *advanced_debug_info_.adv_misc_info;
}
template<>
const coff_debug_info debug_info::get_advanced_debug_info<coff_debug_info>() const
{
if(advanced_info_type_ != advanced_info_coff)
throw pe_exception("Debug info structure does not contain COFF data", pe_exception::advanced_debug_information_request_error);
return *advanced_debug_info_.adv_coff_info;
}
//Sets advanced debug information type, if no advanced info structure available
void debug_info::set_advanced_info_type(advanced_info_type type)
{
free_present_advanced_info();
if(advanced_info_type_ >= advanced_info_codeview_4_0) //Don't set info type for those types, which have advanced info structures
advanced_info_type_ = type;
}
//Default constructor
pdb_7_0_info::pdb_7_0_info()
:age_(0)
{
memset(&guid_, 0, sizeof(guid_));
}
//Constructor from data
pdb_7_0_info::pdb_7_0_info(const CV_INFO_PDB70* info)
:age_(info->Age), guid_(info->Signature),
pdb_file_name_(reinterpret_cast<const char*>(info->PdbFileName)) //Must be checked before for null-termination
{}
//Returns debug PDB 7.0 structure GUID
const guid pdb_7_0_info::get_guid() const
{
return guid_;
}
//Returns age of build
uint32_t pdb_7_0_info::get_age() const
{
return age_;
}
//Returns PDB file name / path
const std::string& pdb_7_0_info::get_pdb_file_name() const
{
return pdb_file_name_;
}
//Default constructor
pdb_2_0_info::pdb_2_0_info()
:age_(0), signature_(0)
{}
//Constructor from data
pdb_2_0_info::pdb_2_0_info(const CV_INFO_PDB20* info)
:age_(info->Age), signature_(info->Signature),
pdb_file_name_(reinterpret_cast<const char*>(info->PdbFileName)) //Must be checked before for null-termination
{}
//Returns debug PDB 2.0 structure signature
uint32_t pdb_2_0_info::get_signature() const
{
return signature_;
}
//Returns age of build
uint32_t pdb_2_0_info::get_age() const
{
return age_;
}
//Returns PDB file name / path
const std::string& pdb_2_0_info::get_pdb_file_name() const
{
return pdb_file_name_;
}
//Default constructor
misc_debug_info::misc_debug_info()
:data_type_(0), unicode_(false)
{}
//Constructor from data
misc_debug_info::misc_debug_info(const image_debug_misc* info)
:data_type_(info->DataType), unicode_(info->Unicode ? true : false)
{
//IMAGE_DEBUG_MISC::Data must be checked before!
if(info->Unicode)
{
#ifdef PE_BLISS_WINDOWS
debug_data_unicode_ = std::wstring(reinterpret_cast<const wchar_t*>(info->Data), (info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */) / 2);
#else
debug_data_unicode_ = pe_utils::from_ucs2(u16string(reinterpret_cast<const unicode16_t*>(info->Data), (info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */) / 2));
#endif
pe_utils::strip_nullbytes(debug_data_unicode_); //Strip nullbytes in the end of string
}
else
{
debug_data_ansi_ = std::string(reinterpret_cast<const char*>(info->Data), info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */);
pe_utils::strip_nullbytes(debug_data_ansi_); //Strip nullbytes in the end of string
}
}
//Returns debug data type
uint32_t misc_debug_info::get_data_type() const
{
return data_type_;
}
//Returns true if data type is exe name
bool misc_debug_info::is_exe_name() const
{
return data_type_ == image_debug_misc_exename;
}
//Returns true if debug data is UNICODE
bool misc_debug_info::is_unicode() const
{
return unicode_;
}
//Returns debug data (ANSI)
const std::string& misc_debug_info::get_data_ansi() const
{
return debug_data_ansi_;
}
//Returns debug data (UNICODE)
const std::wstring& misc_debug_info::get_data_unicode() const
{
return debug_data_unicode_;
}
//Default constructor
coff_debug_info::coff_debug_info()
:number_of_symbols_(0),
lva_to_first_symbol_(0),
number_of_line_numbers_(0),
lva_to_first_line_number_(0),
rva_to_first_byte_of_code_(0),
rva_to_last_byte_of_code_(0),
rva_to_first_byte_of_data_(0),
rva_to_last_byte_of_data_(0)
{}
//Constructor from data
coff_debug_info::coff_debug_info(const image_coff_symbols_header* info)
:number_of_symbols_(info->NumberOfSymbols),
lva_to_first_symbol_(info->LvaToFirstSymbol),
number_of_line_numbers_(info->NumberOfLinenumbers),
lva_to_first_line_number_(info->LvaToFirstLinenumber),
rva_to_first_byte_of_code_(info->RvaToFirstByteOfCode),
rva_to_last_byte_of_code_(info->RvaToLastByteOfCode),
rva_to_first_byte_of_data_(info->RvaToFirstByteOfData),
rva_to_last_byte_of_data_(info->RvaToLastByteOfData)
{}
//Returns number of symbols
uint32_t coff_debug_info::get_number_of_symbols() const
{
return number_of_symbols_;
}
//Returns virtual address of the first symbol
uint32_t coff_debug_info::get_lva_to_first_symbol() const
{
return lva_to_first_symbol_;
}
//Returns number of line-number entries
uint32_t coff_debug_info::get_number_of_line_numbers() const
{
return number_of_line_numbers_;
}
//Returns virtual address of the first line-number entry
uint32_t coff_debug_info::get_lva_to_first_line_number() const
{
return lva_to_first_line_number_;
}
//Returns relative virtual address of the first byte of code
uint32_t coff_debug_info::get_rva_to_first_byte_of_code() const
{
return rva_to_first_byte_of_code_;
}
//Returns relative virtual address of the last byte of code
uint32_t coff_debug_info::get_rva_to_last_byte_of_code() const
{
return rva_to_last_byte_of_code_;
}
//Returns relative virtual address of the first byte of data
uint32_t coff_debug_info::get_rva_to_first_byte_of_data() const
{
return rva_to_first_byte_of_data_;
}
//Returns relative virtual address of the last byte of data
uint32_t coff_debug_info::get_rva_to_last_byte_of_data() const
{
return rva_to_last_byte_of_data_;
}
//Returns COFF symbols list
const coff_debug_info::coff_symbols_list& coff_debug_info::get_symbols() const
{
return symbols_;
}
//Adds COFF symbol
void coff_debug_info::add_symbol(const coff_symbol& sym)
{
symbols_.push_back(sym);
}
//Default constructor
coff_debug_info::coff_symbol::coff_symbol()
:storage_class_(0),
index_(0),
section_number_(0), rva_(0),
type_(0),
is_filename_(false)
{}
//Returns storage class
uint32_t coff_debug_info::coff_symbol::get_storage_class() const
{
return storage_class_;
}
//Returns symbol index
uint32_t coff_debug_info::coff_symbol::get_index() const
{
return index_;
}
//Returns section number
uint32_t coff_debug_info::coff_symbol::get_section_number() const
{
return section_number_;
}
//Returns RVA
uint32_t coff_debug_info::coff_symbol::get_rva() const
{
return rva_;
}
//Returns true if structure contains file name
bool coff_debug_info::coff_symbol::is_file() const
{
return is_filename_;
}
//Returns text data (symbol or file name)
const std::string& coff_debug_info::coff_symbol::get_symbol() const
{
return name_;
}
//Sets storage class
void coff_debug_info::coff_symbol::set_storage_class(uint32_t storage_class)
{
storage_class_ = storage_class;
}
//Sets symbol index
void coff_debug_info::coff_symbol::set_index(uint32_t index)
{
index_ = index;
}
//Sets section number
void coff_debug_info::coff_symbol::set_section_number(uint32_t section_number)
{
section_number_ = section_number;
}
//Sets RVA
void coff_debug_info::coff_symbol::set_rva(uint32_t rva)
{
rva_ = rva;
}
//Sets file name
void coff_debug_info::coff_symbol::set_file_name(const std::string& file_name)
{
name_ = file_name;
is_filename_ = true;
}
//Sets symbol name
void coff_debug_info::coff_symbol::set_symbol_name(const std::string& symbol_name)
{
name_ = symbol_name;
is_filename_ = false;
}
//Returns type
uint16_t coff_debug_info::coff_symbol::get_type() const
{
return type_;
}
//Sets type
void coff_debug_info::coff_symbol::set_type(uint16_t type)
{
type_ = type;
}
//Returns debug information list
const debug_info_list get_debug_information(const pe_base& pe)
{
debug_info_list ret;
//If there's no debug directory, return empty list
if(!pe.has_debug())
return ret;
//Check the length in bytes of the section containing debug directory
if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_debug), pe.get_directory_rva(image_directory_entry_debug), section_data_virtual, true)
< sizeof(image_debug_directory))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
unsigned long current_pos = pe.get_directory_rva(image_directory_entry_debug);
//First IMAGE_DEBUG_DIRECTORY table
image_debug_directory directory = pe.section_data_from_rva<image_debug_directory>(current_pos, section_data_virtual, true);
if(!pe_utils::is_sum_safe(pe.get_directory_rva(image_directory_entry_debug), pe.get_directory_size(image_directory_entry_debug)))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//Iterate over all IMAGE_DEBUG_DIRECTORY directories
while(directory.PointerToRawData
&& current_pos < pe.get_directory_rva(image_directory_entry_debug) + pe.get_directory_size(image_directory_entry_debug))
{
//Create debug information structure
debug_info info(directory);
//Find raw debug data
const pe_base::debug_data_list& debug_datas = pe.get_raw_debug_data_list();
pe_base::debug_data_list::const_iterator it = debug_datas.find(directory.PointerToRawData);
if(it != debug_datas.end()) //If it exists, we'll do some detailed debug info research
{
const std::string& debug_data = (*it).second;
switch(directory.Type)
{
case image_debug_type_coff:
{
//Check data length
if(debug_data.length() < sizeof(image_coff_symbols_header))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//Get coff header structure pointer
const image_coff_symbols_header* coff = reinterpret_cast<const image_coff_symbols_header*>(debug_data.data());
//Check possible overflows
if(coff->NumberOfSymbols >= pe_utils::max_dword / sizeof(image_symbol)
|| !pe_utils::is_sum_safe(coff->NumberOfSymbols * sizeof(image_symbol), coff->LvaToFirstSymbol))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//Check data length again
if(debug_data.length() < coff->NumberOfSymbols * sizeof(image_symbol) + coff->LvaToFirstSymbol)
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//Create COFF debug info structure
coff_debug_info coff_info(coff);
//Enumerate debug symbols data
for(uint32_t i = 0; i < coff->NumberOfSymbols; ++i)
{
//Safe sum (checked above)
const image_symbol* sym = reinterpret_cast<const image_symbol*>(debug_data.data() + i * sizeof(image_symbol) + coff->LvaToFirstSymbol);
coff_debug_info::coff_symbol symbol;
symbol.set_index(i); //Save symbol index
symbol.set_storage_class(sym->StorageClass); //Save storage class
symbol.set_type(sym->Type); //Save storage class
//Check data length again
if(!pe_utils::is_sum_safe(i, sym->NumberOfAuxSymbols)
|| (i + sym->NumberOfAuxSymbols) > coff->NumberOfSymbols
|| debug_data.length() < (i + 1) * sizeof(image_symbol) + coff->LvaToFirstSymbol + sym->NumberOfAuxSymbols * sizeof(image_symbol))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//If symbol is filename
if(sym->StorageClass == image_sym_class_file)
{
//Save file name, it is situated just after this IMAGE_SYMBOL structure
std::string file_name(reinterpret_cast<const char*>(debug_data.data() + (i + 1) * sizeof(image_symbol)), sym->NumberOfAuxSymbols * sizeof(image_symbol));
pe_utils::strip_nullbytes(file_name);
symbol.set_file_name(file_name);
//Save symbol info
coff_info.add_symbol(symbol);
//Move to next symbol
i += sym->NumberOfAuxSymbols;
continue;
}
//Dump some other symbols
if(((sym->StorageClass == image_sym_class_static)
&& (sym->NumberOfAuxSymbols == 0)
&& (sym->SectionNumber == 1))
||
((sym->StorageClass == image_sym_class_external)
&& ISFCN(sym->Type)
&& (sym->SectionNumber > 0))
)
{
//Save RVA and section number
symbol.set_section_number(sym->SectionNumber);
symbol.set_rva(sym->Value);
//If symbol has short name
if(sym->N.Name.Short)
{
//Copy and save symbol name
char name_buff[9];
memcpy(name_buff, sym->N.ShortName, 8);
name_buff[8] = '\0';
symbol.set_symbol_name(name_buff);
}
else
{
//Symbol has long name
//Check possible overflows
if(!pe_utils::is_sum_safe(coff->LvaToFirstSymbol + coff->NumberOfSymbols * sizeof(image_symbol), sym->N.Name.Long))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//Here we have an offset to the string table
uint32_t symbol_offset = coff->LvaToFirstSymbol + coff->NumberOfSymbols * sizeof(image_symbol) + sym->N.Name.Long;
//Check data length
if(debug_data.length() < symbol_offset)
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//Check symbol name for null-termination
if(!pe_utils::is_null_terminated(debug_data.data() + symbol_offset, debug_data.length() - symbol_offset))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//Save symbol name
symbol.set_symbol_name(debug_data.data() + symbol_offset);
}
//Save symbol info
coff_info.add_symbol(symbol);
//Move to next symbol
i += sym->NumberOfAuxSymbols;
continue;
}
}
info.set_advanced_debug_info(coff_info);
}
break;
case image_debug_type_codeview:
{
//Check data length
if(debug_data.length() < sizeof(OMFSignature*))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//Get POMFSignature structure pointer from the very beginning of debug data
const OMFSignature* sig = reinterpret_cast<const OMFSignature*>(debug_data.data());
if(!memcmp(sig->Signature, "RSDS", 4))
{
//Signature is "RSDS" - PDB 7.0
//Check data length
if(debug_data.length() < sizeof(CV_INFO_PDB70))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
const CV_INFO_PDB70* pdb_data = reinterpret_cast<const CV_INFO_PDB70*>(debug_data.data());
//Check PDB file name null-termination
if(!pe_utils::is_null_terminated(pdb_data->PdbFileName, debug_data.length() - (sizeof(CV_INFO_PDB70) - 1 /* BYTE of filename in structure */)))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
info.set_advanced_debug_info(pdb_7_0_info(pdb_data));
}
else if(!memcmp(sig->Signature, "NB10", 4))
{
//Signature is "NB10" - PDB 2.0
//Check data length
if(debug_data.length() < sizeof(CV_INFO_PDB20))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
const CV_INFO_PDB20* pdb_data = reinterpret_cast<const CV_INFO_PDB20*>(debug_data.data());
//Check PDB file name null-termination
if(!pe_utils::is_null_terminated(pdb_data->PdbFileName, debug_data.length() - (sizeof(CV_INFO_PDB20) - 1 /* BYTE of filename in structure */)))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
info.set_advanced_debug_info(pdb_2_0_info(pdb_data));
}
else if(!memcmp(sig->Signature, "NB09", 4))
{
//CodeView 4.0, no structures available
info.set_advanced_info_type(debug_info::advanced_info_codeview_4_0);
}
else if(!memcmp(sig->Signature, "NB11", 4))
{
//CodeView 5.0, no structures available
info.set_advanced_info_type(debug_info::advanced_info_codeview_5_0);
}
else if(!memcmp(sig->Signature, "NB05", 4))
{
//Other CodeView, no structures available
info.set_advanced_info_type(debug_info::advanced_info_codeview);
}
}
break;
case image_debug_type_misc:
{
//Check data length
if(debug_data.length() < sizeof(image_debug_misc))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//Get misc structure pointer
const image_debug_misc* misc_data = reinterpret_cast<const image_debug_misc*>(debug_data.data());
//Check misc data length
if(debug_data.length() < misc_data->Length /* Total length of record */)
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//Save advanced information
info.set_advanced_debug_info(misc_debug_info(misc_data));
}
break;
}
}
//Save debug information structure
ret.push_back(info);
//Check possible overflow
if(!pe_utils::is_sum_safe(current_pos, sizeof(image_debug_directory)))
throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
//Go to next debug entry
current_pos += sizeof(image_debug_directory);
directory = pe.section_data_from_rva<image_debug_directory>(current_pos, section_data_virtual, true);
}
return ret;
}
}