Skip to content

Instantly share code, notes, and snippets.

@JustasMasiulis
Last active November 26, 2017 19:27
Show Gist options
  • Save JustasMasiulis/12235a5c0478c9d9b158f63280bdeb72 to your computer and use it in GitHub Desktop.
Save JustasMasiulis/12235a5c0478c9d9b158f63280bdeb72 to your computer and use it in GitHub Desktop.
get pdb download url from file
/*
* 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();
}
/*
* 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