Skip to content

Commit

Permalink
core: Identify symbols for anchors if available
Browse files Browse the repository at this point in the history
Prior to this, the user could arrange, by doing "source <corefilename>.symreqs"
from gdb on the given core, to create <corefilename>.symdefs.  The use of this
was for cases where mangled class names were not present in the core.  This
change causes the addresses of any anchors to be included in the .symreqs as
well, so that when the .symdefs is created it will give symbols for those
anchors.  At present, the resulting symbol information is only used in the
output of the explain command but it will eventually be incorporated into other
commands.
  • Loading branch information
timboddy committed Jan 22, 2018
1 parent b02aae8 commit 982c9d9
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 65 deletions.
25 changes: 17 additions & 8 deletions src/Allocations/AnchorChainLister.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,27 @@
// SPDX-License-Identifier: GPL-2.0

#pragma once
#include "Graph.h"
#include "SignatureDirectory.h"
#include "../Commands/Runner.h"
#include "../InModuleDescriber.h"
#include "../StackDescriber.h"
#include "Graph.h"
#include "SignatureDirectory.h"
namespace chap {
namespace Allocations {
template <typename Offset>
class AnchorChainLister
: public Graph<Offset>::AnchorChainVisitor {
class AnchorChainLister : public Graph<Offset>::AnchorChainVisitor {
public:
AnchorChainLister(const InModuleDescriber<Offset>& inModuleDescriber,
const StackDescriber<Offset>& stackDescriber,
const Graph<Offset>& graph,
const SignatureDirectory<Offset>* signatureDirectory,
const AnchorDirectory<Offset>* anchorDirectory,
Commands::Context& context, Offset anchoree)
: _graph(graph),
_inModuleDescriber(inModuleDescriber),
_stackDescriber(stackDescriber),
_signatureDirectory(signatureDirectory),
_anchorDirectory(anchorDirectory),
_context(context),
_anchoree(anchoree),
_numStaticAnchorChainsShown(0),
Expand Down Expand Up @@ -56,8 +57,15 @@ class AnchorChainLister
it != staticAddrs.end(); ++it) {
Offset staticAddr = *it;
_inModuleDescriber.Describe(_context, staticAddr, false);
output << "Static address " << staticAddr << " references"
<< (isDirect ? " " : " anchor point ") << address << "\n";
output << "Static address " << staticAddr;
if (_anchorDirectory != 0) {
const std::string& name = _anchorDirectory->Name(staticAddr);
if (!name.empty()) {
output << " (" << name << ")";
}
}
output << " references" << (isDirect ? " " : " anchor point ") << address
<< "\n";
}
_numStaticAnchorChainsShown++;
if (isDirect) {
Expand Down Expand Up @@ -150,6 +158,7 @@ class AnchorChainLister
const InModuleDescriber<Offset>& _inModuleDescriber;
const StackDescriber<Offset>& _stackDescriber;
const SignatureDirectory<Offset>* _signatureDirectory;
const AnchorDirectory<Offset>* _anchorDirectory;
Commands::Context& _context;
const Offset _anchoree;
size_t _numStaticAnchorChainsShown;
Expand All @@ -159,8 +168,8 @@ class AnchorChainLister
size_t _numDirectStackAnchorChainsShown;
size_t _numDirectRegisterAnchorChainsShown;

void ShowSignatureIfPresent(Commands::Output& output,
Offset size, const char* image) {
void ShowSignatureIfPresent(Commands::Output& output, Offset size,
const char* image) {
if (size >= sizeof(Offset)) {
Offset signature = *((Offset*)image);
if ((_signatureDirectory != ((SignatureDirectory<Offset>*)(0))) &&
Expand Down
91 changes: 91 additions & 0 deletions src/Allocations/AnchorDirectory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
// SPDX-License-Identifier: GPL-2.0

#pragma once
#include <map>
#include <set>

/*
* This keeps mappings from anchor to name and name to set of anchors.
* Note that there are potentially multiple anchors (numbers) for a given
* name because a anchor may be defined in multiple load modules.
*/

namespace chap {
namespace Allocations {
template <class Offset>
class AnchorDirectory {
public:
typedef std::map<Offset, std::string> AnchorToNameMap;
typedef typename AnchorToNameMap::iterator AnchorToNameIterator;
typedef typename AnchorToNameMap::const_iterator AnchorToNameConstIterator;
typedef std::map<std::string, std::set<Offset> > NameToAnchorsMap;
typedef typename NameToAnchorsMap::const_iterator NameToAnchorsConstIterator;

AnchorDirectory() : _multipleAnchorsPerName(false) {}

void MapAnchorToName(Offset anchor, std::string name) {
AnchorToNameIterator it = _anchorToName.find(anchor);
if (it != _anchorToName.end()) {
/*
* This anchor is already known to be an anchor.
*/
if (it->second == name || name.empty()) {
/*
* There is no new information about the name.
*/
return;
}
if (!(it->second).empty()) {
/*
* There was a previously known name, which is now no longer
* associated with the anchor.
*/
_nameToAnchors[it->second].erase(anchor);
}
it->second = name;
} else {
_anchorToName[anchor] = name;
}
if (!name.empty()) {
std::set<Offset>& anchors = _nameToAnchors[name];
anchors.insert(anchor);
if (anchors.size() > 1) {
_multipleAnchorsPerName = true;
}
}
}

bool HasMultipleAnchorsPerName() const { return _multipleAnchorsPerName; }

bool IsMapped(Offset anchor) const {
return _anchorToName.find(anchor) != _anchorToName.end();
}

const std::string& Name(Offset anchor) const {
AnchorToNameConstIterator it = _anchorToName.find(anchor);
if (it != _anchorToName.end()) {
return it->second;
} else {
return NO_NAME;
}
}

const std::set<Offset>& Anchors(const std::string& name) const {
typename NameToAnchorsMap::const_iterator it = _nameToAnchors.find(name);
if (it != _nameToAnchors.end()) {
return it->second;
} else {
return NO_ANCHORS;
}
}

private:
bool _multipleAnchorsPerName;
AnchorToNameMap _anchorToName;
NameToAnchorsMap _nameToAnchors;
std::string NO_NAME;
std::set<Offset> NO_ANCHORS;
};
} // namespace Allocations
} // namespace chap
11 changes: 7 additions & 4 deletions src/Allocations/Describer.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
#include "../InModuleDescriber.h"
#include "../ProcessImage.h"
#include "../StackDescriber.h"
#include "SignatureDirectory.h"
#include "AnchorChainLister.h"
#include "AnchorDirectory.h"
#include "Finder.h"
#include "PatternRecognizerRegistry.h"
#include "SignatureDirectory.h"

namespace chap {
namespace Allocations {
Expand All @@ -32,11 +33,13 @@ class Describer : public chap::Describer<Offset> {
_processImage = processImage;
if (processImage == 0) {
_signatureDirectory = 0;
_anchorDirectory = 0;
_addressMap = 0;
_finder = 0;
_graph = 0;
} else {
_signatureDirectory = &(processImage->GetSignatureDirectory());
_anchorDirectory = &(processImage->GetAnchorDirectory());
_addressMap = &(processImage->GetVirtualAddressMap());
_finder = processImage->GetAllocationFinder();
_graph = processImage->GetAllocationGraph();
Expand Down Expand Up @@ -119,9 +122,8 @@ class Describer : public chap::Describer<Offset> {
if (isUsed) {
if (!isLeaked) {
AnchorChainLister<Offset> anchorChainLister(
_inModuleDescriber, _stackDescriber,
*_graph, _signatureDirectory,
context, address);
_inModuleDescriber, _stackDescriber, *_graph, _signatureDirectory,
_anchorDirectory, context, address);
_graph->VisitStaticAnchorChains(index, anchorChainLister);
_graph->VisitRegisterAnchorChains(index, anchorChainLister);
_graph->VisitStackAnchorChains(index, anchorChainLister);
Expand All @@ -137,6 +139,7 @@ class Describer : public chap::Describer<Offset> {
const PatternRecognizerRegistry<Offset>& _patternRecognizerRegistry;
const ProcessImage<Offset>* _processImage;
const SignatureDirectory<Offset>* _signatureDirectory;
const AnchorDirectory<Offset>* _anchorDirectory;
const VirtualAddressMap<Offset>* _addressMap;
const Finder<Offset>* _finder;
const Graph<Offset>* _graph;
Expand Down
79 changes: 32 additions & 47 deletions src/Linux/LinuxProcessImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class LinuxProcessImage : public ProcessImage<OffsetType> {
*/
FindStaticAnchorRanges();

Base::_allocationGraph = new Allocations::Graph<Offset>(
*Base::_allocationFinder, Base::_threadMap, _staticAnchorLimits,
(Allocations::ExternalAnchorPointChecker<Offset>*)(0));

/*
* In Linux processes the current approach is to wait until the
* allocations have been found, then treat pointers at the start of
Expand All @@ -52,10 +56,6 @@ class LinuxProcessImage : public ProcessImage<OffsetType> {
*/

FindSignatures();

Base::_allocationGraph = new Allocations::Graph<Offset>(
*Base::_allocationFinder, Base::_threadMap, _staticAnchorLimits,
(Allocations::ExternalAnchorPointChecker<Offset>*)(0));
}
}

Expand All @@ -71,7 +71,6 @@ class LinuxProcessImage : public ProcessImage<OffsetType> {
}

protected:

void FindModules() {
Offset executableAddress = 0;
typename AddressMap::const_iterator itEnd = Base::_virtualAddressMap.end();
Expand Down Expand Up @@ -351,18 +350,12 @@ class LinuxProcessImage : public ProcessImage<OffsetType> {

private:
/*
* The following is mutable because the symdefs file is read lazily the
* first tyime it is present and needed.
* _symdefsRead is mutable because the symdefs file is read lazily the
* first time it is present and needed.
*/

mutable bool _symdefsRead;
/*
* TODO: This really should not be mutable but it is because static
* anchor limits are calculated lazily because they are calculated
* after the allocations are found and the allocations are found
* lazily.
*/
mutable std::map<Offset, Offset> _staticAnchorLimits;
std::map<Offset, Offset> _staticAnchorLimits;

bool ParseOffset(const std::string& s, Offset& value) const {
if (!s.empty()) {
Expand Down Expand Up @@ -681,8 +674,9 @@ class LinuxProcessImage : public ProcessImage<OffsetType> {
Base::_signatureDirectory.MapSignatureToName(signature, name);
signature = 0;
} else if (anchor != 0) {
// size_t defEnd = line.find(" in section");
//??? _anchorToName[anchor] = line.substr(0, defEnd);
size_t defEnd = line.find(" in section");
std::string name(line.substr(0, defEnd));
Base::_anchorDirectory.MapAnchorToName(anchor, name);
anchor = 0;
}
}
Expand All @@ -691,13 +685,7 @@ class LinuxProcessImage : public ProcessImage<OffsetType> {
return true;
}

/*
* TODO: This is declared as const only because it is done lazily.
* It is done lazily because finding allocations is done lazily. Fix
* this.
*/

void FindSignatures() const {
void FindSignatures() {
std::string emptyName;
bool writeSymreqs = true;
std::string symReqsPath(
Expand Down Expand Up @@ -764,29 +752,26 @@ class LinuxProcessImage : public ProcessImage<OffsetType> {
<< "info symbol 0x" << signature << '\n';
}
}
#if 0
// ??? In old approach we need anchor requests in .symreqs
// ??? as well.
// ??? In the new approach this is awkward because the static
// ??? anchor points are now calculated by the graph, which is
// ??? in turn calculated lazily. We want the anchor points
// ??? somewhat earlier.
if (_staticAnchorPoints.size() > 1000000) {
gdbScriptFile << "# Too many anchors were found ("
<< dec << _staticAnchorPoints.size()
<< ") ... omitting anchor points\n";
}
for (AnchorPointMapConstIterator it = _staticAnchorPoints.begin();
it!= _staticAnchorPoints.end(); ++it) {
for (OffsetVectorConstIterator itVec = it->second.begin();
itVec != it->second.end(); ++itVec) {
gdbScriptFile << "printf \"ANCHOR " << hex << *itVec << "\\n\""
<< '\n'
<< "info symbol 0x" << hex << *itVec << '\n';
}
}
// TODO - possibly handle failed I/O in some way.
#endif
const Allocations::Graph<Offset>& graph = *(Base::_allocationGraph);
for (typename Allocations::Finder<Offset>::AllocationIndex i = 0;
i < numAllocations; ++i) {
const typename Allocations::Finder<Offset>::Allocation* allocation =
finder.AllocationAt(i);
if (!allocation->IsUsed() || !graph.IsStaticAnchorPoint(i)) {
continue;
}
const std::vector<Offset>* anchors = graph.GetStaticAnchors(i);
typename std::vector<Offset>::const_iterator itAnchorsEnd =
anchors->end();
for (typename std::vector<Offset>::const_iterator itAnchors =
anchors->begin();
itAnchors != itAnchorsEnd; ++itAnchors) {
gdbScriptFile << "printf \"ANCHOR " << std::hex << *itAnchors << "\\n\""
<< '\n'
<< "info symbol 0x" << std::hex << *itAnchors << '\n';
}
}
// TODO - possibly handle failed I/O in some way.
if (writeSymreqs) {
gdbScriptFile << "set logging off\n";
gdbScriptFile << "set logging overwrite 0\n";
Expand All @@ -796,7 +781,7 @@ class LinuxProcessImage : public ProcessImage<OffsetType> {
gdbScriptFile.close();
}
}
void FindStaticAnchorRanges() const {
void FindStaticAnchorRanges() {
typename VirtualMemoryPartition<Offset>::UnclaimedImagesConstIterator
itEnd = Base::_virtualMemoryPartition.EndUnclaimedImages();
typename VirtualMemoryPartition<Offset>::UnclaimedImagesConstIterator it =
Expand Down
20 changes: 15 additions & 5 deletions src/ProcessImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0

#pragma once
#include "Allocations/AnchorDirectory.h"
#include "Allocations/Finder.h"
#include "Allocations/Graph.h"
#include "Allocations/SignatureDirectory.h"
Expand Down Expand Up @@ -57,6 +58,14 @@ class ProcessImage {
return _signatureDirectory;
}

const Allocations::AnchorDirectory<Offset> &GetAnchorDirectory() const {
return _anchorDirectory;
}

Allocations::AnchorDirectory<Offset> &GetAnchorDirectory() {
return _anchorDirectory;
}

const Allocations::Finder<Offset> *GetAllocationFinder() const {
RefreshSignatureDirectory();
return _allocationFinder;
Expand All @@ -76,11 +85,12 @@ class ProcessImage {
Allocations::Finder<Offset> *_allocationFinder;
Allocations::Graph<Offset> *_allocationGraph;

/*
* At present this is mutable because some const functions cause the
* signature directory to be refreshed (because we are allowing the
* user to make a symdefs file between commands).
*/
/*
* At present this is mutable because some const functions cause these
* directories to be refreshed (because we are allowing the
* user to make a symdefs file between commands).
*/
mutable Allocations::SignatureDirectory<Offset> _signatureDirectory;
mutable Allocations::AnchorDirectory<Offset> _anchorDirectory;
};
} // namespace chap
2 changes: 1 addition & 1 deletion src/VirtualMemoryPartition.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class VirtualMemoryPartition {

ClaimedRangesConstIterator end() const { return _claimedRanges.end(); }

const AddressMap &GetAddressMap() { return _addressMap; }
const AddressMap &GetAddressMap() const { return _addressMap; }

private:
const AddressMap _addressMap;
Expand Down

0 comments on commit 982c9d9

Please sign in to comment.