1 : // Copyright 2012 Google Inc.
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/dia_util.h"
16 :
17 : #include <diacreate.h>
18 :
19 : #include "base/logging.h"
20 : #include "base/win/scoped_bstr.h"
21 : #include "base/win/scoped_comptr.h"
22 : #include "sawbuck/common/com_utils.h"
23 :
24 : namespace pe {
25 :
26 : using base::win::ScopedBstr;
27 : using base::win::ScopedComPtr;
28 :
29 : #if _MSC_VER == 1500
30 : const wchar_t kDiaDllName[] = L"msdia90.dll";
31 : #elif _MSC_VER == 1600
32 : const wchar_t kDiaDllName[] = L"msdia100.dll";
33 : #else
34 : #error Cannot determine DIA DLL name.
35 : #endif
36 :
37 : const wchar_t kFixupDiaDebugStreamName[] = L"FIXUP";
38 : const wchar_t kOmapToDiaDebugStreamName[] = L"OMAPTO";
39 : const wchar_t kOmapFromDiaDebugStreamName[] = L"OMAPFROM";
40 :
41 E : bool CreateDiaSource(IDiaDataSource** created_source) {
42 E : DCHECK(created_source != NULL);
43 :
44 E : *created_source = NULL;
45 :
46 E : ScopedComPtr<IDiaDataSource> dia_source;
47 E : HRESULT hr1 = dia_source.CreateInstance(CLSID_DiaSource);
48 E : if (SUCCEEDED(hr1)) {
49 E : *created_source = dia_source.Detach();
50 E : return true;
51 : }
52 :
53 : HRESULT hr2 = NoRegCoCreate(kDiaDllName,
54 : CLSID_DiaSource,
55 : IID_IDiaDataSource,
56 E : reinterpret_cast<void**>(&dia_source));
57 E : if (SUCCEEDED(hr2)) {
58 E : *created_source = dia_source.Detach();
59 E : return true;
60 : }
61 :
62 i : LOG(ERROR) << "Failed to create DiaDataSource.";
63 i : LOG(ERROR) << " CreateInstance failed with: " << com::LogHr(hr1);
64 i : LOG(ERROR) << " NoRegCoCreate failed with: " << com::LogHr(hr2);
65 :
66 i : return false;
67 E : }
68 :
69 : bool CreateDiaSession(const FilePath& file,
70 : IDiaDataSource* dia_source,
71 E : IDiaSession** dia_session) {
72 E : DCHECK(dia_source != NULL);
73 E : DCHECK(dia_session != NULL);
74 :
75 E : *dia_session = NULL;
76 :
77 E : HRESULT hr = E_FAIL;
78 :
79 E : if (file.Extension() == L".pdb") {
80 E : hr = dia_source->loadDataFromPdb(file.value().c_str());
81 E : } else {
82 E : hr = dia_source->loadDataForExe(file.value().c_str(), NULL, NULL);
83 : }
84 :
85 E : if (FAILED(hr)) {
86 i : LOG(ERROR) << "Failed to load DIA data for \"" << file.value() << "\": "
87 : << com::LogHr(hr) << ".";
88 i : return false;
89 : }
90 :
91 E : ScopedComPtr<IDiaSession> session;
92 E : hr = dia_source->openSession(session.Receive());
93 E : if (FAILED(hr)) {
94 i : LOG(ERROR) << "Failed to open DIA session for \"" << file.value() << "\" : "
95 : << com::LogHr(hr) << ".";
96 i : return false;
97 : }
98 :
99 E : *dia_session = session.Detach();
100 :
101 E : return true;
102 E : }
103 :
104 : SearchResult FindDiaTable(const IID& iid,
105 : IDiaSession* dia_session,
106 E : void** out_table) {
107 E : DCHECK(dia_session != NULL);
108 E : DCHECK(out_table != NULL);
109 :
110 E : *out_table = NULL;
111 :
112 : // Get the table enumerator.
113 E : base::win::ScopedComPtr<IDiaEnumTables> enum_tables;
114 E : HRESULT hr = dia_session->getEnumTables(enum_tables.Receive());
115 E : if (FAILED(hr)) {
116 i : LOG(ERROR) << "Failed to get DIA table enumerator: "
117 : << com::LogHr(hr) << ".";
118 i : return kSearchErrored;
119 : }
120 :
121 : // Iterate through the tables.
122 E : while (true) {
123 E : base::win::ScopedComPtr<IDiaTable> table;
124 E : ULONG fetched = 0;
125 E : hr = enum_tables->Next(1, table.Receive(), &fetched);
126 E : if (FAILED(hr)) {
127 i : LOG(ERROR) << "Failed to get DIA table: "
128 : << com::LogHr(hr) << ".";
129 i : return kSearchErrored;
130 : }
131 E : if (fetched == 0)
132 i : break;
133 :
134 E : hr = table.QueryInterface(iid, out_table);
135 E : if (SUCCEEDED(hr))
136 E : return kSearchSucceeded;
137 E : }
138 :
139 : // The search completed, even though we didn't find what we were looking for.
140 i : return kSearchFailed;
141 E : }
142 :
143 : SearchResult FindDiaDebugStream(const wchar_t* name,
144 : IDiaSession* dia_session,
145 E : IDiaEnumDebugStreamData** dia_debug_stream) {
146 E : DCHECK(name != NULL);
147 E : DCHECK(dia_session != NULL);
148 E : DCHECK(dia_debug_stream != NULL);
149 :
150 E : *dia_debug_stream = NULL;
151 :
152 E : HRESULT hr = E_FAIL;
153 E : ScopedComPtr<IDiaEnumDebugStreams> debug_streams;
154 E : if (FAILED(hr = dia_session->getEnumDebugStreams(debug_streams.Receive()))) {
155 i : LOG(ERROR) << "Unable to get debug streams: " << com::LogHr(hr) << ".";
156 i : return kSearchErrored;
157 : }
158 :
159 : // Iterate through the debug streams.
160 E : while (true) {
161 E : ScopedComPtr<IDiaEnumDebugStreamData> debug_stream;
162 E : ULONG count = 0;
163 E : HRESULT hr = debug_streams->Next(1, debug_stream.Receive(), &count);
164 E : if (FAILED(hr) || (hr != S_FALSE && count != 1)) {
165 i : LOG(ERROR) << "Unable to load debug stream: "
166 : << com::LogHr(hr) << ".";
167 i : return kSearchErrored;
168 E : } else if (hr == S_FALSE) {
169 : // No more records.
170 E : break;
171 : }
172 :
173 E : ScopedBstr stream_name;
174 E : if (FAILED(hr = debug_stream->get_name(stream_name.Receive()))) {
175 i : LOG(ERROR) << "Unable to get debug stream name: "
176 : << com::LogHr(hr) << ".";
177 i : return kSearchErrored;
178 : }
179 :
180 : // Found the stream?
181 E : if (wcscmp(com::ToString(stream_name), name) == 0) {
182 E : *dia_debug_stream = debug_stream.Detach();
183 E : return kSearchSucceeded;
184 : }
185 E : }
186 :
187 E : return kSearchFailed;
188 E : }
189 :
190 : } // namespace pe
|