1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/pdbfind/pdbfind_app.h"
16 :
17 : #include "base/files/file_util.h"
18 : #include "syzygy/pe/find.h"
19 : #include "syzygy/pe/pdb_info.h"
20 : #include "syzygy/pe/pe_file.h"
21 :
22 : namespace pdbfind {
23 :
24 : namespace {
25 :
26 : // The usage message must be kept in sync with the return codes below.
27 : const int kSuccess = 0;
28 : const int kError = 1;
29 : const int kUnableToFindPdb = 2;
30 : const int kMissingOrMalformedCodeViewRecord = 3;
31 :
32 : const char kUsageFormatStr[] =
33 : "Usage: %ls <input-image-path>\n"
34 : "\n"
35 : " Searches for the PDB file matching the provided image. If successfully\n"
36 : " found prints the absolute path to stdout and exit with a return code\n"
37 : " of 0.\n"
38 : "\n"
39 : " On any error (invalid command line, missing image file) exits with an\n"
40 : " error message and exits with a return code of 1.\n"
41 : "\n"
42 : " If the PDB file is not found but the image contains a CodeView record\n"
43 : " outputs the expected path to the PDB and exits with a return code of\n"
44 : " 2.\n"
45 : "\n"
46 : " If the image does not contain a CodeView record or it is malformed\n"
47 : " exits with a return code of 3.\n"
48 : "\n";
49 :
50 : } // namespace
51 :
52 E : bool PdbFindApp::ParseCommandLine(const base::CommandLine* cmd_line) {
53 E : DCHECK(cmd_line != NULL);
54 :
55 E : if (cmd_line->HasSwitch("help"))
56 E : return Usage(cmd_line, "");
57 :
58 E : base::CommandLine::StringVector args = cmd_line->GetArgs();
59 E : if (args.size() == 0)
60 E : return Usage(cmd_line, "Must specify input-image-path.");
61 :
62 E : if (args.size() > 1)
63 E : return Usage(cmd_line, "Can specify only one input-image-path.");
64 :
65 E : input_image_path_ = base::FilePath(args[0]);
66 :
67 E : return true;
68 E : }
69 :
70 E : int PdbFindApp::Run() {
71 E : if (!base::PathExists(input_image_path_)) {
72 E : LOG(ERROR) << "File not found: " << input_image_path_.value();
73 E : return kError;
74 : }
75 :
76 E : pe::PEFile pe_file;
77 E : if (!pe_file.Init(input_image_path_)) {
78 i : LOG(ERROR) << "Failed to parse PE file: " << input_image_path_.value();
79 i : return kError;
80 : }
81 :
82 : // Malformed or missing CodeView record.
83 E : pe::PdbInfo pdb_info;
84 E : if (!pdb_info.Init(pe_file))
85 i : return kMissingOrMalformedCodeViewRecord;
86 :
87 : // Look for the matching PDB.
88 E : base::FilePath pdb_path;
89 E : if (!pe::FindPdbForModule(input_image_path_, &pdb_path)) {
90 i : LOG(ERROR) << "Error searching for PDB file.";
91 i : return kError;
92 : }
93 :
94 : // Not found? Then output the path where we expected to find it and indicate
95 : // that it could not be found.
96 E : if (pdb_path.empty()) {
97 i : fprintf(out(), "%ls\n", pdb_info.pdb_file_name().value().c_str());
98 i : return kUnableToFindPdb;
99 : }
100 :
101 E : fprintf(out(), "%ls\n", pdb_path.value().c_str());
102 E : return kSuccess;
103 E : }
104 :
105 : bool PdbFindApp::Usage(const base::CommandLine* cmd_line,
106 E : const base::StringPiece& message) const {
107 E : if (!message.empty()) {
108 E : ::fwrite(message.data(), 1, message.length(), err());
109 E : ::fprintf(err(), "\n\n");
110 : }
111 :
112 : ::fprintf(err(),
113 : kUsageFormatStr,
114 E : cmd_line->GetProgram().BaseName().value().c_str());
115 :
116 E : return false;
117 E : }
118 :
119 : } // namespace pdbfind
|