Last active
November 26, 2017 19:27
-
-
Save JustasMasiulis/12235a5c0478c9d9b158f63280bdeb72 to your computer and use it in GitHub Desktop.
get pdb download url from file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2017 Justas Masiulis | |
* | |
* 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 "pdb_extract.hpp" | |
#include <windows.h> | |
#include <vector> | |
#include <fstream> | |
#include <iomanip> | |
#include <sstream> | |
struct pdb_info_t { | |
unsigned long Signature; | |
GUID Guid; | |
unsigned long Age; | |
char PdbFileName[256]; | |
}; | |
std::vector<char> binary_file(const std::string& path) | |
{ | |
std::ifstream in; | |
in.unsetf(std::ios::skipws); | |
in.open(path, std::ios::binary); | |
if (!in.is_open()) | |
throw std::system_error(std::error_code(GetLastError(), std::system_category()) | |
, "pdbe: failed to open file"); | |
in.seekg(0, std::ios::end); | |
const auto size = in.tellg(); | |
in.seekg(0, std::ios::beg); | |
std::vector<char> vec(size); | |
in.read(vec.data(), size); | |
return vec; | |
} | |
template < class NT_HEADERS > | |
pdb_info_t parse(const std::vector<char>& file, const NT_HEADERS* const nt_headers) | |
{ | |
unsigned long debug_offset = 0; | |
unsigned long bytes_from_header = 0; | |
const auto opt_header = &nt_headers->OptionalHeader; | |
auto section_header = reinterpret_cast<const IMAGE_SECTION_HEADER*>(reinterpret_cast<std::uintptr_t>(opt_header) | |
+ nt_headers->FileHeader.SizeOfOptionalHeader); | |
const auto& debug_dir = opt_header->DataDirectory[6]; | |
if (debug_dir.Size == 0) | |
throw std::runtime_error("pdbe: debug data directory size was 0"); | |
for (auto num_sections = nt_headers->FileHeader.NumberOfSections | |
; num_sections; --num_sections, ++section_header) { | |
if (section_header->PointerToRawData != 0 | |
&& section_header->SizeOfRawData != 0 | |
&& bytes_from_header < section_header->PointerToRawData + section_header->SizeOfRawData) | |
bytes_from_header = section_header->PointerToRawData + section_header->SizeOfRawData; | |
if (section_header->VirtualAddress <= debug_dir.VirtualAddress | |
&& section_header->VirtualAddress + section_header->SizeOfRawData > debug_dir.VirtualAddress) | |
debug_offset = debug_dir.VirtualAddress - section_header->VirtualAddress + section_header->PointerToRawData; | |
} | |
const pdb_info_t* pdb_info = nullptr; | |
auto idd = reinterpret_cast<const IMAGE_DEBUG_DIRECTORY*>(file.data() + debug_offset); | |
for (auto dir_size = debug_dir.Size | |
; dir_size >= sizeof(IMAGE_DEBUG_DIRECTORY); dir_size -= sizeof(IMAGE_DEBUG_DIRECTORY), ++idd) { | |
if (idd->Type == 0x2) { | |
pdb_info = reinterpret_cast<const pdb_info_t*>(file.data() + idd->PointerToRawData); | |
break; | |
} | |
if (idd->PointerToRawData != 0 && idd->SizeOfData != 0 | |
&& bytes_from_header < idd->PointerToRawData + idd->SizeOfData) | |
bytes_from_header = idd->PointerToRawData + idd->SizeOfData; | |
} | |
if (!pdb_info) | |
throw std::runtime_error("pdbe: failed to find pdb information in file"); | |
return *pdb_info; | |
} | |
pdb_info_t pdb_info( const std::string& file_path ) | |
{ | |
{ | |
void* unused = nullptr; | |
bool b = Wow64DisableWow64FsRedirection(nullptr); | |
} | |
const auto file = binary_file(file_path); | |
const auto dos_header = reinterpret_cast<const IMAGE_DOS_HEADER*>(file.data()); | |
const auto nt_header = reinterpret_cast<const IMAGE_NT_HEADERS*>(file.data() + dos_header->e_lfanew); | |
const auto& file_header = nt_header->FileHeader; | |
pdb_info_t info; | |
if( file_header.Machine == 332 ) | |
info = parse(file, reinterpret_cast<const IMAGE_NT_HEADERS32*>(file.data() + dos_header->e_lfanew)); | |
else | |
info = parse(file, reinterpret_cast<const IMAGE_NT_HEADERS64*>(file.data() + dos_header->e_lfanew)); | |
return info; | |
} | |
std::string pdbe::extract_download_url( const std::string& file_path ) | |
{ | |
const auto info = pdb_info(file_path); | |
std::ostringstream iss; | |
iss.str(); | |
iss << "http://msdl.microsoft.com/download/symbols/" | |
<< info.PdbFileName << '/' | |
<< std::hex << std::uppercase << info.Guid.Data1 | |
<< info.Guid.Data2 | |
<< info.Guid.Data3; | |
for (int i = 0; i < 8; ++i) | |
iss << std::hex << std::uppercase << std::setfill('0') << std::setw(2) | |
<< unsigned(info.Guid.Data4[i]); | |
iss << std::dec << info.Age << '/' | |
<< info.PdbFileName; | |
return iss.str(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2017 Justas Masiulis | |
* | |
* 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. | |
*/ | |
#pragma once | |
#include <string> | |
namespace pdbe { | |
/// \return Download URL for pdb for the given file from microsoft symbol server. | |
/// \param file_path Path to the file to extract pdb download url from. | |
/// \note May throw std::system_error on failure to open file or runtime_error | |
/// if a parsing failure occurs. | |
std::string extract_download_url( const std::string& file_path ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment