mirror of
https://git.rtems.org/rtems-tools/
synced 2025-06-05 16:51:02 +08:00
covoar: Store address-to-line info outside of DWARF
This adds the AddressToLineMapper class and supporting classes to assume responsibility of tracking address-to-line information. This allows the DWARF library to properly cleanup all of its resources and leads to significant memory savings. Closes #4383
This commit is contained in:
parent
a88be93a88
commit
ac56fce7c1
@ -1893,6 +1893,11 @@ namespace rld
|
||||
return false;
|
||||
}
|
||||
|
||||
const addresses& compilation_unit::get_addresses () const
|
||||
{
|
||||
return addr_lines_;
|
||||
}
|
||||
|
||||
functions&
|
||||
compilation_unit::get_functions ()
|
||||
{
|
||||
|
@ -707,6 +707,11 @@ namespace rld
|
||||
*/
|
||||
unsigned int pc_high () const;
|
||||
|
||||
/**
|
||||
* The addresses associated with this compilation unit.
|
||||
*/
|
||||
const addresses& get_addresses () const;
|
||||
|
||||
/**
|
||||
* Get the source and line for an address. If the address does not match
|
||||
* false is returned the file is set to 'unknown' and the line is set to
|
||||
|
104
tester/covoar/AddressToLineMapper.cc
Normal file
104
tester/covoar/AddressToLineMapper.cc
Normal file
@ -0,0 +1,104 @@
|
||||
/*! @file AddressToLineMapper.cc
|
||||
* @brief AddressToLineMapper Implementation
|
||||
*
|
||||
* This file contains the implementation of the functionality
|
||||
* of the AddressToLineMapper class.
|
||||
*/
|
||||
|
||||
#include "AddressToLineMapper.h"
|
||||
|
||||
namespace Coverage {
|
||||
|
||||
uint64_t SourceLine::location() const
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
bool SourceLine::is_an_end_sequence() const
|
||||
{
|
||||
return is_end_sequence;
|
||||
}
|
||||
|
||||
const std::string& SourceLine::path() const
|
||||
{
|
||||
return path_;
|
||||
}
|
||||
|
||||
int SourceLine::line() const
|
||||
{
|
||||
return line_num;
|
||||
}
|
||||
|
||||
void AddressLineRange::addSourceLine(const rld::dwarf::address& address)
|
||||
{
|
||||
auto insertResult = sourcePaths.insert(address.path());
|
||||
|
||||
sourceLines.emplace_back(
|
||||
SourceLine (
|
||||
address.location(),
|
||||
*insertResult.first,
|
||||
address.line(),
|
||||
address.is_an_end_sequence()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const SourceLine& AddressLineRange::getSourceLine(uint32_t address) const
|
||||
{
|
||||
if (address < lowAddress || address > highAddress) {
|
||||
throw SourceNotFoundError(std::to_string(address));
|
||||
}
|
||||
|
||||
const SourceLine* last_line = nullptr;
|
||||
for (const auto &line : sourceLines) {
|
||||
if (address <= line.location())
|
||||
{
|
||||
if (address == line.location())
|
||||
last_line = &line;
|
||||
break;
|
||||
}
|
||||
last_line = &line;
|
||||
}
|
||||
|
||||
if (last_line == nullptr) {
|
||||
throw SourceNotFoundError(std::to_string(address));
|
||||
}
|
||||
|
||||
return *last_line;
|
||||
}
|
||||
|
||||
void AddressToLineMapper::getSource(
|
||||
uint32_t address,
|
||||
std::string& sourceFile,
|
||||
int& sourceLine
|
||||
) const {
|
||||
const SourceLine default_sourceline = SourceLine();
|
||||
const SourceLine* match = &default_sourceline;
|
||||
|
||||
for (const auto &range : addressLineRanges) {
|
||||
try {
|
||||
const SourceLine& potential_match = range.getSourceLine(address);
|
||||
|
||||
if (match->is_an_end_sequence() || !potential_match.is_an_end_sequence()) {
|
||||
match = &potential_match;
|
||||
}
|
||||
} catch (const AddressLineRange::SourceNotFoundError&) {}
|
||||
}
|
||||
|
||||
sourceFile = match->path();
|
||||
sourceLine = match->line();
|
||||
}
|
||||
|
||||
AddressLineRange& AddressToLineMapper::makeRange(
|
||||
uint32_t low,
|
||||
uint32_t high
|
||||
)
|
||||
{
|
||||
addressLineRanges.emplace_back(
|
||||
AddressLineRange(low, high)
|
||||
);
|
||||
|
||||
return addressLineRanges.back();
|
||||
}
|
||||
|
||||
}
|
211
tester/covoar/AddressToLineMapper.h
Normal file
211
tester/covoar/AddressToLineMapper.h
Normal file
@ -0,0 +1,211 @@
|
||||
/*! @file AddressToLineMapper.h
|
||||
* @brief AddressToLineMapper Specification
|
||||
*
|
||||
* This file contains the specification of the AddressToLineMapper class.
|
||||
*/
|
||||
|
||||
#ifndef __ADDRESS_TO_LINE_MAPPER_H__
|
||||
#define __ADDRESS_TO_LINE_MAPPER_H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <rld-dwarf.h>
|
||||
|
||||
namespace Coverage {
|
||||
|
||||
/*! @class SourceLine
|
||||
*
|
||||
* This class stores source information for a specific address.
|
||||
*/
|
||||
class SourceLine {
|
||||
|
||||
public:
|
||||
|
||||
SourceLine()
|
||||
: address(0),
|
||||
path_("unknown"),
|
||||
line_num(-1),
|
||||
is_end_sequence(true)
|
||||
{
|
||||
}
|
||||
|
||||
SourceLine(
|
||||
uint64_t addr,
|
||||
const std::string& src,
|
||||
int line,
|
||||
bool end_sequence
|
||||
) : address(addr),
|
||||
path_(src),
|
||||
line_num(line),
|
||||
is_end_sequence(end_sequence)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method gets the address of this source information.
|
||||
*
|
||||
* @return Returns the address of this source information
|
||||
*/
|
||||
uint64_t location() const;
|
||||
|
||||
/*!
|
||||
* This method gets a value indicating whether this address represents an
|
||||
* end sequence.
|
||||
*
|
||||
* @return Returns whether this address represents an end sequence or not
|
||||
*/
|
||||
bool is_an_end_sequence() const;
|
||||
|
||||
/*!
|
||||
* This method gets the source file path of this address.
|
||||
*
|
||||
* @return Returns the source file path of this address
|
||||
*/
|
||||
const std::string& path() const;
|
||||
|
||||
/*!
|
||||
* This method gets the source line number of this address.
|
||||
*
|
||||
* @return Returns the source line number of this address
|
||||
*/
|
||||
int line() const;
|
||||
|
||||
private:
|
||||
|
||||
/*!
|
||||
* The address of this source information.
|
||||
*/
|
||||
uint64_t address;
|
||||
|
||||
/*!
|
||||
* An iterator pointing to the location in the set that contains the
|
||||
* source file path of the address.
|
||||
*/
|
||||
const std::string& path_;
|
||||
|
||||
/*!
|
||||
* The source line number of the address.
|
||||
*/
|
||||
int line_num;
|
||||
|
||||
/*!
|
||||
* Whether the address represents an end sequence or not.
|
||||
*/
|
||||
bool is_end_sequence;
|
||||
|
||||
};
|
||||
|
||||
typedef std::vector<SourceLine> SourceLines;
|
||||
|
||||
typedef std::set<std::string> SourcePaths;
|
||||
|
||||
/*! @class AddressLineRange
|
||||
*
|
||||
* This class stores source information for an address range.
|
||||
*/
|
||||
class AddressLineRange {
|
||||
|
||||
public:
|
||||
|
||||
class SourceNotFoundError : public std::runtime_error {
|
||||
/* Use the base class constructors. */
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
AddressLineRange(
|
||||
uint32_t low,
|
||||
uint32_t high
|
||||
) : lowAddress(low), highAddress(high)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method adds source and line information for a specified address.
|
||||
*
|
||||
* @param[in] address specifies the DWARF address information
|
||||
*/
|
||||
void addSourceLine(const rld::dwarf::address& address);
|
||||
|
||||
/*!
|
||||
* This method gets the source file name and line number for a given
|
||||
* address.
|
||||
*
|
||||
* @param[in] address specifies the address to look up
|
||||
*
|
||||
* @return Returns the source information for the specified address.
|
||||
*/
|
||||
const SourceLine& getSourceLine(uint32_t address) const;
|
||||
|
||||
private:
|
||||
|
||||
/*!
|
||||
* The low address for this range.
|
||||
*/
|
||||
uint32_t lowAddress;
|
||||
|
||||
/*!
|
||||
* The high address for this range.
|
||||
*/
|
||||
uint32_t highAddress;
|
||||
|
||||
/*!
|
||||
* The source information for addresses in this range.
|
||||
*/
|
||||
SourceLines sourceLines;
|
||||
|
||||
/*!
|
||||
* The set of source file names for this range.
|
||||
*/
|
||||
SourcePaths sourcePaths;
|
||||
|
||||
};
|
||||
|
||||
typedef std::vector<AddressLineRange> AddressLineRanges;
|
||||
|
||||
/*! @class AddressToLineMapper
|
||||
*
|
||||
* This class provides address-to-line capabilities.
|
||||
*/
|
||||
class AddressToLineMapper {
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
* This method gets the source file name and line number for a given
|
||||
* address.
|
||||
*
|
||||
* @param[in] address specifies the address to look up
|
||||
* @param[out] sourceFile specifies the name of the source file
|
||||
* @param[out] sourceLine specifies the line number in the source file
|
||||
*/
|
||||
void getSource(
|
||||
uint32_t address,
|
||||
std::string& sourceFile,
|
||||
int& sourceLine
|
||||
) const;
|
||||
|
||||
/*!
|
||||
* This method creates a new range with the specified addresses.
|
||||
*
|
||||
* @param[in] low specifies the low address of the range
|
||||
* @param[in] high specifies the high address of the range
|
||||
*
|
||||
* @return Returns a reference to the newly created range
|
||||
*/
|
||||
AddressLineRange& makeRange(uint32_t low, uint32_t high);
|
||||
|
||||
private:
|
||||
|
||||
/*!
|
||||
* The address and line information ranges.
|
||||
*/
|
||||
AddressLineRanges addressLineRanges;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -40,61 +40,60 @@ namespace Coverage {
|
||||
executable.begin();
|
||||
executable.load_symbols(symbols);
|
||||
|
||||
rld::dwarf::file debug;
|
||||
|
||||
debug.begin(executable.elf());
|
||||
debug.load_debug();
|
||||
debug.load_functions();
|
||||
|
||||
try {
|
||||
for (auto& cu : debug.get_cus()) {
|
||||
for (auto& func : cu.get_functions()) {
|
||||
if (!func.has_machine_code()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!SymbolsToAnalyze->isDesired(func.name())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (func.is_inlined()) {
|
||||
if (func.is_external()) {
|
||||
// Flag it
|
||||
std::cerr << "Function is both external and inlined: "
|
||||
<< func.name() << std::endl;
|
||||
}
|
||||
|
||||
if (func.has_entry_pc()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the low PC address is zero, the symbol does not appear in
|
||||
// this executable.
|
||||
if (func.pc_low() == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// We can't process a zero size function.
|
||||
if (func.pc_high() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
createCoverageMap (cu.name(), func.name(),
|
||||
func.pc_low(), func.pc_high() - 1);
|
||||
}
|
||||
for (auto& cu : debug.get_cus()) {
|
||||
AddressLineRange& range = mapper.makeRange(cu.pc_low(), cu.pc_high());
|
||||
// Does not filter on desired symbols under the assumption that the test
|
||||
// code and any support code is small relative to what is being tested.
|
||||
for (const auto &address : cu.get_addresses()) {
|
||||
range.addSourceLine(address);
|
||||
}
|
||||
} catch (...) {
|
||||
debug.end();
|
||||
throw;
|
||||
}
|
||||
|
||||
// Can't cleanup handles until the destructor because the information is
|
||||
// referenced elsewhere. NOTE: This could cause problems from too many open
|
||||
// file descriptors.
|
||||
for (auto& func : cu.get_functions()) {
|
||||
if (!func.has_machine_code()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!SymbolsToAnalyze->isDesired(func.name())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (func.is_inlined()) {
|
||||
if (func.is_external()) {
|
||||
// Flag it
|
||||
std::cerr << "Function is both external and inlined: "
|
||||
<< func.name() << std::endl;
|
||||
}
|
||||
|
||||
if (func.has_entry_pc()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the low PC address is zero, the symbol does not appear in
|
||||
// this executable.
|
||||
if (func.pc_low() == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// We can't process a zero size function.
|
||||
if (func.pc_high() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
createCoverageMap (cu.name(), func.name(),
|
||||
func.pc_low(), func.pc_high() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExecutableInfo::~ExecutableInfo()
|
||||
{
|
||||
debug.end();
|
||||
}
|
||||
|
||||
void ExecutableInfo::dumpCoverageMaps( void ) {
|
||||
@ -197,7 +196,7 @@ namespace Coverage {
|
||||
{
|
||||
std::string file;
|
||||
int lno;
|
||||
debug.get_source (address, file, lno);
|
||||
mapper.getSource (address, file, lno);
|
||||
std::ostringstream ss;
|
||||
ss << file << ':' << lno;
|
||||
line = ss.str ();
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <rld-files.h>
|
||||
#include <rld-symbols.h>
|
||||
|
||||
#include "AddressToLineMapper.h"
|
||||
#include "CoverageMapBase.h"
|
||||
#include "SymbolTable.h"
|
||||
|
||||
@ -157,11 +158,6 @@ namespace Coverage {
|
||||
uint32_t highAddress
|
||||
);
|
||||
|
||||
/*!
|
||||
* The DWARF data to the ELF executable.
|
||||
*/
|
||||
rld::dwarf::file debug;
|
||||
|
||||
/*!
|
||||
* The executable's file name.
|
||||
*/
|
||||
@ -172,6 +168,11 @@ namespace Coverage {
|
||||
*/
|
||||
rld::symbols::table symbols;
|
||||
|
||||
/*!
|
||||
* The address-to-line mapper for this executable.
|
||||
*/
|
||||
AddressToLineMapper mapper;
|
||||
|
||||
/*!
|
||||
* This map associates a symbol with its coverage map.
|
||||
*/
|
||||
|
@ -83,6 +83,7 @@ def build(bld):
|
||||
|
||||
bld.stlib(target = 'ccovoar',
|
||||
source = ['app_common.cc',
|
||||
'AddressToLineMapper.cc',
|
||||
'CoverageFactory.cc',
|
||||
'CoverageMap.cc',
|
||||
'CoverageMapBase.cc',
|
||||
|
Loading…
x
Reference in New Issue
Block a user