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/pe/pdb_info.h"
16 :
17 : #include <string.h>
18 : #include "base/logging.h"
19 : #include "base/strings/utf_string_conversions.h"
20 : #include "syzygy/pe/pe_file.h"
21 :
22 : namespace pe {
23 :
24 E : PdbInfo::PdbInfo() : pdb_age_(0) {
25 E : ::memset(&signature_, 0, sizeof(signature_));
26 E : }
27 :
28 E : bool PdbInfo::Init(const CvInfoPdb70& cv_info_pdb) {
29 E : pdb_age_ = cv_info_pdb.pdb_age;
30 E : signature_ = cv_info_pdb.signature;
31 :
32 : // Convert the UTF-8 filename to a FilePath.
33 E : std::wstring pdb_path;
34 : if (!base::UTF8ToWide(cv_info_pdb.pdb_file_name,
35 : ::strlen(cv_info_pdb.pdb_file_name),
36 E : &pdb_path)) {
37 i : LOG(ERROR) << "base::UTF8ToWide failed.";
38 i : return false;
39 : }
40 E : pdb_file_name_ = base::FilePath(pdb_path);
41 :
42 E : return true;
43 E : }
44 :
45 E : bool PdbInfo::Init(const PEFile& pe_file) {
46 : const IMAGE_DATA_DIRECTORY& debug_data_dir =
47 : pe_file.nt_headers()->OptionalHeader.DataDirectory[
48 E : IMAGE_DIRECTORY_ENTRY_DEBUG];
49 :
50 : // Iterate through the debug directory entries.
51 E : const size_t kEntrySize = sizeof(IMAGE_DEBUG_DIRECTORY);
52 E : for (size_t i = 0; i < debug_data_dir.Size; i += kEntrySize) {
53 E : IMAGE_DEBUG_DIRECTORY debug_dir = {};
54 E : PEFile::RelativeAddress entry_addr(debug_data_dir.VirtualAddress + i);
55 E : if (!pe_file.ReadImage(entry_addr, &debug_dir, sizeof(debug_dir))) {
56 i : LOG(ERROR) << "Unable to read debug directory entry from PE file: "
57 : << pe_file.path().value();
58 i : return false;
59 : }
60 E : entry_addr += kEntrySize;
61 :
62 : // We're looking for a code-view (ie: PDB file) entry, so skip any others.
63 E : if (debug_dir.Type != IMAGE_DEBUG_TYPE_CODEVIEW)
64 i : continue;
65 :
66 E : if (debug_dir.SizeOfData < sizeof(CvInfoPdb70)) {
67 i : LOG(ERROR) << "CodeView debug entry too small.";
68 i : return false;
69 : }
70 :
71 : // Read the actual debug directory data.
72 E : PEFile::RelativeAddress pdb_info_addr(debug_dir.AddressOfRawData);
73 E : std::vector<uint8> buffer(debug_dir.SizeOfData);
74 E : if (!pe_file.ReadImage(pdb_info_addr, &buffer[0], buffer.size())) {
75 i : LOG(ERROR) << "Unable to read debug directory data from PE file: "
76 : << pe_file.path().value();
77 i : return false;
78 : }
79 :
80 E : CvInfoPdb70* cv_info = reinterpret_cast<CvInfoPdb70*>(&buffer[0]);
81 E : return Init(*cv_info);
82 i : }
83 :
84 E : LOG(INFO) << "PE file has no CodeView debug entry.";
85 E : return false;
86 E : }
87 :
88 E : bool PdbInfo::Init(const base::FilePath& pe_path) {
89 E : DCHECK(!pe_path.empty());
90 :
91 E : PEFile pe_file;
92 E : if (!pe_file.Init(pe_path)) {
93 E : LOG(ERROR) << "Unable to process PE file: " << pe_path.value();
94 E : return false;
95 : }
96 :
97 E : return Init(pe_file);
98 E : }
99 :
100 E : bool PdbInfo::IsConsistent(const pdb::PdbInfoHeader70& pdb_header) const {
101 : // The PDB age in the PDB file is bumped when e.g. source information
102 : // is added to the file, so we want the PdbInfoHeader to have an equal or
103 : // greater age that the image's.
104 : return pdb_age_ <= pdb_header.pdb_age &&
105 E : signature_ == pdb_header.signature;
106 E : }
107 :
108 : } // namespace pe
|