Make identical-code-folded symbol output more consistent between runs
Consistently output the "least" symbol by decorated name when multiple symbols share an address. Testing with chrome.dll.pdb the diffs between the new and old output look sensible, and this is actually ~20% faster than the existing implementation. Bug: 749 Change-Id: Ie638559b63f0eb2dcb80b1ebb579228d62c63bb2 Reviewed-on: https://chromium-review.googlesource.com/758885 Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
615ad2b6f4
commit
70914b2d38
1 changed files with 43 additions and 37 deletions
|
@ -37,8 +37,11 @@
|
||||||
#include <ImageHlp.h>
|
#include <ImageHlp.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "common/windows/dia_util.h"
|
#include "common/windows/dia_util.h"
|
||||||
#include "common/windows/guid_string.h"
|
#include "common/windows/guid_string.h"
|
||||||
|
@ -106,6 +109,8 @@ namespace {
|
||||||
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
|
typedef std::multimap<DWORD, CComPtr<IDiaSymbol>> SymbolMultimap;
|
||||||
|
|
||||||
// A helper class to scope a PLOADED_IMAGE.
|
// A helper class to scope a PLOADED_IMAGE.
|
||||||
class AutoImage {
|
class AutoImage {
|
||||||
public:
|
public:
|
||||||
|
@ -166,6 +171,16 @@ bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Computing undecorated names for all symbols is expensive, so we compare
|
||||||
|
// decorated names.
|
||||||
|
bool CompareSymbols(const SymbolMultimap::value_type& a,
|
||||||
|
const SymbolMultimap::value_type& b) {
|
||||||
|
BSTR a_name, b_name;
|
||||||
|
a.second->get_name(&a_name);
|
||||||
|
b.second->get_name(&b_name);
|
||||||
|
return wcscmp(a_name, b_name) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
|
PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
|
||||||
|
@ -400,7 +415,7 @@ bool PDBSourceLineWriter::PrintFunctions() {
|
||||||
CComPtr<IDiaEnumSymbols> symbols = NULL;
|
CComPtr<IDiaEnumSymbols> symbols = NULL;
|
||||||
|
|
||||||
// Find all function symbols first.
|
// Find all function symbols first.
|
||||||
std::set<DWORD> rvas;
|
SymbolMultimap rva_symbols;
|
||||||
hr = global->findChildren(SymTagFunction, NULL, nsNone, &symbols);
|
hr = global->findChildren(SymTagFunction, NULL, nsNone, &symbols);
|
||||||
|
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
|
@ -408,9 +423,10 @@ bool PDBSourceLineWriter::PrintFunctions() {
|
||||||
|
|
||||||
while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) {
|
while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) {
|
||||||
if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) {
|
if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) {
|
||||||
// To maintain existing behavior of one symbol per address, place the
|
// Place the symbols into a multimap indexed by rva, so we can choose
|
||||||
// rva onto a set here to uniquify them.
|
// the apropriate symbol name to use when multiple symbols share an
|
||||||
rvas.insert(rva);
|
// address.
|
||||||
|
rva_symbols.insert(std::make_pair(rva, symbol));
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n");
|
fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n");
|
||||||
return false;
|
return false;
|
||||||
|
@ -432,8 +448,9 @@ bool PDBSourceLineWriter::PrintFunctions() {
|
||||||
|
|
||||||
while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) {
|
while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) {
|
||||||
if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) {
|
if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) {
|
||||||
if (rvas.count(rva) == 0) {
|
if (rva_symbols.find(rva) == rva_symbols.end()) {
|
||||||
rvas.insert(rva); // Keep symbols in rva order.
|
// Keep symbols in rva order.
|
||||||
|
rva_symbols.insert(std::make_pair(rva, symbol));
|
||||||
public_only_rvas.insert(rva);
|
public_only_rvas.insert(rva);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -447,40 +464,29 @@ bool PDBSourceLineWriter::PrintFunctions() {
|
||||||
symbols.Release();
|
symbols.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<DWORD>::iterator it;
|
// For each rva, dump one symbol at the address.
|
||||||
|
SymbolMultimap::iterator it = rva_symbols.begin();
|
||||||
// For each rva, dump the first symbol DIA knows about at the address.
|
while (it != rva_symbols.end()) {
|
||||||
for (it = rvas.begin(); it != rvas.end(); ++it) {
|
std::pair<SymbolMultimap::iterator, SymbolMultimap::iterator> symbol_range =
|
||||||
CComPtr<IDiaSymbol> symbol = NULL;
|
rva_symbols.equal_range(it->first);
|
||||||
// If the symbol is not in the public list, look for SymTagFunction. This is
|
// Find the minimum symbol by name to make the output more consistent
|
||||||
// a workaround to a bug where DIA will hang if searching for a private
|
// between runs on different releases of the same module, in the case of
|
||||||
// symbol at an address where only a public symbol exists.
|
// multiple symbols sharing an address.
|
||||||
// See http://connect.microsoft.com/VisualStudio/feedback/details/722366
|
SymbolMultimap::iterator least_symbol_iter =
|
||||||
if (public_only_rvas.count(*it) == 0) {
|
std::min_element(symbol_range.first, symbol_range.second, CompareSymbols);
|
||||||
if (SUCCEEDED(session_->findSymbolByRVA(*it, SymTagFunction, &symbol))) {
|
CComPtr<IDiaSymbol> symbol = least_symbol_iter->second;
|
||||||
// Sometimes findSymbolByRVA returns S_OK, but NULL.
|
// Only print public symbols if there is no function symbol for the address.
|
||||||
if (symbol) {
|
if (public_only_rvas.count(it->first) == 0) {
|
||||||
if (!PrintFunction(symbol, symbol))
|
if (!PrintFunction(symbol, symbol))
|
||||||
return false;
|
|
||||||
symbol.Release();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "findSymbolByRVA SymTagFunction failed\n");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
symbol.Release();
|
||||||
} else if (SUCCEEDED(session_->findSymbolByRVA(*it,
|
|
||||||
SymTagPublicSymbol,
|
|
||||||
&symbol))) {
|
|
||||||
// Sometimes findSymbolByRVA returns S_OK, but NULL.
|
|
||||||
if (symbol) {
|
|
||||||
if (!PrintCodePublicSymbol(symbol))
|
|
||||||
return false;
|
|
||||||
symbol.Release();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "findSymbolByRVA SymTagPublicSymbol failed\n");
|
if (!PrintCodePublicSymbol(symbol))
|
||||||
return false;
|
return false;
|
||||||
|
symbol.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it = symbol_range.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When building with PGO, the compiler can split functions into
|
// When building with PGO, the compiler can split functions into
|
||||||
|
|
Loading…
Reference in a new issue