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/pe_relinker.h"
16 :
17 : #include "base/file_util.h"
18 : #include "syzygy/block_graph/orderers/original_orderer.h"
19 : #include "syzygy/core/zstream.h"
20 : #include "syzygy/pdb/pdb_byte_stream.h"
21 : #include "syzygy/pdb/pdb_file.h"
22 : #include "syzygy/pdb/pdb_reader.h"
23 : #include "syzygy/pdb/pdb_util.h"
24 : #include "syzygy/pdb/pdb_writer.h"
25 : #include "syzygy/pe/decomposer.h"
26 : #include "syzygy/pe/find.h"
27 : #include "syzygy/pe/image_layout_builder.h"
28 : #include "syzygy/pe/image_source_map.h"
29 : #include "syzygy/pe/metadata.h"
30 : #include "syzygy/pe/new_decomposer.h"
31 : #include "syzygy/pe/pdb_info.h"
32 : #include "syzygy/pe/pe_file_writer.h"
33 : #include "syzygy/pe/pe_utils.h"
34 : #include "syzygy/pe/serialization.h"
35 : #include "syzygy/pe/orderers/pe_orderer.h"
36 : #include "syzygy/pe/transforms/add_metadata_transform.h"
37 : #include "syzygy/pe/transforms/add_pdb_info_transform.h"
38 : #include "syzygy/pe/transforms/prepare_headers_transform.h"
39 :
40 : namespace pe {
41 :
42 : namespace {
43 :
44 : typedef block_graph::BlockGraphTransformInterface Transform;
45 : typedef block_graph::BlockGraphOrdererInterface Orderer;
46 :
47 : using block_graph::ApplyBlockGraphTransform;
48 : using block_graph::BlockGraph;
49 : using block_graph::OrderedBlockGraph;
50 : using core::RelativeAddress;
51 : using pdb::NameStreamMap;
52 : using pdb::PdbByteStream;
53 : using pdb::PdbFile;
54 : using pdb::PdbInfoHeader70;
55 : using pdb::PdbMutatorInterface;
56 : using pdb::PdbStream;
57 : using pdb::WritablePdbStream;
58 :
59 : // A utility class for wrapping a serialization OutStream around a
60 : // WritablePdbStream.
61 : // TODO(chrisha): We really need to centralize stream/buffer semantics in
62 : // a small set of clean interfaces, and make all input/output/parsing work
63 : // on these interfaces.
64 : class PdbOutStream : public core::OutStream {
65 : public:
66 E : explicit PdbOutStream(WritablePdbStream* pdb_stream)
67 : : pdb_stream_(pdb_stream) {
68 E : DCHECK(pdb_stream != NULL);
69 E : }
70 :
71 E : virtual ~PdbOutStream() { }
72 :
73 E : virtual bool Write(size_t length, const core::Byte* bytes) OVERRIDE {
74 E : return pdb_stream_->Write(length, bytes);
75 E : }
76 :
77 : private:
78 : scoped_refptr<WritablePdbStream> pdb_stream_;
79 : };
80 :
81 : void GetOmapRange(const std::vector<ImageLayout::SectionInfo>& sections,
82 E : RelativeAddressRange* range) {
83 E : DCHECK(range != NULL);
84 :
85 : // There need to be at least two sections, one containing something and the
86 : // other containing the relocs.
87 E : DCHECK_GT(sections.size(), 1u);
88 E : DCHECK_EQ(sections.back().name, std::string(kRelocSectionName));
89 :
90 : // For some reason, if we output OMAP entries for the headers (before the
91 : // first section), everything falls apart. Not outputting these allows the
92 : // unittests to pass. Also, we don't want to output OMAP information for
93 : // the relocs, as these are entirely different from image to image.
94 E : RelativeAddress start_of_image = sections.front().addr;
95 E : RelativeAddress end_of_image = sections.back().addr;
96 E : *range = RelativeAddressRange(start_of_image, end_of_image - start_of_image);
97 E : }
98 :
99 : // TODO(chrisha): Make this utility function part of orderer.h.
100 : bool ApplyOrderer(Orderer* orderer,
101 : OrderedBlockGraph* obg,
102 E : BlockGraph::Block* header_block) {
103 E : DCHECK(orderer != NULL);
104 E : DCHECK(obg != NULL);
105 E : DCHECK(header_block != NULL);
106 :
107 E : if (!orderer->OrderBlockGraph(obg, header_block)) {
108 E : LOG(ERROR) << "Orderer failed: " << orderer->name();
109 E : return false;
110 : }
111 :
112 E : return true;
113 E : }
114 :
115 : bool ApplyPdbMutator(PdbMutatorInterface* pdb_mutator,
116 E : PdbFile* pdb_file) {
117 E : DCHECK(pdb_mutator != NULL);
118 E : DCHECK(pdb_file != NULL);
119 :
120 E : if (!pdb_mutator->MutatePdb(pdb_file)) {
121 E : LOG(ERROR) << "PDB mutator failed: " << pdb_mutator->name();
122 E : return false;
123 : }
124 :
125 E : return true;
126 E : }
127 :
128 : // Initializes input_pdb_path, output_pdb_path, pe_file and guid. If the input
129 : // paths are unable to be found this will return false. If @p allow_overwrite is
130 : // false and output path or output_pdb_path will overwrite an existing file this
131 : // will return false. @p input_pdb_path may be left empty in which case it will
132 : // be automatically determined from the debug information in @p input_path; this
133 : // step may fail causing this to return false. @p output_pdb_path may also be
134 : // left empty in which case it will be inferred from input_pdb_path, being
135 : // placed alongside output_path.
136 : bool InitializePaths(const base::FilePath& input_path,
137 : const base::FilePath& output_path,
138 : bool allow_overwrite,
139 : base::FilePath* input_pdb_path,
140 E : base::FilePath* output_pdb_path) {
141 E : DCHECK(input_pdb_path != NULL);
142 E : DCHECK(output_pdb_path != NULL);
143 :
144 : // At a very minimum we have to specify input and outputs.
145 E : if (input_path.empty() || output_path.empty()) {
146 E : LOG(ERROR) << "input_path and output_path must be set!";
147 E : return false;
148 : }
149 :
150 E : if (!file_util::PathExists(input_path)) {
151 E : LOG(ERROR) << "Input module not found: " << input_path.value();
152 E : return false;
153 : }
154 :
155 : // No input PDB specified? Find it automagically.
156 E : if (input_pdb_path->empty()) {
157 E : LOG(INFO) << "Input PDB not specified, searching for it.";
158 : if (!FindPdbForModule(input_path, input_pdb_path) ||
159 E : input_pdb_path->empty()) {
160 i : LOG(ERROR) << "Unable to find PDB file for module: "
161 : << input_path.value();
162 i : return false;
163 : }
164 : }
165 :
166 E : if (!file_util::PathExists(*input_pdb_path)) {
167 i : LOG(ERROR) << "Input PDB not found: " << input_pdb_path->value();
168 i : return false;
169 : }
170 :
171 : // If no output PDB path is specified, infer one.
172 E : if (output_pdb_path->empty()) {
173 : // If the input and output DLLs have the same basename, default to writing
174 : // using the same PDB basename, but alongside the new module.
175 E : if (input_path.BaseName() == output_path.BaseName()) {
176 : *output_pdb_path = output_path.DirName().Append(
177 E : input_pdb_path->BaseName());
178 E : } else {
179 : // Otherwise, default to using the output basename with a PDB extension.
180 i : *output_pdb_path = output_path.ReplaceExtension(L"pdb");
181 : }
182 :
183 E : LOG(INFO) << "Using default output PDB path: " << output_pdb_path->value();
184 : }
185 :
186 : // Ensure we aren't about to overwrite anything we don't want to. We do this
187 : // early on so that we abort before decomposition, transformation, etc.
188 E : if (!allow_overwrite) {
189 E : bool terminate = false;
190 E : if (file_util::PathExists(output_path)) {
191 E : terminate = true;
192 E : LOG(ERROR) << "Output module path already exists.";
193 : }
194 E : if (file_util::PathExists(*output_pdb_path)) {
195 i : terminate = true;
196 i : LOG(ERROR) << "Output PDB path already exists.";
197 : }
198 E : if (terminate)
199 E : return false;
200 : }
201 :
202 E : return true;
203 E : }
204 :
205 : // Decomposes the module enclosed by the given PE file.
206 : bool Decompose(bool use_new_decomposer,
207 : bool parse_debug_info,
208 : const PEFile& pe_file,
209 : const base::FilePath& pdb_path,
210 : ImageLayout* image_layout,
211 E : BlockGraph::Block** dos_header_block) {
212 E : DCHECK(image_layout != NULL);
213 E : DCHECK(dos_header_block != NULL);
214 :
215 E : LOG(INFO) << "Decomposing module: " << pe_file.path().value();
216 :
217 E : BlockGraph* block_graph = image_layout->blocks.graph();
218 E : ImageLayout orig_image_layout(block_graph);
219 :
220 : // Decompose the input image.
221 E : if (use_new_decomposer) {
222 E : LOG(INFO) << "Using new decomposer for decomposition.";
223 E : if (!parse_debug_info)
224 E : LOG(INFO) << "Not parsing debug information.";
225 E : NewDecomposer decomposer(pe_file);
226 E : decomposer.set_pdb_path(pdb_path);
227 E : decomposer.set_parse_debug_info(parse_debug_info);
228 E : if (!decomposer.Decompose(&orig_image_layout)) {
229 i : LOG(ERROR) << "Unable to decompose module: " << pe_file.path().value();
230 i : return false;
231 : }
232 E : } else {
233 E : Decomposer decomposer(pe_file);
234 E : decomposer.set_pdb_path(pdb_path);
235 E : if (!decomposer.Decompose(&orig_image_layout)) {
236 i : LOG(ERROR) << "Unable to decompose module: " << pe_file.path().value();
237 i : return false;
238 : }
239 E : }
240 :
241 : // Make a copy of the image layout without padding. We don't want to carry
242 : // the padding through the toolchain.
243 E : LOG(INFO) << "Removing padding blocks.";
244 E : if (!pe::CopyImageLayoutWithoutPadding(orig_image_layout, image_layout)) {
245 i : LOG(ERROR) << "Failed to remove padding blocks.";
246 i : return false;
247 : }
248 :
249 : // Get the DOS header block.
250 : *dos_header_block =
251 : image_layout->blocks.GetBlockByAddress(
252 E : BlockGraph::RelativeAddress(0));
253 E : if (*dos_header_block == NULL) {
254 i : LOG(ERROR) << "Unable to find the DOS header block.";
255 i : return false;
256 : }
257 :
258 E : return true;
259 E : }
260 :
261 : bool ApplyTransforms(const base::FilePath& input_path,
262 : const base::FilePath& output_pdb_path,
263 : const GUID& guid,
264 : bool add_metadata,
265 : std::vector<Transform*>* transforms,
266 : BlockGraph* block_graph,
267 E : BlockGraph::Block* dos_header_block) {
268 E : DCHECK(transforms != NULL);
269 E : DCHECK(block_graph != NULL);
270 E : DCHECK(dos_header_block != NULL);
271 :
272 E : LOG(INFO) << "Transforming block graph.";
273 :
274 E : std::vector<Transform*> local_transforms(*transforms);
275 :
276 E : pe::transforms::AddMetadataTransform add_metadata_tx(input_path);
277 E : pe::transforms::AddPdbInfoTransform add_pdb_info_tx(output_pdb_path, 1, guid);
278 E : pe::transforms::PrepareHeadersTransform prep_headers_tx;
279 :
280 : // We first run the sequence of user requested transforms.
281 :
282 : // If we've been requested to we add metadata to the image.
283 E : if (add_metadata)
284 E : local_transforms.push_back(&add_metadata_tx);
285 :
286 : // Update the PDB information to point to the correct PDB file.
287 E : local_transforms.push_back(&add_pdb_info_tx);
288 :
289 : // Finally, run the prepare headers transform. This ensures that the header
290 : // block is properly sized to receive layout information post-ordering.
291 E : local_transforms.push_back(&prep_headers_tx);
292 :
293 : // Apply the transforms.
294 E : for (size_t i = 0; i < local_transforms.size(); ++i) {
295 E : LOG(INFO) << "Applying transform: " << local_transforms[i]->name() << ".";
296 : // ApplyBlockGraphTransform takes care of verbosely logging any failures.
297 : if (!ApplyBlockGraphTransform(local_transforms[i],
298 : block_graph,
299 E : dos_header_block)) {
300 E : return false;
301 : }
302 E : }
303 :
304 E : return true;
305 E : }
306 :
307 : bool ApplyOrderers(std::vector<Orderer*>* orderers,
308 : OrderedBlockGraph* obg,
309 E : BlockGraph::Block* dos_header_block) {
310 E : DCHECK(orderers != NULL);
311 E : DCHECK(obg != NULL);
312 E : DCHECK(dos_header_block != NULL);
313 :
314 E : LOG(INFO) << "Ordering block graph.";
315 :
316 E : std::vector<Orderer*> local_orderers(*orderers);
317 :
318 E : block_graph::orderers::OriginalOrderer orig_orderer;
319 E : pe::orderers::PEOrderer pe_orderer;
320 :
321 E : if (local_orderers.size() == 0) {
322 E : LOG(INFO) << "No orderers specified, using original orderer.";
323 E : local_orderers.push_back(&orig_orderer);
324 : }
325 :
326 E : local_orderers.push_back(&pe_orderer);
327 :
328 : // Apply the orderers.
329 E : for (size_t i = 0; i < local_orderers.size(); ++i) {
330 E : LOG(INFO) << "Applying orderer: " << local_orderers[i]->name();
331 E : if (!ApplyOrderer(local_orderers[i], obg, dos_header_block))
332 E : return false;
333 E : }
334 :
335 E : return true;
336 E : }
337 :
338 : bool ApplyPdbMutators(const std::vector<PdbMutatorInterface*>& pdb_mutators,
339 E : PdbFile* pdb_file) {
340 E : DCHECK(pdb_file != NULL);
341 :
342 E : LOG(INFO) << "Mutating PDB.";
343 :
344 : // Apply the orderers.
345 E : for (size_t i = 0; i < pdb_mutators.size(); ++i) {
346 E : LOG(INFO) << "Applying PDB mutator: " << pdb_mutators[i]->name();
347 E : if (!ApplyPdbMutator(pdb_mutators[i], pdb_file))
348 E : return false;
349 E : }
350 :
351 E : return true;
352 E : }
353 :
354 : // Lays out the image.
355 : bool BuildImageLayout(size_t padding,
356 : const OrderedBlockGraph& ordered_block_graph,
357 : BlockGraph::Block* dos_header_block,
358 E : ImageLayout* image_layout) {
359 E : DCHECK(dos_header_block != NULL);
360 E : DCHECK(image_layout != NULL);
361 :
362 E : LOG(INFO) << "Building image layout.";
363 :
364 E : ImageLayoutBuilder builder(image_layout);
365 E : builder.set_padding(padding);
366 E : if (!builder.LayoutImageHeaders(dos_header_block)) {
367 i : LOG(ERROR) << "ImageLayoutBuilder::LayoutImageHeaders failed.";
368 i : return false;
369 : }
370 :
371 E : if (!builder.LayoutOrderedBlockGraph(ordered_block_graph)) {
372 i : LOG(ERROR) << "ImageLayoutBuilder::LayoutOrderedBlockGraph failed.";
373 i : return false;
374 : }
375 :
376 E : LOG(INFO) << "Finalizing image layout.";
377 E : if (!builder.Finalize()) {
378 i : LOG(ERROR) << "ImageLayoutBuilder::Finalize failed.";
379 i : return false;
380 : }
381 :
382 E : return true;
383 E : }
384 :
385 : // Writes the image.
386 : bool WriteImage(const ImageLayout& image_layout,
387 E : const base::FilePath& output_path) {
388 E : PEFileWriter writer(image_layout);
389 :
390 E : LOG(INFO) << "Writing image: " << output_path.value();
391 E : if (!writer.WriteImage(output_path)) {
392 i : LOG(ERROR) << "Failed to write image \"" << output_path.value() << "\".";
393 i : return false;
394 : }
395 :
396 E : return true;
397 E : }
398 :
399 : void BuildOmapVectors(const RelativeAddressRange& input_range,
400 : const ImageLayout& output_image_layout,
401 : std::vector<OMAP>* omap_to,
402 E : std::vector<OMAP>* omap_from) {
403 E : DCHECK(omap_to != NULL);
404 E : DCHECK(omap_from != NULL);
405 :
406 E : LOG(INFO) << "Building OMAP vectors.";
407 :
408 : // Get the range of the output image, sans headers. This is required for
409 : // generating OMAP information.
410 E : RelativeAddressRange output_range;
411 E : GetOmapRange(output_image_layout.sections, &output_range);
412 :
413 E : ImageSourceMap reverse_map;
414 E : BuildImageSourceMap(output_image_layout, &reverse_map);
415 :
416 E : ImageSourceMap forward_map;
417 E : if (reverse_map.ComputeInverse(&forward_map) != 0) {
418 E : LOG(WARNING) << "OMAPFROM not unique (there exist repeated source ranges).";
419 : }
420 :
421 : // Build the two OMAP vectors.
422 E : BuildOmapVectorFromImageSourceMap(output_range, reverse_map, omap_to);
423 E : BuildOmapVectorFromImageSourceMap(input_range, forward_map, omap_from);
424 E : }
425 :
426 : // Updates the OMAP and GUID info in the given PDB file.
427 : bool SetOmapAndGuid(const RelativeAddressRange input_range,
428 : const ImageLayout& image_layout,
429 : const GUID& guid,
430 E : PdbFile* pdb_file) {
431 E : DCHECK(pdb_file != NULL);
432 :
433 E : LOG(INFO) << "Updating OMAP and GUID information.";
434 :
435 E : std::vector<OMAP> omap_to, omap_from;
436 E : BuildOmapVectors(input_range, image_layout, &omap_to, &omap_from);
437 :
438 E : if (!pdb::SetGuid(guid, pdb_file)) {
439 i : LOG(ERROR) << "Unable to set PDB GUID.";
440 i : return false;
441 : }
442 :
443 E : if (!pdb::SetOmapToStream(omap_to, pdb_file)) {
444 i : LOG(ERROR) << "Unable to set OMAP_TO.";
445 i : return false;
446 : }
447 :
448 E : if (!pdb::SetOmapFromStream(omap_from, pdb_file)) {
449 i : LOG(ERROR) << "Unable to set OMAP_FROM.";
450 i : return false;
451 : }
452 :
453 E : return true;
454 E : }
455 :
456 : bool WritePdbFile(const base::FilePath& output_pdb_path,
457 E : const PdbFile& pdb_file) {
458 E : LOG(INFO) << "Writing PDB file: " << output_pdb_path.value();
459 :
460 E : base::FilePath temp_pdb;
461 : if (!file_util::CreateTemporaryFileInDir(output_pdb_path.DirName(),
462 E : &temp_pdb)) {
463 i : LOG(ERROR) << "Unable to create temporary PDB file.";
464 i : return false;
465 : }
466 :
467 E : pdb::PdbWriter pdb_writer;
468 E : if (!pdb_writer.Write(temp_pdb, pdb_file)) {
469 i : LOG(ERROR) << "Failed to write temporary PDB file to \""
470 : << temp_pdb.value() << "\".";
471 : }
472 :
473 E : if (!file_util::ReplaceFile(temp_pdb, output_pdb_path)) {
474 i : LOG(ERROR) << "Unable to move temporary PDB file to \""
475 : << output_pdb_path.value() << "\".";
476 i : file_util::Delete(temp_pdb, false);
477 i : return false;
478 : }
479 :
480 E : return true;
481 E : }
482 :
483 : // Get a specific named stream if it already exists, otherwise create one.
484 : // @param stream_name The name of the stream.
485 : // @param name_stream_map The map containing the names of the streams in the
486 : // PDB. If the stream doesn't already exist the map will be augmented with
487 : // another entry.
488 : // @param pdb_file The PDB file to which the stream will be added.
489 : // @param replace_stream If true, will cause a new stream to be created even if
490 : // another one already existed.
491 : // @return a pointer to the PDB stream on success, NULL on failure.
492 : PdbStream* GetOrCreatePdbStreamByName(const char* stream_name,
493 : bool replace_stream,
494 : NameStreamMap* name_stream_map,
495 E : PdbFile* pdb_file) {
496 E : DCHECK(name_stream_map != NULL);
497 E : DCHECK(pdb_file != NULL);
498 E : scoped_refptr<PdbStream> stream;
499 :
500 E : NameStreamMap::const_iterator name_it = name_stream_map->find(stream_name);
501 E : if (name_it != name_stream_map->end()) {
502 : // Replace the existing stream by a brand-new one if it's required.
503 i : if (replace_stream) {
504 i : stream = new PdbByteStream();
505 i : pdb_file->ReplaceStream(name_it->second, stream.get());
506 i : } else {
507 i : if (!pdb::EnsureStreamWritable(name_it->second, pdb_file)) {
508 i : LOG(ERROR) << "Failed to make " << stream_name << " stream writable.";
509 i : return NULL;
510 : }
511 i : stream = pdb_file->GetStream(name_it->second);
512 : }
513 i : } else {
514 E : stream = new PdbByteStream();
515 E : uint32 index = pdb_file->AppendStream(stream.get());
516 E : (*name_stream_map)[stream_name] = index;
517 : }
518 :
519 E : return stream.get();
520 E : }
521 :
522 : // This updates or creates the Syzygy history stream, appending the metadata
523 : // describing this module and transform. The history stream consists of
524 : // a named PDB stream with the name /Syzygy/History. It consists of:
525 : //
526 : // uint32 version
527 : // uint32 history_length
528 : // serialized pe::Metadata 0
529 : // ...
530 : // serialized pe::Metadata history_length - 1
531 : //
532 : // If the format is changed, be sure to update this documentation and
533 : // pdb::kSyzygyHistoryStreamVersion (in pdb_constants.h).
534 : bool WriteSyzygyHistoryStream(const base::FilePath& input_path,
535 : NameStreamMap* name_stream_map,
536 E : PdbFile* pdb_file) {
537 : // Get the history stream.
538 : scoped_refptr<PdbStream> history_reader =
539 : GetOrCreatePdbStreamByName(pdb::kSyzygyHistoryStreamName,
540 : false,
541 : name_stream_map,
542 E : pdb_file);
543 :
544 E : if (history_reader == NULL) {
545 i : LOG(ERROR) << "Failed to get the history stream.";
546 i : return false;
547 : }
548 :
549 : scoped_refptr<WritablePdbStream> history_writer =
550 E : history_reader->GetWritablePdbStream();
551 E : DCHECK(history_writer.get() != NULL);
552 :
553 : // Get the metadata.
554 E : Metadata metadata;
555 E : PEFile pe_file;
556 E : if (!pe_file.Init(input_path)) {
557 i : LOG(ERROR) << "Failed to initialize PE file for \"" << input_path.value()
558 : << "\".";
559 i : return false;
560 : }
561 :
562 E : PEFile::Signature pe_sig;
563 E : pe_file.GetSignature(&pe_sig);
564 E : if (!metadata.Init(pe_sig)) {
565 i : LOG(ERROR) << "Failed to initialize metadata for \"" << input_path.value()
566 : << "\".";
567 i : return false;
568 : }
569 :
570 : // Validate the history stream if it is non-empty.
571 E : if (history_reader->length() > 0) {
572 : // Read the header.
573 i : uint32 version = 0;
574 i : uint32 history_length = 0;
575 : if (!history_reader->Seek(0) ||
576 : !history_reader->Read(&version, 1) ||
577 i : !history_reader->Read(&history_length, 1)) {
578 i : LOG(ERROR) << "Failed to read existing Syzygy history stream header.";
579 i : return false;
580 : }
581 :
582 : // Check the version.
583 i : if (version != pdb::kSyzygyHistoryStreamVersion) {
584 i : LOG(ERROR) << "PDB contains unsupported Syzygy history stream version "
585 : << "(got " << version << ", expected "
586 : << pdb::kSyzygyHistoryStreamVersion << ").";
587 i : return false;
588 : }
589 :
590 : // Increment the history length and rewrite it.
591 i : history_length++;
592 i : history_writer->set_pos(sizeof(pdb::kSyzygyHistoryStreamVersion));
593 i : if (!history_writer->Write(history_length)) {
594 i : LOG(ERROR) << "Failed to write new Syzygy history stream length.";
595 i : return false;
596 : }
597 i : } else {
598 : // If there wasn't already a history stream, create one and write the
599 : // header.
600 E : DCHECK_EQ(0u, history_writer->pos());
601 E : const uint32 kHistoryLength = 1;
602 : if (!history_writer->Write(pdb::kSyzygyHistoryStreamVersion) ||
603 E : !history_writer->Write(kHistoryLength)) {
604 i : LOG(ERROR) << "Failed to write Syzygy history stream header.";
605 i : return false;
606 : }
607 : }
608 :
609 : // Append the metadata to the history.
610 E : history_writer->set_pos(history_writer->length());
611 E : PdbOutStream out_stream(history_writer.get());
612 E : core::OutArchive out_archive(&out_stream);
613 E : if (!out_archive.Save(metadata)) {
614 i : LOG(ERROR) << "Failed to write metadata to Syzygy history stream.";
615 i : return false;
616 : }
617 :
618 E : return true;
619 E : }
620 :
621 : // This writes the serialized block-graph and the image layout in a PDB stream
622 : // named /Syzygy/BlockGraph. If the format is changed, be sure to update this
623 : // documentation and pdb::kSyzygyBlockGraphStreamVersion (in pdb_constants.h).
624 : // The block graph stream will not include the data from the blocks of the
625 : // block-graph. If the strip-strings flag is set to true the strings contained
626 : // in the block-graph won't be saved.
627 : bool WriteSyzygyBlockGraphStream(const PEFile& pe_file,
628 : const ImageLayout& image_layout,
629 : bool strip_strings,
630 : bool compress,
631 : NameStreamMap* name_stream_map,
632 E : PdbFile* pdb_file) {
633 : // Get the redecomposition data stream.
634 : scoped_refptr<PdbStream> block_graph_reader =
635 : GetOrCreatePdbStreamByName(pdb::kSyzygyBlockGraphStreamName,
636 : true,
637 : name_stream_map,
638 E : pdb_file);
639 :
640 E : if (block_graph_reader == NULL) {
641 i : LOG(ERROR) << "Failed to get the block-graph stream.";
642 i : return false;
643 : }
644 E : DCHECK_EQ(0u, block_graph_reader->length());
645 :
646 : scoped_refptr<WritablePdbStream> block_graph_writer =
647 E : block_graph_reader->GetWritablePdbStream();
648 E : DCHECK(block_graph_writer.get() != NULL);
649 :
650 : // Write the version of the BlockGraph stream, and whether or not its
651 : // contents are compressed.
652 : if (!block_graph_writer->Write(pdb::kSyzygyBlockGraphStreamVersion) ||
653 E : !block_graph_writer->Write(static_cast<unsigned char>(compress))) {
654 i : LOG(ERROR) << "Failed to write Syzygy BlockGraph stream header.";
655 i : return false;
656 : }
657 :
658 : // Set up the output stream.
659 E : PdbOutStream pdb_out_stream(block_graph_writer.get());
660 E : core::OutStream* out_stream = &pdb_out_stream;
661 :
662 : // If requested, compress the output.
663 E : scoped_ptr<core::ZOutStream> zip_stream;
664 E : if (compress) {
665 E : zip_stream.reset(new core::ZOutStream(&pdb_out_stream));
666 E : out_stream = zip_stream.get();
667 E : if (!zip_stream->Init(core::ZOutStream::kZBestCompression)) {
668 i : LOG(ERROR) << "Failed to initialize zlib compressor.";
669 i : return false;
670 : }
671 : }
672 :
673 E : core::OutArchive out_archive(out_stream);
674 :
675 : // Set up the serialization properties.
676 E : block_graph::BlockGraphSerializer::Attributes attributes = 0;
677 E : if (strip_strings)
678 E : attributes |= block_graph::BlockGraphSerializer::OMIT_STRINGS;
679 :
680 : // And finally, perform the serialization.
681 : if (!SaveBlockGraphAndImageLayout(pe_file, attributes, image_layout,
682 E : &out_archive)) {
683 i : LOG(ERROR) << "SaveBlockGraphAndImageLayout failed.";
684 i : return false;
685 : }
686 :
687 : // We have to flush the stream in case it's a zstream.
688 E : out_stream->Flush();
689 :
690 E : return true;
691 E : }
692 :
693 : } // namespace
694 :
695 : PERelinker::PERelinker()
696 : : add_metadata_(true), allow_overwrite_(false), augment_pdb_(true),
697 : compress_pdb_(false), parse_debug_info_(true), strip_strings_(false),
698 : use_new_decomposer_(false), padding_(0), inited_(false),
699 : input_image_layout_(&block_graph_), dos_header_block_(NULL),
700 E : output_guid_(GUID_NULL) {
701 E : }
702 :
703 E : void PERelinker::AppendTransform(Transform* transform) {
704 E : DCHECK(transform != NULL);
705 E : transforms_.push_back(transform);
706 E : }
707 :
708 E : void PERelinker::AppendTransforms(const std::vector<Transform*>& transforms) {
709 E : transforms_.insert(transforms_.end(), transforms.begin(), transforms.end());
710 E : }
711 :
712 E : void PERelinker::AppendOrderer(Orderer* orderer) {
713 E : DCHECK(orderer != NULL);
714 E : orderers_.push_back(orderer);
715 E : }
716 :
717 E : void PERelinker::AppendOrderers(const std::vector<Orderer*>& orderers) {
718 E : orderers_.insert(orderers_.end(), orderers.begin(), orderers.end());
719 E : }
720 :
721 E : void PERelinker::AppendPdbMutator(PdbMutatorInterface* pdb_mutator) {
722 E : DCHECK(pdb_mutator != NULL);
723 E : pdb_mutators_.push_back(pdb_mutator);
724 E : }
725 :
726 : void PERelinker::AppendPdbMutators(
727 E : const std::vector<PdbMutatorInterface*>& pdb_mutators) {
728 : pdb_mutators_.insert(pdb_mutators_.end(),
729 : pdb_mutators.begin(),
730 E : pdb_mutators.end());
731 E : }
732 :
733 E : bool PERelinker::Init() {
734 E : DCHECK(inited_ == false);
735 :
736 : // Initialize the paths.
737 : if (!InitializePaths(input_path_, output_path_, allow_overwrite_,
738 E : &input_pdb_path_, &output_pdb_path_)) {
739 E : return false;
740 : }
741 :
742 E : LOG(INFO) << "Input module : " << input_path_.value();
743 E : LOG(INFO) << "Input PDB : " << input_pdb_path_.value();
744 E : LOG(INFO) << "Output module: " << output_path_.value();
745 E : LOG(INFO) << "Output PDB : " << output_pdb_path_.value();
746 :
747 : // Open the input PE file.
748 E : if (!input_pe_file_.Init(input_path_)) {
749 i : LOG(ERROR) << "Unable to load \"" << input_path_.value() << "\".";
750 i : return false;
751 : }
752 :
753 : // Generate a GUID for the relinked image's PDB file.
754 E : if (FAILED(::CoCreateGuid(&output_guid_))) {
755 i : LOG(ERROR) << "Failed to create new PDB GUID.";
756 i : return false;
757 : }
758 :
759 : // Decompose the image.
760 : if (!Decompose(use_new_decomposer_, parse_debug_info_,
761 : input_pe_file_, input_pdb_path_,
762 E : &input_image_layout_, &dos_header_block_)) {
763 i : return false;
764 : }
765 :
766 E : inited_ = true;
767 :
768 E : return true;
769 E : }
770 :
771 E : bool PERelinker::Relink() {
772 E : if (!inited_) {
773 i : LOG(ERROR) << "Init has not been successfully called.";
774 i : return false;
775 : }
776 :
777 : // Transform it.
778 : if (!ApplyTransforms(input_path_, output_pdb_path_, output_guid_,
779 : add_metadata_, &transforms_, &block_graph_,
780 E : dos_header_block_)) {
781 E : return false;
782 : }
783 :
784 : // Order it.
785 E : OrderedBlockGraph ordered_block_graph(&block_graph_);
786 E : if (!ApplyOrderers(&orderers_, &ordered_block_graph, dos_header_block_))
787 E : return false;
788 :
789 : // Lay it out.
790 E : ImageLayout output_image_layout(&block_graph_);
791 : if (!BuildImageLayout(padding_, ordered_block_graph, dos_header_block_,
792 E : &output_image_layout)) {
793 i : return false;
794 : }
795 :
796 : // Write the image.
797 E : if (!WriteImage(output_image_layout, output_path_))
798 i : return false;
799 :
800 : // From here on down we are processing the PDB file.
801 :
802 : // Read the PDB file.
803 E : LOG(INFO) << "Reading PDB file: " << input_pdb_path_.value();
804 E : pdb::PdbReader pdb_reader;
805 E : PdbFile pdb_file;
806 E : if (!pdb_reader.Read(input_pdb_path_, &pdb_file)) {
807 i : LOG(ERROR) << "Unable to read PDB file: " << input_pdb_path_.value();
808 i : return false;
809 : }
810 :
811 : // Apply the mutators to the PDB file.
812 E : if (!ApplyPdbMutators(pdb_mutators_, &pdb_file))
813 E : return false;
814 :
815 : // TODO(chrisha): Make the following 3 PDB updates PdbMutatorInterface
816 : // implementations.
817 :
818 : // Update the OMAP and GUID information.
819 E : RelativeAddressRange input_range;
820 E : GetOmapRange(input_image_layout_.sections, &input_range);
821 : if (!SetOmapAndGuid(input_range, output_image_layout, output_guid_,
822 E : &pdb_file)) {
823 i : return false;
824 : }
825 :
826 : // Parse the header and named streams.
827 E : pdb::PdbInfoHeader70 header = {};
828 E : pdb::NameStreamMap name_stream_map;
829 E : if (!pdb::ReadHeaderInfoStream(pdb_file, &header, &name_stream_map))
830 i : return false;
831 :
832 : // Update/create the Syzygy history stream.
833 E : if (!WriteSyzygyHistoryStream(input_path_, &name_stream_map, &pdb_file))
834 i : return false;
835 :
836 : // Add redecomposition data in another stream, only if augment_pdb_ is set.
837 E : if (augment_pdb_) {
838 E : LOG(INFO) << "The block-graph stream is being written to the PDB.";
839 :
840 E : PEFile new_pe_file;
841 E : if (!new_pe_file.Init(output_path_)) {
842 i : LOG(ERROR) << "Failed to read newly written PE file.";
843 i : return false;
844 : }
845 :
846 : if (!WriteSyzygyBlockGraphStream(new_pe_file,
847 : output_image_layout,
848 : strip_strings_,
849 : compress_pdb_,
850 : &name_stream_map,
851 E : &pdb_file)) {
852 i : return false;
853 : }
854 E : }
855 :
856 : // Write the updated name-stream map back to the header info stream.
857 E : if (!pdb::WriteHeaderInfoStream(header, name_stream_map, &pdb_file))
858 i : return false;
859 :
860 : // Stream 0 contains a copy of the previous PDB's directory. This, combined
861 : // with copy-on-write semantics of individual blocks makes the file contain
862 : // its whole edit history. Since we're writing a 'new' PDB file (we reset the
863 : // GUID and age), we have no history so can safely throw away this stream.
864 E : pdb_file.ReplaceStream(0, NULL);
865 :
866 : // Write the PDB file. We use a helper function that first writes it to a
867 : // temporary file and then moves it, enabling overwrites.
868 E : if (!WritePdbFile(output_pdb_path_, pdb_file))
869 i : return false;
870 :
871 E : return true;
872 E : }
873 :
874 : } // namespace pe
|