Coverage for /Syzygy/reorder/reorderer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
73.4%2373230.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 :      ListValue::const_iterator block_it = blocks->begin();
 322  E :      for (size_t block_idx = 0; block_idx != blocks->GetSize(); ++block_idx) {
 323  E :        const Value* block_value = NULL;
 324  E :        if (!blocks->Get(block_idx, &block_value)) {
 325  i :          LOG(ERROR) << "Failed to access item " << block_idx << ".";
 326  i :          return false;
 327    :        }
 328    :  
 329  E :        if (!LoadBlockSpec(image, block_value, &section_spec->blocks[block_idx]))
 330  i :          return false;
 331  E :      }
 332    :    }
 333    :  
 334  E :    return true;
 335  E :  }
 336    :  
 337    :  }  // namespace
 338    :  
 339    :  const size_t Reorderer::Order::SectionSpec::kNewSectionId = ~1;
 340    :  
 341    :  Reorderer::Reorderer(const FilePath& module_path,
 342    :                       const FilePath& instrumented_path,
 343    :                       const TraceFileList& trace_files,
 344    :                       Flags flags)
 345    :      : playback_(module_path, instrumented_path, trace_files),
 346    :        flags_(flags),
 347    :        code_block_entry_events_(0),
 348  E :        order_generator_(NULL) {
 349  E :  }
 350    :  
 351  E :  Reorderer::~Reorderer() {
 352  E :  }
 353    :  
 354    :  bool Reorderer::Reorder(OrderGenerator* order_generator,
 355    :                          Order* order,
 356    :                          PEFile* pe_file,
 357  E :                          ImageLayout* image) {
 358  E :    DCHECK(order_generator != NULL);
 359  E :    DCHECK(order != NULL);
 360    :  
 361  E :    DCHECK(order_generator_ == NULL);
 362  E :    order_generator_ = order_generator;
 363    :  
 364  E :    bool success = ReorderImpl(order, pe_file, image);
 365    :  
 366  E :    order_generator_ = NULL;
 367    :  
 368  E :    return success;
 369  E :  }
 370    :  
 371    :  bool Reorderer::ReorderImpl(Order* order,
 372    :                              PEFile* pe_file,
 373  E :                              ImageLayout* image) {
 374  E :    DCHECK(order != NULL);
 375  E :    DCHECK(order_generator_ != NULL);
 376    :  
 377  E :     if (!parser_.Init(this)) {
 378  i :      LOG(ERROR) << "Failed to initialize call trace parser.";
 379    :  
 380  i :      return false;
 381    :    }
 382    :  
 383  E :    if (!playback_.Init(pe_file, image, &parser_))
 384  i :      return false;
 385    :  
 386  E :    if (playback_.trace_files().size() > 0) {
 387  E :      LOG(INFO) << "Processing trace events.";
 388  E :      if (!parser_.Consume())
 389  i :        return false;
 390    :  
 391  E :      if (code_block_entry_events_ == 0) {
 392  i :        LOG(ERROR) << "No events originated from the given instrumented DLL.";
 393  i :        return false;
 394    :      }
 395    :    }
 396    :  
 397  E :    if (!CalculateReordering(order))
 398  i :      return false;
 399    :  
 400  E :    return true;
 401  E :  }
 402    :  
 403  E :  bool Reorderer::CalculateReordering(Order* order) {
 404  E :    DCHECK(order != NULL);
 405  E :    DCHECK(order_generator_ != NULL);
 406    :  
 407  E :    LOG(INFO) << "Calculating new order.";
 408    :    if (!order_generator_->CalculateReordering(*playback_.pe_file(),
 409    :                                               *playback_.image(),
 410    :                                               (flags_ & kFlagReorderCode) != 0,
 411    :                                               (flags_ & kFlagReorderData) != 0,
 412  E :                                               order))
 413  i :      return false;
 414    :  
 415    :    order->comment = base::StringPrintf("Generated using the %s.",
 416  E :                                        order_generator_->name().c_str());
 417    :  
 418  E :    return true;
 419  E :  }
 420    :  
 421  E :  void Reorderer::OnProcessEnded(base::Time time, DWORD process_id) {
 422    :    // Notify the order generator.
 423  E :    if (!order_generator_->OnProcessEnded(process_id, UniqueTime(time))) {
 424  i :      parser_.set_error_occurred(true);
 425  i :      return;
 426    :    }
 427    :  
 428    :    // Cleanup the local record for process_id.
 429  E :    ignore_result(matching_process_ids_.erase(process_id));
 430  E :  }
 431    :  
 432    :  // CallTraceEvents implementation.
 433    :  void Reorderer::OnFunctionEntry(base::Time time,
 434    :                                  DWORD process_id,
 435    :                                  DWORD thread_id,
 436  E :                                  const TraceEnterExitEventData* data) {
 437  E :    DCHECK(data != NULL);
 438    :  
 439    :    const BlockGraph::Block* block = playback_.FindFunctionBlock(process_id,
 440  E :                                                                 data->function);
 441    :  
 442  E :    if (block == NULL) {
 443  i :      parser_.set_error_occurred(true);
 444  i :      return;
 445    :    }
 446    :  
 447    :    // Get the time of the call. Since batched function calls come in with the
 448    :    // same time stamp, we rely on their relative ordering and UniqueTime's
 449    :    // incrementing ID to maintain relative order.
 450  E :    UniqueTime entry_time(time);
 451    :  
 452    :    // If this is the first call of interest by a given process, send an
 453    :    // OnProcessStarted event.
 454  E :    if (matching_process_ids_.insert(process_id).second) {
 455  E :      if (!order_generator_->OnProcessStarted(process_id, entry_time)) {
 456  i :        parser_.set_error_occurred(true);
 457  i :        return;
 458    :      }
 459    :    }
 460    :  
 461  E :    ++code_block_entry_events_;
 462    :    if (!order_generator_->OnCodeBlockEntry(block,
 463    :                                            block->addr(),
 464    :                                            process_id,
 465    :                                            thread_id,
 466  E :                                            entry_time)) {
 467  i :      parser_.set_error_occurred(true);
 468    :      return;
 469    :    }
 470  E :  }
 471    :  
 472    :  void Reorderer::OnBatchFunctionEntry(base::Time time,
 473    :                                       DWORD process_id,
 474    :                                       DWORD thread_id,
 475  E :                                       const TraceBatchEnterData* data) {
 476    :    // Explode the batch event into individual function entry events.
 477  E :    TraceEnterExitEventData new_data = {};
 478  E :    for (size_t i = 0; i < data->num_calls; ++i) {
 479  E :      new_data.function = data->calls[i].function;
 480  E :      OnFunctionEntry(time, process_id, thread_id, &new_data);
 481  E :    }
 482  E :  }
 483    :  
 484    :  bool Reorderer::Order::SerializeToJSON(const PEFile& pe,
 485    :                                         const FilePath &path,
 486  E :                                         bool pretty_print) const {
 487  E :    file_util::ScopedFILE file(file_util::OpenFile(path, "wb"));
 488  E :    if (file.get() == NULL)
 489  i :      return false;
 490  E :    core::JSONFileWriter json_file(file.get(), pretty_print);
 491  E :    return SerializeToJSON(pe, &json_file);
 492  E :  }
 493    :  
 494    :  bool Reorderer::Order::SerializeToJSON(const PEFile& pe,
 495  E :                                         core::JSONFileWriter* json_file) const {
 496  E :    DCHECK(json_file != NULL);
 497    :  
 498    :    // Open the top-level dictionary and the metadata dictionary.
 499  E :    if (!json_file->OpenDict())
 500  i :      return false;
 501    :  
 502    :    // Output the filecomment.
 503    :    if (!json_file->OutputKey(kCommentKey) ||
 504  E :        !json_file->OutputString(comment)) {
 505  i :      return false;
 506    :    }
 507    :  
 508    :    // Output metadata.
 509  E :    PEFile::Signature orig_sig;
 510  E :    pe.GetSignature(&orig_sig);
 511  E :    pe::Metadata metadata;
 512    :    if (!metadata.Init(orig_sig) ||
 513    :        !json_file->OutputKey(kMetadataKey) ||
 514  E :        !metadata.SaveToJSON(json_file)) {
 515  i :      return false;
 516    :    }
 517    :  
 518    :    // Open list of sections.
 519    :    if (!json_file->OutputKey(kSectionsKey) ||
 520  E :        !json_file->OpenList()) {
 521  i :      return false;
 522    :    }
 523    :  
 524    :    // Output the individual block lists.
 525  E :    SectionSpecVector::const_iterator it = sections.begin();
 526  E :    for (; it != sections.end(); ++it) {
 527  E :      const SectionSpec& section_spec = *it;
 528  E :      if (section_spec.blocks.empty())
 529  i :        continue;
 530    :  
 531  E :      if (!OutputSectionSpec(section_spec, json_file))
 532  i :        return false;
 533  E :    }
 534    :  
 535    :    // Close the list of sections.
 536  E :    if (!json_file->CloseList())
 537  i :      return false;
 538    :  
 539    :    // Close the outermost dictionary.
 540  E :    if (!json_file->CloseDict())
 541  i :      return false;
 542    :  
 543  E :    return true;
 544  E :  }
 545    :  
 546    :  bool Reorderer::Order::LoadFromJSON(const PEFile& pe,
 547    :                                      const ImageLayout& image,
 548  E :                                      const FilePath& path) {
 549  E :    std::string file_string;
 550  E :    if (!file_util::ReadFileToString(path, &file_string)) {
 551  i :      LOG(ERROR) << "Unable to read order file to string";
 552  i :      return false;
 553    :    }
 554    :  
 555    :    // Read in the JSON file. It should be a dictionary.
 556  E :    const DictionaryValue* outer_dict = NULL;
 557  E :    scoped_ptr<Value> value(base::JSONReader::Read(file_string, false));
 558  E :    if (value.get() == NULL || !value->GetAsDictionary(&outer_dict)) {
 559  i :      LOG(ERROR) << "Order file does not contain a valid JSON dictionary.";
 560  i :      return false;
 561    :    }
 562    :  
 563    :    // Load the metadata from the order file, and ensure it is consistent with
 564    :    // the signature of the module the ordering is being applied to.
 565  E :    pe::Metadata metadata;
 566  E :    PEFile::Signature pe_sig;
 567  E :    pe.GetSignature(&pe_sig);
 568  E :    const DictionaryValue* metadata_dict = NULL;
 569    :    if (!outer_dict->GetDictionary(kMetadataKey, &metadata_dict) ||
 570    :        !metadata.LoadFromJSON(*metadata_dict) ||
 571  E :        !metadata.IsConsistent(pe_sig)) {
 572  i :      LOG(ERROR) << "Missing, invalid, or inconsistent " << kMetadataKey << ".";
 573  i :      return false;
 574    :    }
 575    :  
 576    :    // Load the comments field.
 577    :    if (outer_dict->HasKey(kCommentKey) &&
 578  E :        !outer_dict->GetString(kCommentKey, &comment)) {
 579  i :      LOG(ERROR) << "Invalid " << kCommentKey << " value. Must be a string.";
 580  i :      return false;
 581    :    }
 582    :  
 583    :    // Grab the sections list.
 584  E :    const ListValue* order = NULL;
 585  E :    if (!outer_dict->GetList(kSectionsKey, &order)) {
 586  i :      LOG(ERROR) << "Missing or invalid " << kSectionsKey << ".";
 587  i :      return false;
 588    :    }
 589    :  
 590    :    // Allocate the expected number of sections.
 591  E :    sections.clear();
 592    :  
 593    :    // Iterate through the elements of the list. They should each be dictionaries
 594    :    // representing a single section. We'll also track the sections descriptions
 595    :    // we have already seen.
 596  E :    std::set<size_t> seen_section_ids;
 597  E :    sections.resize(order->GetSize());
 598  E :    for (size_t index = 0; index < order->GetSize(); ++index) {
 599  E :      const DictionaryValue* section = NULL;
 600  E :      if (!order->GetDictionary(index, &section)) {
 601  i :        LOG(ERROR) << "Item " << index << "of " << kSectionsKey
 602    :                   << " list is not a dictionary.";
 603  i :        return false;
 604    :      }
 605    :  
 606  E :      if (!LoadSectionSpec(image, section, &sections[index], &seen_section_ids))
 607  i :        return false;
 608  E :    }
 609    :  
 610  E :    return true;
 611  E :  }
 612    :  
 613    :  bool Reorderer::Order::GetOriginalModulePath(const FilePath& path,
 614  E :                                               FilePath* module) {
 615  E :    std::string file_string;
 616  E :    if (!file_util::ReadFileToString(path, &file_string)) {
 617  E :      LOG(ERROR) << "Unable to read order file to string.";
 618  E :      return false;
 619    :    }
 620    :  
 621  E :    scoped_ptr<Value> value(base::JSONReader::Read(file_string, false));
 622  E :    if (value.get() == NULL || value->GetType() != Value::TYPE_DICTIONARY) {
 623  i :      LOG(ERROR) << "Order file does not contain a valid JSON dictionary.";
 624  i :      return false;
 625    :    }
 626    :    const DictionaryValue* outer_dict =
 627  E :        reinterpret_cast<const DictionaryValue*>(value.get());
 628    :  
 629  E :    std::string metadata_key("metadata");
 630  E :    const DictionaryValue* metadata_dict = NULL;
 631  E :    if (!outer_dict->GetDictionary(metadata_key, &metadata_dict)) {
 632  i :      LOG(ERROR) << "Order dictionary must contain 'metadata'.";
 633  i :      return false;
 634    :    }
 635    :  
 636  E :    pe::Metadata metadata;
 637  E :    if (!metadata.LoadFromJSON(*metadata_dict))
 638  i :      return false;
 639    :  
 640  E :    *module = FilePath(metadata.module_signature().path);
 641    :  
 642  E :    return true;
 643  E :  }
 644    :  
 645    :  Reorderer::UniqueTime::UniqueTime()
 646    :      : time_(),
 647    :        id_(0) {
 648    :  }
 649    :  
 650    :  Reorderer::UniqueTime::UniqueTime(const UniqueTime& other)
 651    :      : time_(other.time_),
 652  E :        id_(other.id_) {
 653  E :  }
 654    :  
 655    :  Reorderer::UniqueTime::UniqueTime(const base::Time& time)
 656    :      : time_(time),
 657  E :        id_(next_id_++) {
 658  E :  }
 659    :  
 660  E :  Reorderer::UniqueTime& Reorderer::UniqueTime::operator=(const UniqueTime& rhs) {
 661  E :    time_ = rhs.time_;
 662  E :    id_ = rhs.id_;
 663  E :    return *this;
 664  E :  }
 665    :  
 666  E :  int Reorderer::UniqueTime::compare(const UniqueTime& rhs) const {
 667  E :    if (time_ < rhs.time_)
 668  i :      return -1;
 669  E :    if (time_ > rhs.time_)
 670  i :      return 1;
 671  E :    if (id_ < rhs.id_)
 672  E :      return -1;
 673  E :    if (id_ > rhs.id_)
 674  E :      return 1;
 675  E :    return 0;
 676  E :  }
 677    :  
 678    :  size_t Reorderer::UniqueTime::next_id_ = 0;
 679    :  
 680    :  }  // namespace reorder

Coverage information generated Thu Mar 14 11:53:36 2013.