Skip to content

Commit

Permalink
Fix FDE printing
Browse files Browse the repository at this point in the history
Iterating over all the FDEs in the dump was broken by the lazy eval of
FDEs. This is a quick-and-dirty fix.

We need to make the cie and fde sets mutable, which is in-keeping with
other similar lazy caches, and, for now, call "ensureFDEs" to make sure
all FDEs are available. It would be better to have a proper
iterable/iterator type that would do this behind the scenes.
  • Loading branch information
peadar committed Jun 13, 2024
1 parent 5e08a34 commit d605b7f
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 32 deletions.
1 change: 1 addition & 0 deletions dump.cc
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ operator << (std::ostream &os, const JSON<Dwarf::CFI> &info)
{
Mapper<AddrStr, decltype(info.object.cies)::mapped_type, decltype(info.object.cies)>
ciesByString(info.object.cies);
info.object.ensureFDEs();
return JObject(os)
.field("cielist", ciesByString, &info.object)
.field("fdelist", info.object.fdes, &info.object)
Expand Down
61 changes: 36 additions & 25 deletions dwarf_frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ static size_t sizeForEncoding( ExceptionHandlingEncoding ehe ) {
}

void
CFI::putCIE(Elf::Addr offset, DWARFReader &r, Elf::Addr end) {
CFI::putCIE(Elf::Addr offset, DWARFReader &r, Elf::Addr end) const {
cies.emplace(std::piecewise_construct,
std::forward_as_tuple(offset),
std::forward_as_tuple(this, r, end));
Expand All @@ -107,7 +107,7 @@ CFI::putCIE(Elf::Addr offset, DWARFReader &r, Elf::Addr end) {
// CIE/FDE The header indicates if its a CIE or FDE - an FDE starts with a
// reference to the CIE, while a CIE starts with a reference of "-1"
std::pair<bool, std::unique_ptr<FDE>>
CFI::putFDEorCIE( DWARFReader &reader ) {
CFI::putFDEorCIE( DWARFReader &reader ) const {
size_t startOffset = reader.getOffset();
Elf::Off associatedCIE;
Elf::Off nextoff = decodeCIEFDEHdr(reader, type, &associatedCIE);
Expand All @@ -123,7 +123,7 @@ CFI::putFDEorCIE( DWARFReader &reader ) {
auto [ success, notAnFde ] = putFDEorCIE(r2);
assert(success && notAnFde == nullptr);
}
std::unique_ptr<FDE> fde = std::make_unique<FDE>(this, reader, associatedCIE, nextoff);
std::unique_ptr<FDE> fde = std::make_unique<FDE>(*this, reader, associatedCIE, nextoff);
reader.setOffset( nextoff );
return {true, std::move(fde) };
}
Expand Down Expand Up @@ -212,33 +212,44 @@ CFI::CFI(const Info *info, FIType type_)
return l->iloc < r->iloc; });
}


void
CFI::ensureFDE(size_t idx) const {
auto &entry = fdes[idx];
if (entry != nullptr)
return;
size_t encodingSize = sizeForEncoding( ExceptionHandlingEncoding(fdeTableEnc) );
DWARFReader tableReader( fdeTable, encodingSize * 2 * idx );
auto [fdeAddr,indirectAddr] = decodeAddress(tableReader, fdeTableEnc, ehFrameHdrAddr);
(void)fdeAddr;
(void)indirectAddr;
auto [fdeOff,indirectOff] = decodeAddress(tableReader, fdeTableEnc, ehFrameHdrAddr);
DWARFReader fdeReader( io, fdeOff - sectionAddr );
auto [ success, newEntry ] = putFDEorCIE( fdeReader );
entry = std::move(newEntry);
assert(fdeAddr == entry->iloc);
}

void
CFI::ensureFDEs() const {
if (fdeTable == nullptr)
return;
for (size_t i = 0; i < fdes.size(); ++i)
ensureFDE(i);
fdeTable.reset(); // We don't need this anymore, as we've read all the FDEs.
}

const FDE *
CFI::findFDE(Elf::Addr addr)
{
CFI::findFDE(Elf::Addr addr) const {

// No FDE found. Check the lookup table.
uintptr_t start = 0;
uintptr_t end = fdes.size();

DWARFReader fdeReader( io );

size_t encodingSize = sizeForEncoding( ExceptionHandlingEncoding(fdeTableEnc) );
while (start < end) {
auto mid = start + (end - start) / 2;
ensureFDE(mid);
auto &entry = fdes[mid];
if (entry == nullptr) {
DWARFReader tableReader( fdeTable, encodingSize * 2 * mid );
auto [fdeAddr,indirectAddr] = decodeAddress(tableReader, fdeTableEnc, ehFrameHdrAddr);

(void)fdeAddr;
(void)indirectAddr;

auto [fdeOff,indirectOff] = decodeAddress(tableReader, fdeTableEnc, ehFrameHdrAddr);
fdeReader.setOffset(fdeOff - sectionAddr);
auto [ success, newEntry ] = putFDEorCIE( fdeReader );
entry = std::move(newEntry);
assert(fdeAddr == entry->iloc);
}
if (entry->iloc <= addr) {
start = mid + 1;
if (addr < entry->iloc + entry->irange)
Expand Down Expand Up @@ -451,16 +462,16 @@ struct FdeCounter {

static FdeCounter fdeCounter;

FDE::FDE(CFI *fi, DWARFReader &reader, Elf::Off cieOff_, Elf::Off endOff_)
FDE::FDE(const CFI &fi, DWARFReader &reader, Elf::Off cieOff_, Elf::Off endOff_)
: end(endOff_)
, cieOff(cieOff_)
{
auto &cie = fi->cies[cieOff];
auto &cie = fi.cies.at( cieOff );
bool indirect;
std::tie(iloc, indirect) = fi->decodeAddress(reader, cie.addressEncoding, fi->sectionAddr);
std::tie(iloc, indirect) = fi.decodeAddress(reader, cie.addressEncoding, fi.sectionAddr);
if (indirect)
throw (Exception() << "FDE has indirect encoding for location");
std::tie(irange, indirect) = fi->decodeAddress(reader, cie.addressEncoding & 0xf, fi->sectionAddr);
std::tie(irange, indirect) = fi.decodeAddress(reader, cie.addressEncoding & 0xf, fi.sectionAddr);
assert(!indirect); // we've anded out the indirect encoding flag.
if (!cie.augmentation.empty() && cie.augmentation[0] == 'z') {
size_t alen = reader.getuleb128();
Expand Down
17 changes: 10 additions & 7 deletions libpstack/dwarf.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ struct FDE {
Elf::Off end;
Elf::Off cieOff;
std::vector<unsigned char> augmentation;
FDE(CFI *, DWARFReader &, Elf::Off cieOff_, Elf::Off endOff_);
FDE(const CFI &, DWARFReader &, Elf::Off cieOff_, Elf::Off endOff_);
};

enum RegisterType {
Expand Down Expand Up @@ -548,7 +548,7 @@ class CFI {
Elf::Addr sectionAddr; // virtual address of section (either eh_frame or debug_frame.
Elf::Addr ehFrameHdrAddr; // virtual address of eh_frame_hdr
FIType type;
std::map<Elf::Addr, CIE> cies;
mutable std::map<Elf::Addr, CIE> cies;

// FDEs are sorted by their iloc field. If we have an fdeTable, then the
// table starts out with the correct size, but unpopulated, and searching
Expand All @@ -558,23 +558,26 @@ class CFI {
// with al the FDEs. Currently, this happens for the VDSO in aarch64
// platforms (where there are just a handful of FDEs), and pretty much
// everything else has an eh_frame_hdr.
std::vector<std::unique_ptr<FDE>> fdes;
mutable std::vector<std::unique_ptr<FDE>> fdes;

ExceptionHandlingEncoding fdeTableEnc; // the encoding format of the entries in fdeTable.
Reader::csptr fdeTable; // the start of the table in the eh_frame_hdr section.
std::pair<bool, std::unique_ptr<FDE>> putFDEorCIE( DWARFReader &reader );
mutable Reader::csptr fdeTable; // the start of the table in the eh_frame_hdr section.
std::pair<bool, std::unique_ptr<FDE>> putFDEorCIE( DWARFReader &reader ) const;

// cieOFF set to -1 if this is CIE, set to offset of associated CIE for an FDE
Elf::Addr decodeCIEFDEHdr(DWARFReader &, FIType, Elf::Off *cieOff) const;
bool isCIE(Elf::Addr) const noexcept;
//void putCIE(DWARFReader &r); // Put CIE from current offset.
void putCIE(Elf::Addr offset, DWARFReader &r, Elf::Addr end); // put CIE who's header we already decoded.
void putCIE(Elf::Addr offset, DWARFReader &r, Elf::Addr end) const; // put CIE who's header we already decoded.

std::pair<uintmax_t, bool> decodeAddress(DWARFReader &, uint8_t encoding, uintptr_t sectionVa) const;
friend std::ostream & ::operator << (std::ostream &os, const JSON<CFI> &);
friend struct FDE;
friend struct CIE;

void ensureFDE(size_t idx) const; // ensures that the fde at index idx is preloaded.
void ensureFDEs() const; // ensure all FDEs are pre-loaded.

public:
const CIE &getCIE(Elf::Addr off) const {
return cies.at(off);
Expand All @@ -588,7 +591,7 @@ class CFI {
CFI &operator = (CFI &&) = delete;
~CFI() = default;

[[nodiscard]] const FDE *findFDE(Elf::Addr);
[[nodiscard]] const FDE *findFDE(Elf::Addr) const;
operator bool() const noexcept { return io != nullptr; }
// If we know the VA of the byte addressed by the start of the dwarf reader, psas it in "va".
};
Expand Down
1 change: 1 addition & 0 deletions reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "libpstack/fs.h"
#include "libpstack/global.h"
#include <cstring>
#include <utility>

namespace pstack {
using std::string;
Expand Down

0 comments on commit d605b7f

Please sign in to comment.