blob: 8d269299eec9bac657e7ff1c14414c3c85b91286 [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
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
#include "syzygy/pdbfind/pdbfind_app.h"
#include "base/files/file_util.h"
#include "syzygy/pe/find.h"
#include "syzygy/pe/pdb_info.h"
#include "syzygy/pe/pe_file.h"
namespace pdbfind {
namespace {
// The usage message must be kept in sync with the return codes below.
const int kSuccess = 0;
const int kError = 1;
const int kUnableToFindPdb = 2;
const int kMissingOrMalformedCodeViewRecord = 3;
const char kUsageFormatStr[] =
"Usage: %ls <input-image-path>\n"
" Searches for the PDB file matching the provided image. If successfully\n"
" found prints the absolute path to stdout and exit with a return code\n"
" of 0.\n"
" On any error (invalid command line, missing image file) exits with an\n"
" error message and exits with a return code of 1.\n"
" If the PDB file is not found but the image contains a CodeView record\n"
" outputs the expected path to the PDB and exits with a return code of\n"
" 2.\n"
" If the image does not contain a CodeView record or it is malformed\n"
" exits with a return code of 3.\n"
} // namespace
bool PdbFindApp::ParseCommandLine(const base::CommandLine* cmd_line) {
DCHECK(cmd_line != NULL);
if (cmd_line->HasSwitch("help"))
return Usage(cmd_line, "");
base::CommandLine::StringVector args = cmd_line->GetArgs();
if (args.size() == 0)
return Usage(cmd_line, "Must specify input-image-path.");
if (args.size() > 1)
return Usage(cmd_line, "Can specify only one input-image-path.");
input_image_path_ = base::FilePath(args[0]);
return true;
int PdbFindApp::Run() {
if (!base::PathExists(input_image_path_)) {
LOG(ERROR) << "File not found: " << input_image_path_.value();
return kError;
pe::PEFile pe_file;
if (!pe_file.Init(input_image_path_)) {
LOG(ERROR) << "Failed to parse PE file: " << input_image_path_.value();
return kError;
// Malformed or missing CodeView record.
pe::PdbInfo pdb_info;
if (!pdb_info.Init(pe_file))
return kMissingOrMalformedCodeViewRecord;
// Look for the matching PDB.
base::FilePath pdb_path;
if (!pe::FindPdbForModule(input_image_path_, &pdb_path)) {
LOG(ERROR) << "Error searching for PDB file.";
return kError;
// Not found? Then output the path where we expected to find it and indicate
// that it could not be found.
if (pdb_path.empty()) {
fprintf(out(), "%ls\n", pdb_info.pdb_file_name().value().c_str());
return kUnableToFindPdb;
fprintf(out(), "%ls\n", pdb_path.value().c_str());
return kSuccess;
bool PdbFindApp::Usage(const base::CommandLine* cmd_line,
const base::StringPiece& message) const {
if (!message.empty()) {
::fwrite(, 1, message.length(), err());
::fprintf(err(), "\n\n");
return false;
} // namespace pdbfind