Coverage for /Syzygy/reorder/reorderer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
73.8%2373210.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/file_util.h"
  18    :  #include "base/stringprintf.h"
  19    :  #include "base/utf_string_conversions.h"
  20    :  #include "base/values.h"
  21    :  #include "base/json/json_reader.h"
  22    :  #include "base/json/string_escape.h"
  23    :  #include "syzygy/block_graph/block_graph.h"
  24    :  #include "syzygy/common/defs.h"
  25    :  #include "syzygy/common/syzygy_version.h"
  26    :  #include "syzygy/core/json_file_writer.h"
  27    :  #include "syzygy/core/serialization.h"
  28    :  #include "syzygy/pdb/omap.h"
  29    :  #include "syzygy/pe/find.h"
  30    :  #include "syzygy/pe/metadata.h"
  31    :  #include "syzygy/pe/pe_file.h"
  32    :  #include "syzygy/pe/pe_utils.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 :    if (rva_list != NULL && !rva_list->empty()) {
 211  E :      block_spec->basic_block_offsets.reserve(rva_list->GetSize());
 212  E :      for (size_t i = 0; i < rva_list->GetSize(); ++i) {
 213  E :        int offset = 0;
 214  E :        if (!rva_list->GetInteger(i, &offset)) {
 215  i :          LOG(ERROR) << "Unexpected value for basic-block offset #" << i
 216    :                     << " of " << address << " [" << block->name() << "].";
 217  i :          block_spec->basic_block_offsets.clear();
 218  i :          return false;
 219    :        }
 220    :        if (offset < 0 ||
 221  E :            static_cast<BlockGraph::Size>(offset) >= block->size()) {
 222  i :          LOG(ERROR) << "Offset " << offset << " falls outside block range [0-"
 223    :                     << (block->size() - 1) << "] for " << block->name();
 224  i :          return false;
 225    :        }
 226  E :        block_spec->basic_block_offsets.push_back(offset);
 227  E :      }
 228    :    }
 229    :  
 230  E :    block_spec->block = block;
 231  E :    return true;
 232  E :  }
 233    :  
 234    :  bool LoadSectionSpec(const pe::ImageLayout& image,
 235    :                       const DictionaryValue* section_value,
 236    :                       Reorderer::Order::SectionSpec* section_spec,
 237  E :                       std::set<size_t>* seen_section_ids) {
 238  E :    DCHECK(section_value != NULL);
 239  E :    DCHECK(section_spec != NULL);
 240  E :    DCHECK(seen_section_ids != NULL);
 241    :  
 242    :    // Some keys we'll refer to multiple times below.
 243  E :    const std::string section_id_key(kSectionIdKey);
 244  E :    const std::string section_name_key(kSectionNameKey);
 245  E :    const std::string section_characteristics_key(kSectionCharacteristicsKey);
 246  E :    const std::string blocks_key(kBlocksKey);
 247    :  
 248    :    // Get the section id, if given.
 249  E :    int tmp_section_id = Reorderer::Order::SectionSpec::kNewSectionId;
 250    :    if (section_value->HasKey(section_id_key) &&
 251  E :        !section_value->GetInteger(section_id_key, &tmp_section_id)) {
 252  i :      LOG(ERROR) << "Invalid value for " << section_id_key << ".";
 253  i :      return false;
 254    :    }
 255    :  
 256    :    // Lookup the original section by id, if the id was given. Populate the
 257    :    // section metadata based on the original section info. The other keys
 258    :    // will be inspected below to see if any of the metadata needs to be
 259    :    // over-ridden.
 260  E :    section_spec->id = tmp_section_id;
 261  E :    if (section_spec->id != Reorderer::Order::SectionSpec::kNewSectionId) {
 262    :      // Lookup the section in the original image layout.
 263  E :      if (section_spec->id < 0 || section_spec->id > image.sections.size()) {
 264  i :        LOG(ERROR) << "Invalid section id: " << section_spec->id << ".";
 265  i :        return false;
 266    :      }
 267    :  
 268    :      // Make sure this section id does not already exist.
 269  E :      if (!seen_section_ids->insert(section_spec->id).second) {
 270  i :        LOG(ERROR) << "Section ID " << section_spec->id << " redefined.";
 271  i :        return false;
 272    :      }
 273    :  
 274    :      // Copy the metadata into the section spec.
 275  E :      section_spec->name = image.sections[section_spec->id].name;
 276    :      section_spec->characteristics =
 277  E :          image.sections[section_spec->id].characteristics;
 278    :    }
 279    :  
 280    :    // Possibly over-ride the section name.
 281    :    if (section_value->HasKey(section_name_key) &&
 282  E :        !section_value->GetString(section_name_key, &section_spec->name)) {
 283  i :      LOG(ERROR) << "Invalid value for " << section_name_key << ".";
 284  i :      return false;
 285    :    }
 286    :  
 287    :    // Make sure we've got a section name. This may have come from either the
 288    :    // the original image (via the section id) or explicitly from the section
 289    :    // name key.
 290  E :    if (section_spec->name.empty()) {
 291  i :      LOG(ERROR) << "Missing a value for the section name. Either a valid "
 292    :                 << section_id_key << " or valid " << section_name_key
 293    :                 << " is required.";
 294  i :      return false;
 295    :    }
 296    :  
 297    :    // Possibly over-ride the section characteristics. The characteristics are
 298    :    // required if the section was not given by id.
 299    :    if (section_spec->id == Reorderer::Order::SectionSpec::kNewSectionId ||
 300  E :        section_value->HasKey(section_characteristics_key)) {
 301  E :      int tmp_characteristics = 0;
 302    :      if (!section_value->GetInteger(section_characteristics_key,
 303  E :                                     &tmp_characteristics)) {
 304  i :        LOG(ERROR) << "Missing or invalid value for "
 305    :                   << section_characteristics_key << ".";
 306  i :        return false;
 307    :      }
 308  E :      section_spec->characteristics = tmp_characteristics;
 309    :    }
 310    :  
 311    :    // Get the list of block specifications.
 312  E :    const ListValue* blocks = NULL;
 313  E :    if (!section_value->GetList(blocks_key, &blocks)) {
 314  i :      LOG(ERROR) << "Invalid or missing value for " << blocks_key << ".";
 315  i :      return false;
 316    :    }
 317    :  
 318  E :    if (!blocks->empty()) {
 319    :      // Populate the block spec vector.
 320  E :      section_spec->blocks.resize(blocks->GetSize());
 321  E :      for (size_t block_idx = 0; block_idx != blocks->GetSize(); ++block_idx) {
 322  E :        const Value* block_value = NULL;
 323  E :        if (!blocks->Get(block_idx, &block_value)) {
 324  i :          LOG(ERROR) << "Failed to access item " << block_idx << ".";
 325  i :          return false;
 326    :        }
 327    :  
 328  E :        if (!LoadBlockSpec(image, block_value, &section_spec->blocks[block_idx]))
 329  i :          return false;
 330  E :      }
 331    :    }
 332    :  
 333  E :    return true;
 334  E :  }
 335    :  
 336    :  }  // namespace
 337    :  
 338    :  const size_t Reorderer::Order::SectionSpec::kNewSectionId = ~1;
 339    :  
 340    :  Reorderer::Reorderer(const base::FilePath& module_path,
 341    :                       const base::FilePath& instrumented_path,
 342    :                       const TraceFileList& trace_files,
 343    :                       Flags flags)
 344    :      : playback_(module_path, instrumented_path, trace_files),
 345    :        flags_(flags),
 346    :        code_block_entry_events_(0),
 347  E :        order_generator_(NULL) {
 348  E :  }
 349    :  
 350  E :  Reorderer::~Reorderer() {
 351  E :  }
 352    :  
 353    :  bool Reorderer::Reorder(OrderGenerator* order_generator,
 354    :                          Order* order,
 355    :                          PEFile* pe_file,
 356  E :                          ImageLayout* image) {
 357  E :    DCHECK(order_generator != NULL);
 358  E :    DCHECK(order != NULL);
 359    :  
 360  E :    DCHECK(order_generator_ == NULL);
 361  E :    order_generator_ = order_generator;
 362    :  
 363  E :    bool success = ReorderImpl(order, pe_file, image);
 364    :  
 365  E :    order_generator_ = NULL;
 366    :  
 367  E :    return success;
 368  E :  }
 369    :  
 370    :  bool Reorderer::ReorderImpl(Order* order,
 371    :                              PEFile* pe_file,
 372  E :                              ImageLayout* image) {
 373  E :    DCHECK(order != NULL);
 374  E :    DCHECK(order_generator_ != NULL);
 375    :  
 376  E :    if (!parser_.Init(this)) {
 377  i :      LOG(ERROR) << "Failed to initialize call trace parser.";
 378  i :      return false;
 379    :    }
 380    :  
 381  E :    if (!playback_.Init(pe_file, image, &parser_))
 382  i :      return false;
 383    :  
 384  E :    if (playback_.trace_files().size() > 0) {
 385  E :      LOG(INFO) << "Processing trace events.";
 386  E :      if (!parser_.Consume())
 387  i :        return false;
 388    :  
 389  E :      if (code_block_entry_events_ == 0) {
 390  i :        LOG(ERROR) << "No events originated from the given instrumented DLL.";
 391  i :        return false;
 392    :      }
 393    :    }
 394    :  
 395  E :    if (!CalculateReordering(order))
 396  i :      return false;
 397    :  
 398  E :    return true;
 399  E :  }
 400    :  
 401  E :  bool Reorderer::CalculateReordering(Order* order) {
 402  E :    DCHECK(order != NULL);
 403  E :    DCHECK(order_generator_ != NULL);
 404    :  
 405  E :    LOG(INFO) << "Calculating new order.";
 406    :    if (!order_generator_->CalculateReordering(*playback_.pe_file(),
 407    :                                               *playback_.image(),
 408    :                                               (flags_ & kFlagReorderCode) != 0,
 409    :                                               (flags_ & kFlagReorderData) != 0,
 410  E :                                               order))
 411  i :      return false;
 412    :  
 413    :    order->comment = base::StringPrintf("Generated using the %s.",
 414  E :                                        order_generator_->name().c_str());
 415    :  
 416  E :    return true;
 417  E :  }
 418    :  
 419    :  void Reorderer::OnProcessStarted(
 420  E :      base::Time time, DWORD process_id, const TraceSystemInfo* data) {
 421  E :    UniqueTime entry_time(time);
 422    :  
 423  E :    if (!order_generator_->OnProcessStarted(process_id, entry_time)) {
 424  i :      parser_.set_error_occurred(true);
 425    :      return;
 426    :    }
 427  E :  }
 428    :  
 429  E :  void Reorderer::OnProcessEnded(base::Time time, DWORD process_id) {
 430    :    // Notify the order generator.
 431  E :    if (!order_generator_->OnProcessEnded(process_id, UniqueTime(time))) {
 432  i :      parser_.set_error_occurred(true);
 433    :      return;
 434    :    }
 435  E :  }
 436    :  
 437    :  // CallTraceEvents implementation.
 438    :  void Reorderer::OnFunctionEntry(base::Time time,
 439    :                                  DWORD process_id,
 440    :                                  DWORD thread_id,
 441  E :                                  const TraceEnterExitEventData* data) {
 442  E :    DCHECK(data != NULL);
 443    :  
 444    :    const BlockGraph::Block* block = playback_.FindFunctionBlock(process_id,
 445  E :                                                                 data->function);
 446    :  
 447  E :    if (block == NULL) {
 448  i :      parser_.set_error_occurred(true);
 449  i :      return;
 450    :    }
 451    :  
 452    :    // Get the time of the call. Since batched function calls come in with the
 453    :    // same time stamp, we rely on their relative ordering and UniqueTime's
 454    :    // incrementing ID to maintain relative order.
 455  E :    UniqueTime entry_time(time);
 456    :  
 457  E :    ++code_block_entry_events_;
 458    :    if (!order_generator_->OnCodeBlockEntry(block,
 459    :                                            block->addr(),
 460    :                                            process_id,
 461    :                                            thread_id,
 462  E :                                            entry_time)) {
 463  i :      parser_.set_error_occurred(true);
 464    :      return;
 465    :    }
 466  E :  }
 467    :  
 468    :  void Reorderer::OnBatchFunctionEntry(base::Time time,
 469    :                                       DWORD process_id,
 470    :                                       DWORD thread_id,
 471  E :                                       const TraceBatchEnterData* data) {
 472    :    // Explode the batch event into individual function entry events.
 473  E :    TraceEnterExitEventData new_data = {};
 474  E :    for (size_t i = 0; i < data->num_calls; ++i) {
 475  E :      new_data.function = data->calls[i].function;
 476  E :      OnFunctionEntry(time, process_id, thread_id, &new_data);
 477  E :    }
 478  E :  }
 479    :  
 480    :  bool Reorderer::Order::SerializeToJSON(const PEFile& pe,
 481    :                                         const base::FilePath &path,
 482  E :                                         bool pretty_print) const {
 483  E :    file_util::ScopedFILE file(file_util::OpenFile(path, "wb"));
 484  E :    if (file.get() == NULL)
 485  i :      return false;
 486  E :    core::JSONFileWriter json_file(file.get(), pretty_print);
 487  E :    return SerializeToJSON(pe, &json_file);
 488  E :  }
 489    :  
 490    :  bool Reorderer::Order::SerializeToJSON(const PEFile& pe,
 491  E :                                         core::JSONFileWriter* json_file) const {
 492  E :    DCHECK(json_file != NULL);
 493    :  
 494    :    // Open the top-level dictionary and the metadata dictionary.
 495  E :    if (!json_file->OpenDict())
 496  i :      return false;
 497    :  
 498    :    // Output the filecomment.
 499    :    if (!json_file->OutputKey(kCommentKey) ||
 500  E :        !json_file->OutputString(comment)) {
 501  i :      return false;
 502    :    }
 503    :  
 504    :    // Output metadata.
 505  E :    PEFile::Signature orig_sig;
 506  E :    pe.GetSignature(&orig_sig);
 507  E :    pe::Metadata metadata;
 508    :    if (!metadata.Init(orig_sig) ||
 509    :        !json_file->OutputKey(kMetadataKey) ||
 510  E :        !metadata.SaveToJSON(json_file)) {
 511  i :      return false;
 512    :    }
 513    :  
 514    :    // Open list of sections.
 515    :    if (!json_file->OutputKey(kSectionsKey) ||
 516  E :        !json_file->OpenList()) {
 517  i :      return false;
 518    :    }
 519    :  
 520    :    // Output the individual block lists.
 521  E :    SectionSpecVector::const_iterator it = sections.begin();
 522  E :    for (; it != sections.end(); ++it) {
 523  E :      const SectionSpec& section_spec = *it;
 524  E :      if (section_spec.blocks.empty())
 525  i :        continue;
 526    :  
 527  E :      if (!OutputSectionSpec(section_spec, json_file))
 528  i :        return false;
 529  E :    }
 530    :  
 531    :    // Close the list of sections.
 532  E :    if (!json_file->CloseList())
 533  i :      return false;
 534    :  
 535    :    // Close the outermost dictionary.
 536  E :    if (!json_file->CloseDict())
 537  i :      return false;
 538    :  
 539  E :    return true;
 540  E :  }
 541    :  
 542    :  bool Reorderer::Order::LoadFromJSON(const PEFile& pe,
 543    :                                      const ImageLayout& image,
 544  E :                                      const base::FilePath& path) {
 545  E :    std::string file_string;
 546  E :    if (!file_util::ReadFileToString(path, &file_string)) {
 547  i :      LOG(ERROR) << "Unable to read order file to string";
 548  i :      return false;
 549    :    }
 550    :  
 551    :    // Read in the JSON file. It should be a dictionary.
 552  E :    const DictionaryValue* outer_dict = NULL;
 553  E :    scoped_ptr<Value> value(base::JSONReader::Read(file_string));
 554  E :    if (value.get() == NULL || !value->GetAsDictionary(&outer_dict)) {
 555  i :      LOG(ERROR) << "Order file does not contain a valid JSON dictionary.";
 556  i :      return false;
 557    :    }
 558    :  
 559    :    // Load the metadata from the order file, and ensure it is consistent with
 560    :    // the signature of the module the ordering is being applied to.
 561  E :    pe::Metadata metadata;
 562  E :    PEFile::Signature pe_sig;
 563  E :    pe.GetSignature(&pe_sig);
 564  E :    const DictionaryValue* metadata_dict = NULL;
 565    :    if (!outer_dict->GetDictionary(kMetadataKey, &metadata_dict) ||
 566    :        !metadata.LoadFromJSON(*metadata_dict) ||
 567  E :        !metadata.IsConsistent(pe_sig)) {
 568  i :      LOG(ERROR) << "Missing, invalid, or inconsistent " << kMetadataKey << ".";
 569  i :      return false;
 570    :    }
 571    :  
 572    :    // Load the comments field.
 573    :    if (outer_dict->HasKey(kCommentKey) &&
 574  E :        !outer_dict->GetString(kCommentKey, &comment)) {
 575  i :      LOG(ERROR) << "Invalid " << kCommentKey << " value. Must be a string.";
 576  i :      return false;
 577    :    }
 578    :  
 579    :    // Grab the sections list.
 580  E :    const ListValue* order = NULL;
 581  E :    if (!outer_dict->GetList(kSectionsKey, &order)) {
 582  i :      LOG(ERROR) << "Missing or invalid " << kSectionsKey << ".";
 583  i :      return false;
 584    :    }
 585    :  
 586    :    // Allocate the expected number of sections.
 587  E :    sections.clear();
 588    :  
 589    :    // Iterate through the elements of the list. They should each be dictionaries
 590    :    // representing a single section. We'll also track the sections descriptions
 591    :    // we have already seen.
 592  E :    std::set<size_t> seen_section_ids;
 593  E :    sections.resize(order->GetSize());
 594  E :    for (size_t index = 0; index < order->GetSize(); ++index) {
 595  E :      const DictionaryValue* section = NULL;
 596  E :      if (!order->GetDictionary(index, &section)) {
 597  i :        LOG(ERROR) << "Item " << index << "of " << kSectionsKey
 598    :                   << " list is not a dictionary.";
 599  i :        return false;
 600    :      }
 601    :  
 602  E :      if (!LoadSectionSpec(image, section, &sections[index], &seen_section_ids))
 603  i :        return false;
 604  E :    }
 605    :  
 606  E :    return true;
 607  E :  }
 608    :  
 609    :  bool Reorderer::Order::GetOriginalModulePath(const base::FilePath& path,
 610  E :                                               base::FilePath* module) {
 611  E :    std::string file_string;
 612  E :    if (!file_util::ReadFileToString(path, &file_string)) {
 613  E :      LOG(ERROR) << "Unable to read order file to string.";
 614  E :      return false;
 615    :    }
 616    :  
 617  E :    scoped_ptr<Value> value(base::JSONReader::Read(file_string));
 618  E :    if (value.get() == NULL || value->GetType() != Value::TYPE_DICTIONARY) {
 619  i :      LOG(ERROR) << "Order file does not contain a valid JSON dictionary.";
 620  i :      return false;
 621    :    }
 622    :    const DictionaryValue* outer_dict =
 623  E :        reinterpret_cast<const DictionaryValue*>(value.get());
 624    :  
 625  E :    std::string metadata_key("metadata");
 626  E :    const DictionaryValue* metadata_dict = NULL;
 627  E :    if (!outer_dict->GetDictionary(metadata_key, &metadata_dict)) {
 628  i :      LOG(ERROR) << "Order dictionary must contain 'metadata'.";
 629  i :      return false;
 630    :    }
 631    :  
 632  E :    pe::Metadata metadata;
 633  E :    if (!metadata.LoadFromJSON(*metadata_dict))
 634  i :      return false;
 635    :  
 636  E :    *module = base::FilePath(metadata.module_signature().path);
 637    :  
 638  E :    return true;
 639  E :  }
 640    :  
 641    :  Reorderer::UniqueTime::UniqueTime()
 642    :      : time_(),
 643    :        id_(0) {
 644    :  }
 645    :  
 646    :  Reorderer::UniqueTime::UniqueTime(const UniqueTime& other)
 647    :      : time_(other.time_),
 648  E :        id_(other.id_) {
 649  E :  }
 650    :  
 651    :  Reorderer::UniqueTime::UniqueTime(const base::Time& time)
 652    :      : time_(time),
 653  E :        id_(next_id_++) {
 654  E :  }
 655    :  
 656  E :  Reorderer::UniqueTime& Reorderer::UniqueTime::operator=(const UniqueTime& rhs) {
 657  E :    time_ = rhs.time_;
 658  E :    id_ = rhs.id_;
 659  E :    return *this;
 660  E :  }
 661    :  
 662  E :  int Reorderer::UniqueTime::compare(const UniqueTime& rhs) const {
 663  E :    if (time_ < rhs.time_)
 664  i :      return -1;
 665  E :    if (time_ > rhs.time_)
 666  i :      return 1;
 667  E :    if (id_ < rhs.id_)
 668  E :      return -1;
 669  E :    if (id_ > rhs.id_)
 670  E :      return 1;
 671  E :    return 0;
 672  E :  }
 673    :  
 674    :  size_t Reorderer::UniqueTime::next_id_ = 0;
 675    :  
 676    :  }  // namespace reorder

Coverage information generated Thu Jul 04 09:34:53 2013.