Coverage for /Syzygy/pe/coff_utils.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
88.3%1281450.C++source

Line-by-line coverage:

   1    :  // Copyright 2014 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/coff_utils.h"
  16    :  
  17    :  #include "base/bind.h"
  18    :  #include "syzygy/block_graph/typed_block.h"
  19    :  
  20    :  namespace pe {
  21    :  
  22    :  namespace {
  23    :  
  24    :  using block_graph::BlockGraph;
  25    :  using block_graph::TypedBlock;
  26    :  
  27    :  // This is used by FindCoffSymbol as a callback function with VisitCoffSymbols.
  28    :  bool VisitCoffSymbol(const base::StringPiece& symbol_name,
  29    :                       CoffSymbolOffsets* symbol_offsets,
  30    :                       BlockGraph::Block* symbols_block,
  31    :                       BlockGraph::Block* strings_block,
  32  E :                       BlockGraph::Offset symbol_offset) {
  33  E :    DCHECK_NE(reinterpret_cast<CoffSymbolOffsets*>(NULL), symbol_offsets);
  34  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
  35  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
  36    :  
  37    :    // Record the offset for matching names.
  38  E :    base::StringPiece name;
  39  E :    if (!GetCoffSymbolName(symbols_block, strings_block, symbol_offset, &name))
  40  i :      return false;
  41  E :    if (name != symbol_name)
  42  E :      return true;
  43  E :    symbol_offsets->insert(symbol_offset);
  44  E :    return true;
  45  E :  }
  46    :  
  47    :  bool AddSymbolToNameOffsetMap(CoffSymbolNameOffsetMap* map,
  48    :                                BlockGraph::Block* symbols_block,
  49    :                                BlockGraph::Block* strings_block,
  50  E :                                BlockGraph::Offset symbol_offset) {
  51  E :    DCHECK_NE(reinterpret_cast<CoffSymbolNameOffsetMap*>(NULL), map);
  52  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
  53  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
  54    :  
  55  E :    base::StringPiece name;
  56  E :    if (!GetCoffSymbolName(symbols_block, strings_block, symbol_offset, &name))
  57  i :      return false;
  58    :  
  59  E :    std::string name2 = name.as_string();
  60    :    CoffSymbolNameOffsetMap::iterator it = map->insert(
  61  E :        std::make_pair(name2, CoffSymbolOffsets())).first;
  62  E :    DCHECK(it != map->end());
  63  E :    it->second.insert(symbol_offset);
  64  E :    return true;
  65  E :  }
  66    :  
  67    :  }  // namespace
  68    :  
  69    :  bool FindCoffSpecialBlocks(BlockGraph* block_graph,
  70    :                             BlockGraph::Block** headers_block,
  71    :                             BlockGraph::Block** symbols_block,
  72  E :                             BlockGraph::Block** strings_block) {
  73  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
  74    :  
  75  E :    bool headers_block_found = false;
  76  E :    bool symbols_block_found = false;
  77  E :    bool strings_block_found = false;
  78    :  
  79    :    // Walk through all the blocks once to find all the special blocks.
  80  E :    BlockGraph::BlockMap& blocks = block_graph->blocks_mutable();
  81  E :    BlockGraph::BlockMap::iterator it = blocks.begin();
  82  E :    for (; it != blocks.end(); ++it) {
  83  E :      if ((it->second.attributes() & BlockGraph::COFF_HEADERS) != 0) {
  84  E :        if (headers_block != NULL)
  85  E :          *headers_block = &it->second;
  86  E :        headers_block_found = true;
  87  E :      } else if ((it->second.attributes() & BlockGraph::COFF_SYMBOL_TABLE) != 0) {
  88  E :        if (symbols_block != NULL)
  89  E :          *symbols_block = &it->second;
  90  E :        symbols_block_found = true;
  91  E :      } else if ((it->second.attributes() & BlockGraph::COFF_STRING_TABLE) != 0) {
  92  E :        if (strings_block != NULL)
  93  E :          *strings_block = &it->second;
  94  E :        strings_block_found = true;
  95    :      }
  96  E :    }
  97    :  
  98  E :    if (!headers_block_found || !symbols_block_found || !strings_block_found)
  99  E :      return false;
 100  E :    return true;
 101  E :  }
 102    :  
 103    :  bool GetCoffSymbolName(const BlockGraph::Block* symbols_block,
 104    :                         const BlockGraph::Block* strings_block,
 105    :                         BlockGraph::Offset symbol_offset,
 106  E :                         base::StringPiece* name) {
 107  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
 108  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
 109  E :    DCHECK_LE(0, symbol_offset);
 110  E :    DCHECK_GE(symbols_block->data_size(), symbol_offset + sizeof(IMAGE_SYMBOL));
 111  E :    DCHECK_NE(reinterpret_cast<base::StringPiece*>(NULL), name);
 112    :  
 113    :    // Cast to a raw symbol.
 114    :    const IMAGE_SYMBOL* symbol = reinterpret_cast<const IMAGE_SYMBOL*>(
 115  E :        symbols_block->data() + symbol_offset);
 116    :  
 117    :    // If the symbol name is short enough it's stored directly in the symbol
 118    :    // record.
 119  E :    if (symbol->N.Name.Short != 0) {
 120    :      // The string isn't necessarily zero terminated if it uses the whole
 121    :      // length, so we determine it's length using a cap.
 122  E :      const char* s = reinterpret_cast<const char*>(&symbol->N.ShortName);
 123    :  
 124  E :      size_t length = ::strnlen(s, sizeof(symbol->N.ShortName));
 125  E :      *name = base::StringPiece(s, length);
 126  E :      return true;
 127    :    }
 128    :  
 129    :    // Otherwise the name is stored in the string table, and is zero
 130    :    // terminated.
 131  E :    size_t i = symbol->N.Name.Long;
 132  E :    if (i >= strings_block->size()) {
 133  i :      LOG(ERROR) << "COFF symbol name outside of strings block.";
 134  i :      return false;
 135    :    }
 136    :  
 137    :    // If the string is outside of the data portion of the block then it is
 138    :    // implicitly zero length.
 139  E :    if (i >= strings_block->data_size()) {
 140  i :      *name = base::StringPiece(NULL, 0);
 141  i :      return true;
 142    :    }
 143    :  
 144    :    // Determine the length of the symbol name.
 145    :    const char* s = reinterpret_cast<const char*>(
 146  E :        strings_block->data() + symbol->N.Name.Long);
 147  E :    size_t max_length = strings_block->data_size() - symbol->N.Name.Long;
 148  E :    size_t length = ::strnlen(s, max_length);
 149    :  
 150    :    // Ensure the terminating zero is actually in the strings block.
 151    :    if (length == max_length &&
 152  E :        strings_block->data_size() == strings_block->size()) {
 153  i :      LOG(ERROR) << "COFF symbol name has no terminating NUL.";
 154  i :      return false;
 155    :    }
 156    :  
 157  E :    *name = base::StringPiece(s, length);
 158  E :    return true;
 159  E :  }
 160    :  
 161    :  bool VisitCoffSymbols(const VisitCoffSymbolCallback& callback,
 162    :                        BlockGraph::Block* symbols_block,
 163  E :                        BlockGraph::Block* strings_block) {
 164  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
 165  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
 166    :  
 167  E :    TypedBlock<IMAGE_SYMBOL> symbols;
 168  E :    if (!symbols.Init(0, symbols_block)) {
 169  i :      LOG(ERROR) << "Unable to cast symbol table.";
 170  i :      return false;
 171    :    }
 172    :  
 173  E :    size_t num_symbols = symbols.ElementCount();
 174  E :    for (size_t i = 0; i < num_symbols; i += 1 + symbols[i].NumberOfAuxSymbols) {
 175  E :      size_t symbol_offset = i * sizeof(IMAGE_SYMBOL);
 176  E :      if (!callback.Run(symbols_block, strings_block, symbol_offset))
 177  E :        return false;
 178  E :    }
 179    :  
 180  E :    return true;
 181  E :  }
 182    :  
 183    :  bool VisitCoffSymbols(const VisitCoffSymbolCallback& callback,
 184  E :                        BlockGraph* block_graph) {
 185  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 186    :  
 187  E :    BlockGraph::Block* symbols_block = NULL;
 188  E :    BlockGraph::Block* strings_block = NULL;
 189    :    if (!FindCoffSpecialBlocks(block_graph, NULL, &symbols_block,
 190  E :                               &strings_block)) {
 191  i :      return false;
 192    :    }
 193    :  
 194  E :    if (!VisitCoffSymbols(callback, symbols_block, strings_block))
 195  E :      return false;
 196    :  
 197  E :    return true;
 198  E :  }
 199    :  
 200    :  bool FindCoffSymbol(const base::StringPiece& symbol_name,
 201    :                      BlockGraph::Block* symbols_block,
 202    :                      BlockGraph::Block* strings_block,
 203  E :                      CoffSymbolOffsets* symbol_offsets) {
 204  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
 205  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
 206  E :    DCHECK_NE(reinterpret_cast<CoffSymbolOffsets*>(NULL), symbol_offsets);
 207    :  
 208  E :    symbol_offsets->clear();
 209    :    VisitCoffSymbolCallback callback = base::Bind(
 210  E :        &VisitCoffSymbol, symbol_name, symbol_offsets);
 211  E :    if (!VisitCoffSymbols(callback, symbols_block, strings_block))
 212  i :      return false;
 213  E :    return true;
 214  E :  }
 215    :  
 216    :  bool FindCoffSymbol(const base::StringPiece& symbol_name,
 217    :                      BlockGraph* block_graph,
 218  E :                      CoffSymbolOffsets* symbol_offsets) {
 219  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 220  E :    DCHECK_NE(reinterpret_cast<CoffSymbolOffsets*>(NULL), symbol_offsets);
 221    :  
 222  E :    BlockGraph::Block* symbols_block = NULL;
 223  E :    BlockGraph::Block* strings_block = NULL;
 224    :    if (!FindCoffSpecialBlocks(block_graph, NULL, &symbols_block,
 225  E :                               &strings_block)) {
 226  i :      return false;
 227    :    }
 228    :  
 229    :    if (!FindCoffSymbol(symbol_name, symbols_block, strings_block,
 230  E :                        symbol_offsets)) {
 231  i :      return false;
 232    :    }
 233    :  
 234  E :    return true;
 235  E :  }
 236    :  
 237    :  bool BuildCoffSymbolNameOffsetMap(BlockGraph::Block* symbols_block,
 238    :                                    BlockGraph::Block* strings_block,
 239  E :                                    CoffSymbolNameOffsetMap* map) {
 240  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
 241  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
 242  E :    DCHECK_NE(reinterpret_cast<CoffSymbolNameOffsetMap*>(NULL), map);
 243    :  
 244  E :    map->clear();
 245    :    VisitCoffSymbolCallback callback = base::Bind(
 246  E :        &AddSymbolToNameOffsetMap, base::Unretained(map));
 247  E :    if (!VisitCoffSymbols(callback, symbols_block, strings_block))
 248  i :      return false;
 249  E :    return true;
 250  E :  }
 251    :  
 252    :  bool BuildCoffSymbolNameOffsetMap(BlockGraph* block_graph,
 253  E :                                    CoffSymbolNameOffsetMap* map) {
 254  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 255  E :    DCHECK_NE(reinterpret_cast<CoffSymbolNameOffsetMap*>(NULL), map);
 256    :  
 257  E :    BlockGraph::Block* symbols_block = NULL;
 258  E :    BlockGraph::Block* strings_block = NULL;
 259    :    if (!FindCoffSpecialBlocks(block_graph, NULL, &symbols_block,
 260  E :                               &strings_block)) {
 261  i :      return false;
 262    :    }
 263    :  
 264  E :    if (!BuildCoffSymbolNameOffsetMap(symbols_block, strings_block, map))
 265  i :      return false;
 266    :  
 267  E :    return true;
 268  E :  }
 269    :  
 270    :  }  // namespace pe

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