Coverage for /Syzygy/reorder/reorderer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
73.8%2453320.C++source

Line-by-line coverage:

   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/reorder/reorderer.h"
  16    :  
  17    :  #include "base/values.h"
  18    :  #include "base/files/file_util.h"
  19    :  #include "base/json/json_reader.h"
  20    :  #include "base/json/string_escape.h"
  21    :  #include "base/strings/stringprintf.h"
  22    :  #include "base/strings/utf_string_conversions.h"
  23    :  #include "syzygy/block_graph/block_graph.h"
  24    :  #include "syzygy/common/defs.h"
  25    :  #include "syzygy/core/json_file_writer.h"
  26    :  #include "syzygy/core/serialization.h"
  27    :  #include "syzygy/pdb/omap.h"
  28    :  #include "syzygy/pe/find.h"
  29    :  #include "syzygy/pe/metadata.h"
  30    :  #include "syzygy/pe/pe_file.h"
  31    :  #include "syzygy/pe/pe_utils.h"
  32    :  #include "syzygy/version/syzygy_version.h"
  33    :  
  34    :  namespace reorder {
  35    :  
  36    :  using block_graph::BlockGraph;
  37    :  using trace::parser::Parser;
  38    :  using base::ListValue;
  39    :  using base::DictionaryValue;
  40    :  using base::Value;
  41    :  
  42    :  namespace {
  43    :  
  44    :  const char kCommentKey[] = "comment";
  45    :  const char kMetadataKey[] = "metadata";
  46    :  const char kSectionsKey[] = "sections";
  47    :  const char kSectionIdKey[] = "id";
  48    :  const char kSectionNameKey[] = "name";
  49    :  const char kSectionCharacteristicsKey[] = "characteristics";
  50    :  const char kBlocksKey[] = "blocks";
  51    :  
  52    :  bool OutputTrailingBlockComment(const BlockGraph::Block* block,
  53  E :                                  core::JSONFileWriter* json_file) {
  54  E :    DCHECK(block != NULL);
  55  E :    DCHECK(json_file != NULL);
  56    :  
  57  E :    if (!json_file->pretty_print())
  58  E :      return true;
  59    :  
  60    :    std::string comment = base::StringPrintf(
  61    :        "%s(%s)",
  62    :        BlockGraph::BlockTypeToString(block->type()),
  63  E :        block->name().c_str());
  64    :  
  65  E :    if (!json_file->OutputTrailingComment(comment))
  66  i :      return false;
  67    :  
  68  E :    return true;
  69  E :  }
  70    :  
  71    :  bool OutputBlockSpec(const Reorderer::Order::BlockSpec& block_spec,
  72  E :                       core::JSONFileWriter* json_file) {
  73    :    // TODO(rogerm): Stop referring to block->addr() and take the address space
  74    :    //     as an input parameter.
  75  E :    DCHECK(json_file != NULL);
  76    :    // TODO(rogerm): Flesh out support for synthesizing new blocks.
  77  E :    DCHECK(block_spec.block != NULL);
  78    :  
  79    :    // If no basic-block RVAs are given then the entire block is to be
  80    :    // used and we can just just the block address.
  81  E :    if (block_spec.basic_block_offsets.empty()) {
  82  E :      if (!json_file->OutputInteger(block_spec.block->addr().value()))
  83  i :        return false;
  84  E :      if (!OutputTrailingBlockComment(block_spec.block, json_file))
  85  i :        return false;
  86  E :      return true;
  87    :    }
  88    :  
  89    :    // Otherwise, we output a pair (two element list) comprising the block
  90    :    // address and the list of basic-block RVAs.
  91    :  
  92    :    // Open the outer list.
  93  E :    if (!json_file->OpenList())
  94  i :      return false;
  95    :  
  96    :    // Output the block address.
  97    :    if (!json_file->OutputInteger(block_spec.block->addr().value()) ||
  98  E :        !OutputTrailingBlockComment(block_spec.block, json_file)) {
  99  i :      return false;
 100    :    }
 101    :  
 102    :    // Open the inner list.
 103  E :    if (!json_file->OpenList())
 104  i :      return false;
 105    :  
 106    :    // Output the basic block RVAs.
 107    :    Reorderer::Order::OffsetVector::const_iterator it =
 108  E :        block_spec.basic_block_offsets.begin();
 109  E :    for (; it != block_spec.basic_block_offsets.end(); ++it) {
 110  E :      if (!json_file->OutputInteger(*it))
 111  i :        return false;
 112  E :    }
 113    :  
 114    :    // Close the inner list.
 115  E :    if (!json_file->CloseList())
 116  i :      return false;
 117    :  
 118    :    // Close the outer list.
 119  E :    if (!json_file->CloseList())
 120  i :      return false;
 121    :  
 122  E :    return true;
 123  E :  }
 124    :  
 125    :  // Serializes a block list to JSON.
 126    :  bool OutputSectionSpec(const Reorderer::Order::SectionSpec& section_spec,
 127  E :                         core::JSONFileWriter* json_file) {
 128  E :    DCHECK(json_file != NULL);
 129    :  
 130    :    // Open the section specification dictionary.
 131  E :    if (!json_file->OpenDict())
 132  i :      return false;
 133    :  
 134    :    // If the section has an ID in the original image, output the ID.
 135  E :    if (section_spec.id != Reorderer::Order::SectionSpec::kNewSectionId) {
 136    :      if (!json_file->OutputKey(kSectionIdKey) ||
 137  E :          !json_file->OutputInteger(section_spec.id)) {
 138  i :        return false;
 139    :      }
 140    :    }
 141    :  
 142    :    // Output the section metadata.
 143    :    if (!json_file->OutputKey(kSectionNameKey) ||
 144    :        !json_file->OutputString(section_spec.name) ||
 145    :        !json_file->OutputKey(kSectionCharacteristicsKey) ||
 146  E :        !json_file->OutputInteger(section_spec.characteristics)) {
 147  i :      return false;
 148    :    }
 149    :  
 150    :    // Open the block spec list.
 151    :    if (!json_file->OutputKey(kBlocksKey) ||
 152  E :        !json_file->OpenList()) {
 153  i :      return false;
 154    :    }
 155    :  
 156    :    // Output each of the block specifications.
 157    :    Reorderer::Order::BlockSpecVector::const_iterator it =
 158  E :        section_spec.blocks.begin();
 159  E :    for (; it != section_spec.blocks.end(); ++it) {
 160  E :      if (!OutputBlockSpec(*it, json_file))
 161  i :        return false;
 162  E :    }
 163    :  
 164    :    // Close the block spec list.
 165  E :    if (!json_file->CloseList())
 166  i :      return false;
 167    :  
 168    :    // Close the section spec dictionary.
 169  E :    if (!json_file->CloseDict())
 170  i :      return false;
 171    :  
 172  E :    return true;
 173  E :  }
 174    :  
 175    :  bool LoadBlockSpec(const pe::ImageLayout& image,
 176    :                     const Value* block_value,
 177  E :                     Reorderer::Order::BlockSpec* block_spec) {
 178  E :    DCHECK(block_value != NULL);
 179  E :    DCHECK(block_spec != NULL);
 180    :  
 181  E :    block_spec->block = NULL;
 182  E :    block_spec->basic_block_offsets.clear();
 183    :  
 184    :    // If the block value is a single integer, then we use the entire block.
 185    :    // Otherwise, we evaluate the value as a pair (represented as a list)
 186    :    // where the first element is the address and the second element is a list
 187    :    // of basic-block RVAs.
 188  E :    int address = 0;
 189  E :    const ListValue* rva_list = NULL;
 190  E :    if (!block_value->GetAsInteger(&address)) {
 191  E :      const ListValue* pair = NULL;
 192    :      if (!block_value->GetAsList(&pair) ||
 193    :          !pair->GetInteger(0, &address) ||
 194  E :          !pair->GetList(1, &rva_list)) {
 195  i :        LOG(ERROR) << "Invalid entry for block specification.";
 196  i :        return false;
 197    :      }
 198    :    }
 199    :  
 200    :    // Resolve the referenced block.
 201  E :    core::RelativeAddress rva(address);
 202  E :    const BlockGraph::Block* block = image.blocks.GetBlockByAddress(rva);
 203  E :    if (block == NULL) {
 204  i :      LOG(ERROR) << "Block address not found in decomposed image: "
 205    :                  << address;
 206  i :      return false;
 207    :    }
 208    :  
 209    :    // Read in the basic_block offsets.
 210  E :    bool seen_end_block = false;
 211  E :    if (rva_list != NULL && !rva_list->empty()) {
 212  E :      block_spec->basic_block_offsets.reserve(rva_list->GetSize());
 213  E :      for (size_t i = 0; i < rva_list->GetSize(); ++i) {
 214  E :        int offset = 0;
 215  E :        if (!rva_list->GetInteger(i, &offset)) {
 216  i :          LOG(ERROR) << "Unexpected value for basic-block offset #" << i
 217    :                     << " of " << address << " [" << block->name() << "].";
 218  i :          block_spec->basic_block_offsets.clear();
 219  i :          return false;
 220    :        }
 221    :        if (offset < 0 ||
 222  E :            static_cast<BlockGraph::Size>(offset) > block->size()) {
 223  i :          LOG(ERROR) << "Offset " << offset << " falls outside block range [0-"
 224    :                     << block->size() << "] for " << block->name();
 225  i :          return false;
 226    :        }
 227    :  
 228    :        // The basic-end block must be last in the block specification. The
 229    :        // block builder will catch this error but we can meaningfully catch this
 230    :        // earlier and avoid a lot of computation for nothing.
 231  E :        if (static_cast<BlockGraph::Size>(offset) == block->size()) {
 232  E :          seen_end_block = true;
 233  E :        } else if (seen_end_block) {
 234  i :          LOG(ERROR) << "Encountered basic-end block that is not last in the "
 235    :                     << "specified ordering.";
 236  i :          return false;
 237    :        }
 238  E :        block_spec->basic_block_offsets.push_back(offset);
 239  E :      }
 240    :    }
 241    :  
 242  E :    block_spec->block = block;
 243  E :    return true;
 244  E :  }
 245    :  
 246    :  bool LoadSectionSpec(const pe::ImageLayout& image,
 247    :                       const DictionaryValue* section_value,
 248    :                       Reorderer::Order::SectionSpec* section_spec,
 249  E :                       std::set<size_t>* seen_section_ids) {
 250  E :    DCHECK(section_value != NULL);
 251  E :    DCHECK(section_spec != NULL);
 252  E :    DCHECK(seen_section_ids != NULL);
 253    :  
 254    :    // Some keys we'll refer to multiple times below.
 255  E :    const std::string section_id_key(kSectionIdKey);
 256  E :    const std::string section_name_key(kSectionNameKey);
 257  E :    const std::string section_characteristics_key(kSectionCharacteristicsKey);
 258  E :    const std::string blocks_key(kBlocksKey);
 259    :  
 260    :    // Get the section id, if given.
 261  E :    int tmp_section_id = Reorderer::Order::SectionSpec::kNewSectionId;
 262    :    if (section_value->HasKey(section_id_key) &&
 263  E :        !section_value->GetInteger(section_id_key, &tmp_section_id)) {
 264  i :      LOG(ERROR) << "Invalid value for " << section_id_key << ".";
 265  i :      return false;
 266    :    }
 267    :  
 268    :    // Lookup the original section by id, if the id was given. Populate the
 269    :    // section metadata based on the original section info. The other keys
 270    :    // will be inspected below to see if any of the metadata needs to be
 271    :    // over-ridden.
 272  E :    section_spec->id = tmp_section_id;
 273  E :    if (section_spec->id != Reorderer::Order::SectionSpec::kNewSectionId) {
 274    :      // Lookup the section in the original image layout.
 275  E :      if (section_spec->id < 0 || section_spec->id > image.sections.size()) {
 276  i :        LOG(ERROR) << "Invalid section id: " << section_spec->id << ".";
 277  i :        return false;
 278    :      }
 279    :  
 280    :      // Make sure this section id does not already exist.
 281  E :      if (!seen_section_ids->insert(section_spec->id).second) {
 282  i :        LOG(ERROR) << "Section ID " << section_spec->id << " redefined.";
 283  i :        return false;
 284    :      }
 285    :  
 286    :      // Copy the metadata into the section spec.
 287  E :      section_spec->name = image.sections[section_spec->id].name;
 288    :      section_spec->characteristics =
 289  E :          image.sections[section_spec->id].characteristics;
 290    :    }
 291    :  
 292    :    // Possibly over-ride the section name.
 293    :    if (section_value->HasKey(section_name_key) &&
 294  E :        !section_value->GetString(section_name_key, &section_spec->name)) {
 295  i :      LOG(ERROR) << "Invalid value for " << section_name_key << ".";
 296  i :      return false;
 297    :    }
 298    :  
 299    :    // Make sure we've got a section name. This may have come from either the
 300    :    // the original image (via the section id) or explicitly from the section
 301    :    // name key.
 302  E :    if (section_spec->name.empty()) {
 303  i :      LOG(ERROR) << "Missing a value for the section name. Either a valid "
 304    :                 << section_id_key << " or valid " << section_name_key
 305    :                 << " is required.";
 306  i :      return false;
 307    :    }
 308    :  
 309    :    // Possibly over-ride the section characteristics. The characteristics are
 310    :    // required if the section was not given by id.
 311    :    if (section_spec->id == Reorderer::Order::SectionSpec::kNewSectionId ||
 312  E :        section_value->HasKey(section_characteristics_key)) {
 313  E :      int tmp_characteristics = 0;
 314    :      if (!section_value->GetInteger(section_characteristics_key,
 315  E :                                     &tmp_characteristics)) {
 316  i :        LOG(ERROR) << "Missing or invalid value for "
 317    :                   << section_characteristics_key << ".";
 318  i :        return false;
 319    :      }
 320  E :      section_spec->characteristics = tmp_characteristics;
 321    :    }
 322    :  
 323    :    // Get the list of block specifications.
 324  E :    const ListValue* blocks = NULL;
 325  E :    if (!section_value->GetList(blocks_key, &blocks)) {
 326  i :      LOG(ERROR) << "Invalid or missing value for " << blocks_key << ".";
 327  i :      return false;
 328    :    }
 329    :  
 330  E :    if (!blocks->empty()) {
 331    :      // Populate the block spec vector.
 332  E :      section_spec->blocks.resize(blocks->GetSize());
 333  E :      for (size_t block_idx = 0; block_idx != blocks->GetSize(); ++block_idx) {
 334  E :        const Value* block_value = NULL;
 335  E :        if (!blocks->Get(block_idx, &block_value)) {
 336  i :          LOG(ERROR) << "Failed to access item " << block_idx << ".";
 337  i :          return false;
 338    :        }
 339    :  
 340  E :        if (!LoadBlockSpec(image, block_value, &section_spec->blocks[block_idx]))
 341  i :          return false;
 342  E :      }
 343    :    }
 344    :  
 345  E :    return true;
 346  E :  }
 347    :  
 348    :  }  // namespace
 349    :  
 350    :  const size_t Reorderer::Order::SectionSpec::kNewSectionId = ~1U;
 351    :  
 352    :  Reorderer::Reorderer(const base::FilePath& module_path,
 353    :                       const base::FilePath& instrumented_path,
 354    :                       const TraceFileList& trace_files,
 355    :                       Flags flags)
 356    :      : playback_(module_path, instrumented_path, trace_files),
 357    :        flags_(flags),
 358    :        code_block_entry_events_(0),
 359  E :        order_generator_(NULL) {
 360  E :  }
 361    :  
 362  E :  Reorderer::~Reorderer() {
 363  E :  }
 364    :  
 365    :  bool Reorderer::Reorder(OrderGenerator* order_generator,
 366    :                          Order* order,
 367    :                          PEFile* pe_file,
 368  E :                          ImageLayout* image) {
 369  E :    DCHECK(order_generator != NULL);
 370  E :    DCHECK(order != NULL);
 371    :  
 372  E :    DCHECK(order_generator_ == NULL);
 373  E :    order_generator_ = order_generator;
 374    :  
 375  E :    bool success = ReorderImpl(order, pe_file, image);
 376    :  
 377  E :    order_generator_ = NULL;
 378    :  
 379  E :    return success;
 380  E :  }
 381    :  
 382    :  bool Reorderer::ReorderImpl(Order* order,
 383    :                              PEFile* pe_file,
 384  E :                              ImageLayout* image) {
 385  E :    DCHECK(order != NULL);
 386  E :    DCHECK(order_generator_ != NULL);
 387    :  
 388  E :    if (!parser_.Init(this)) {
 389  i :      LOG(ERROR) << "Failed to initialize call trace parser.";
 390  i :      return false;
 391    :    }
 392    :  
 393  E :    if (!playback_.Init(pe_file, image, &parser_))
 394  i :      return false;
 395    :  
 396  E :    if (playback_.trace_files().size() > 0) {
 397  E :      LOG(INFO) << "Processing trace events.";
 398  E :      if (!parser_.Consume())
 399  i :        return false;
 400    :  
 401  E :      if (code_block_entry_events_ == 0) {
 402  i :        LOG(ERROR) << "No events originated from the given instrumented DLL.";
 403  i :        return false;
 404    :      }
 405    :    }
 406    :  
 407  E :    if (!CalculateReordering(order))
 408  i :      return false;
 409    :  
 410  E :    return true;
 411  E :  }
 412    :  
 413  E :  bool Reorderer::CalculateReordering(Order* order) {
 414  E :    DCHECK(order != NULL);
 415  E :    DCHECK(order_generator_ != NULL);
 416    :  
 417  E :    LOG(INFO) << "Calculating new order.";
 418    :    if (!order_generator_->CalculateReordering(*playback_.pe_file(),
 419    :                                               *playback_.image(),
 420    :                                               (flags_ & kFlagReorderCode) != 0,
 421    :                                               (flags_ & kFlagReorderData) != 0,
 422  E :                                               order))
 423  i :      return false;
 424    :  
 425    :    order->comment = base::StringPrintf("Generated using the %s.",
 426  E :                                        order_generator_->name().c_str());
 427    :  
 428  E :    return true;
 429  E :  }
 430    :  
 431    :  void Reorderer::OnProcessStarted(
 432  E :      base::Time time, DWORD process_id, const TraceSystemInfo* data) {
 433  E :    UniqueTime entry_time(time);
 434    :  
 435  E :    if (!order_generator_->OnProcessStarted(process_id, entry_time)) {
 436  i :      parser_.set_error_occurred(true);
 437    :      return;
 438    :    }
 439  E :  }
 440    :  
 441  E :  void Reorderer::OnProcessEnded(base::Time time, DWORD process_id) {
 442    :    // Notify the order generator.
 443  E :    if (!order_generator_->OnProcessEnded(process_id, UniqueTime(time))) {
 444  i :      parser_.set_error_occurred(true);
 445    :      return;
 446    :    }
 447  E :  }
 448    :  
 449    :  // CallTraceEvents implementation.
 450    :  void Reorderer::OnFunctionEntry(base::Time time,
 451    :                                  DWORD process_id,
 452    :                                  DWORD thread_id,
 453  E :                                  const TraceEnterExitEventData* data) {
 454  E :    DCHECK(data != NULL);
 455    :  
 456  E :    bool error = false;
 457    :    const BlockGraph::Block* block = playback_.FindFunctionBlock(process_id,
 458    :                                                                 data->function,
 459  E :                                                                 &error);
 460    :  
 461    :    // Handle the error if any occurred.
 462  E :    if (error) {
 463  i :      LOG(ERROR) << "Playback::FindFunctionBlock failed.";
 464  i :      parser_.set_error_occurred(true);
 465  i :      return;
 466    :    }
 467    :  
 468    :    // If no block was found then we simply ignore the event.
 469  E :    if (block == NULL)
 470  i :      return;
 471    :  
 472    :    // Get the time of the call. Since batched function calls come in with the
 473    :    // same time stamp, we rely on their relative ordering and UniqueTime's
 474    :    // incrementing ID to maintain relative order.
 475  E :    UniqueTime entry_time(time);
 476    :  
 477  E :    ++code_block_entry_events_;
 478    :    if (!order_generator_->OnCodeBlockEntry(block,
 479    :                                            block->addr(),
 480    :                                            process_id,
 481    :                                            thread_id,
 482  E :                                            entry_time)) {
 483  i :      LOG(ERROR) << order_generator_->name() << "::OnCodeBlockEntry failed.";
 484  i :      parser_.set_error_occurred(true);
 485    :      return;
 486    :    }
 487  E :  }
 488    :  
 489    :  void Reorderer::OnBatchFunctionEntry(base::Time time,
 490    :                                       DWORD process_id,
 491    :                                       DWORD thread_id,
 492  E :                                       const TraceBatchEnterData* data) {
 493    :    // Explode the batch event into individual function entry events.
 494  E :    TraceEnterExitEventData new_data = {};
 495  E :    for (size_t i = 0; i < data->num_calls; ++i) {
 496  E :      new_data.function = data->calls[i].function;
 497  E :      OnFunctionEntry(time, process_id, thread_id, &new_data);
 498  E :    }
 499  E :  }
 500    :  
 501    :  bool Reorderer::Order::SerializeToJSON(const PEFile& pe,
 502    :                                         const base::FilePath &path,
 503  E :                                         bool pretty_print) const {
 504  E :    base::ScopedFILE file(base::OpenFile(path, "wb"));
 505  E :    if (file.get() == NULL)
 506  i :      return false;
 507  E :    core::JSONFileWriter json_file(file.get(), pretty_print);
 508  E :    return SerializeToJSON(pe, &json_file);
 509  E :  }
 510    :  
 511    :  bool Reorderer::Order::SerializeToJSON(const PEFile& pe,
 512  E :                                         core::JSONFileWriter* json_file) const {
 513  E :    DCHECK(json_file != NULL);
 514    :  
 515    :    // Open the top-level dictionary and the metadata dictionary.
 516  E :    if (!json_file->OpenDict())
 517  i :      return false;
 518    :  
 519    :    // Output the filecomment.
 520    :    if (!json_file->OutputKey(kCommentKey) ||
 521  E :        !json_file->OutputString(comment)) {
 522  i :      return false;
 523    :    }
 524    :  
 525    :    // Output metadata.
 526  E :    PEFile::Signature orig_sig;
 527  E :    pe.GetSignature(&orig_sig);
 528  E :    pe::Metadata metadata;
 529    :    if (!metadata.Init(orig_sig) ||
 530    :        !json_file->OutputKey(kMetadataKey) ||
 531  E :        !metadata.SaveToJSON(json_file)) {
 532  i :      return false;
 533    :    }
 534    :  
 535    :    // Open list of sections.
 536    :    if (!json_file->OutputKey(kSectionsKey) ||
 537  E :        !json_file->OpenList()) {
 538  i :      return false;
 539    :    }
 540    :  
 541    :    // Output the individual block lists.
 542  E :    SectionSpecVector::const_iterator it = sections.begin();
 543  E :    for (; it != sections.end(); ++it) {
 544  E :      const SectionSpec& section_spec = *it;
 545  E :      if (section_spec.blocks.empty())
 546  i :        continue;
 547    :  
 548  E :      if (!OutputSectionSpec(section_spec, json_file))
 549  i :        return false;
 550  E :    }
 551    :  
 552    :    // Close the list of sections.
 553  E :    if (!json_file->CloseList())
 554  i :      return false;
 555    :  
 556    :    // Close the outermost dictionary.
 557  E :    if (!json_file->CloseDict())
 558  i :      return false;
 559    :  
 560  E :    return true;
 561  E :  }
 562    :  
 563    :  bool Reorderer::Order::LoadFromJSON(const PEFile& pe,
 564    :                                      const ImageLayout& image,
 565  E :                                      const base::FilePath& path) {
 566  E :    std::string file_string;
 567  E :    if (!base::ReadFileToString(path, &file_string)) {
 568  i :      LOG(ERROR) << "Unable to read order file to string";
 569  i :      return false;
 570    :    }
 571    :  
 572    :    // Read in the JSON file. It should be a dictionary.
 573  E :    const DictionaryValue* outer_dict = NULL;
 574  E :    scoped_ptr<Value> value(base::JSONReader::Read(file_string));
 575  E :    if (value.get() == NULL || !value->GetAsDictionary(&outer_dict)) {
 576  i :      LOG(ERROR) << "Order file does not contain a valid JSON dictionary.";
 577  i :      return false;
 578    :    }
 579    :  
 580    :    // Load the metadata from the order file, and ensure it is consistent with
 581    :    // the signature of the module the ordering is being applied to.
 582  E :    pe::Metadata metadata;
 583  E :    PEFile::Signature pe_sig;
 584  E :    pe.GetSignature(&pe_sig);
 585  E :    const DictionaryValue* metadata_dict = NULL;
 586    :    if (!outer_dict->GetDictionary(kMetadataKey, &metadata_dict) ||
 587    :        !metadata.LoadFromJSON(*metadata_dict) ||
 588  E :        !metadata.IsConsistent(pe_sig)) {
 589  i :      LOG(ERROR) << "Missing, invalid, or inconsistent " << kMetadataKey << ".";
 590  i :      return false;
 591    :    }
 592    :  
 593    :    // Load the comments field.
 594    :    if (outer_dict->HasKey(kCommentKey) &&
 595  E :        !outer_dict->GetString(kCommentKey, &comment)) {
 596  i :      LOG(ERROR) << "Invalid " << kCommentKey << " value. Must be a string.";
 597  i :      return false;
 598    :    }
 599    :  
 600    :    // Grab the sections list.
 601  E :    const ListValue* order = NULL;
 602  E :    if (!outer_dict->GetList(kSectionsKey, &order)) {
 603  i :      LOG(ERROR) << "Missing or invalid " << kSectionsKey << ".";
 604  i :      return false;
 605    :    }
 606    :  
 607    :    // Allocate the expected number of sections.
 608  E :    sections.clear();
 609    :  
 610    :    // Iterate through the elements of the list. They should each be dictionaries
 611    :    // representing a single section. We'll also track the sections descriptions
 612    :    // we have already seen.
 613  E :    std::set<size_t> seen_section_ids;
 614  E :    sections.resize(order->GetSize());
 615  E :    for (size_t index = 0; index < order->GetSize(); ++index) {
 616  E :      const DictionaryValue* section = NULL;
 617  E :      if (!order->GetDictionary(index, &section)) {
 618  i :        LOG(ERROR) << "Item " << index << "of " << kSectionsKey
 619    :                   << " list is not a dictionary.";
 620  i :        return false;
 621    :      }
 622    :  
 623  E :      if (!LoadSectionSpec(image, section, &sections[index], &seen_section_ids))
 624  i :        return false;
 625  E :    }
 626    :  
 627  E :    return true;
 628  E :  }
 629    :  
 630    :  bool Reorderer::Order::GetOriginalModulePath(const base::FilePath& path,
 631  E :                                               base::FilePath* module) {
 632  E :    std::string file_string;
 633  E :    if (!base::ReadFileToString(path, &file_string)) {
 634  E :      LOG(ERROR) << "Unable to read order file to string.";
 635  E :      return false;
 636    :    }
 637    :  
 638  E :    scoped_ptr<Value> value(base::JSONReader::Read(file_string));
 639  E :    if (value.get() == NULL || value->GetType() != Value::TYPE_DICTIONARY) {
 640  i :      LOG(ERROR) << "Order file does not contain a valid JSON dictionary.";
 641  i :      return false;
 642    :    }
 643    :    const DictionaryValue* outer_dict =
 644  E :        reinterpret_cast<const DictionaryValue*>(value.get());
 645    :  
 646  E :    std::string metadata_key("metadata");
 647  E :    const DictionaryValue* metadata_dict = NULL;
 648  E :    if (!outer_dict->GetDictionary(metadata_key, &metadata_dict)) {
 649  i :      LOG(ERROR) << "Order dictionary must contain 'metadata'.";
 650  i :      return false;
 651    :    }
 652    :  
 653  E :    pe::Metadata metadata;
 654  E :    if (!metadata.LoadFromJSON(*metadata_dict))
 655  i :      return false;
 656    :  
 657  E :    *module = base::FilePath(metadata.module_signature().path);
 658    :  
 659  E :    return true;
 660  E :  }
 661    :  
 662    :  Reorderer::UniqueTime::UniqueTime()
 663    :      : time_(),
 664    :        id_(0) {
 665    :  }
 666    :  
 667    :  Reorderer::UniqueTime::UniqueTime(const UniqueTime& other)
 668    :      : time_(other.time_),
 669  E :        id_(other.id_) {
 670  E :  }
 671    :  
 672    :  Reorderer::UniqueTime::UniqueTime(const base::Time& time)
 673    :      : time_(time),
 674  E :        id_(next_id_++) {
 675  E :  }
 676    :  
 677  E :  Reorderer::UniqueTime& Reorderer::UniqueTime::operator=(const UniqueTime& rhs) {
 678  E :    time_ = rhs.time_;
 679  E :    id_ = rhs.id_;
 680  E :    return *this;
 681  E :  }
 682    :  
 683  E :  int Reorderer::UniqueTime::compare(const UniqueTime& rhs) const {
 684  E :    if (time_ < rhs.time_)
 685  E :      return -1;
 686  E :    if (time_ > rhs.time_)
 687  E :      return 1;
 688  E :    if (id_ < rhs.id_)
 689  E :      return -1;
 690  E :    if (id_ > rhs.id_)
 691  E :      return 1;
 692  E :    return 0;
 693  E :  }
 694    :  
 695    :  size_t Reorderer::UniqueTime::next_id_ = 0;
 696    :  
 697    :  }  // namespace reorder

Coverage information generated Thu Jan 14 17:40:38 2016.