Skip to content

Commit 3f30113

Browse files
committed
Better support for registers beyond those in user_regs_struct
Include the other register sets we care about in the CoreRegisters in general - I started this for aarch64, and it made sense to homogenize it for other platforms, and make the support more sane. The use of archreg.h has just become too cumbersome, so retire that, and actually do the register get/set for DWARF register numbers in C++ code rather than macro hacks, with separate functions for each platform We no longer mark all the registers we know about in the call frame info, so when unwinding, we just now copy the entire register set as a struct copy, then just apply the non-default changes on top of that, so it's simpler, and likely faster I need to add better support for dealing with registers bigger than uintmax_t, but this is still strictly an improvement over what was there before, I think
1 parent 14ab938 commit 3f30113

File tree

20 files changed

+934
-350
lines changed

20 files changed

+934
-350
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ build
1717
.clang-tidy
1818
py311
1919
compile_commands.json
20+
arm

arch.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Copyright (c) 2025 Arista Networks, Inc. All rights reserved.
2+
// Arista Networks, Inc. Confidential and Proprietary.
3+
4+
#include <cstdint>
5+
#include "libpstack/arch.h"
6+
7+
namespace pstack::Procman {
8+
}

dwarf_frame.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,6 @@ CallFrame::CallFrame()
274274
{
275275
cfaReg = 0;
276276
cfaValue.type = UNDEF;
277-
#define REGMAP(number, field) registers[number].type = ARCH;
278-
#include "libpstack/archreg.h"
279-
#undef REGMAP
280-
#ifdef CFA_RESTORE_REGNO
281-
#endif
282277
}
283278

284279
CallFrame

dwarf_info.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ Abbreviation::Abbreviation(DWARFReader &r)
218218
, sorted(false)
219219
, nextSibIdx(-1)
220220
{
221+
forms.reserve(4);
222+
attrName2Idx.reserve(4);
221223
for (size_t i = 0;; ++i) {
222224
auto name = AttrName(r.getuleb128());
223225
auto form = Form(r.getuleb128());
@@ -229,6 +231,8 @@ Abbreviation::Abbreviation(DWARFReader &r)
229231
forms.emplace_back(form, value);
230232
attrName2Idx.emplace_back(name, i);
231233
}
234+
attrName2Idx.shrink_to_fit();
235+
forms.shrink_to_fit();
232236
}
233237

234238
std::unique_ptr<LineInfo>

dwarfproc.cc

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "libpstack/arch.h"
12
#include "libpstack/dwarf.h"
23
#include "libpstack/elf.h"
34
#include "libpstack/proc.h"
@@ -7,31 +8,28 @@
78
extern std::ostream & operator << (std::ostream &os, const pstack::Dwarf::DIE &);
89

910
namespace pstack::Procman {
10-
void
11-
StackFrame::setCoreRegs(const Elf::CoreRegisters &sys)
12-
{
13-
#define REGMAP(number, field) Elf::setReg(regs, number, sys.field);
14-
#include "libpstack/archreg.h"
15-
#undef REGMAP
16-
}
1711

18-
void
19-
StackFrame::getCoreRegs(Elf::CoreRegisters &core) const
20-
{
21-
#define REGMAP(number, field) core.field = Elf::getReg(regs, number);
22-
#include "libpstack/archreg.h"
23-
#undef REGMAP
12+
struct RegisterFromReader {
13+
const Reader &reader;
14+
off_t offset;
15+
public:
16+
explicit RegisterFromReader(const Reader &reader, off_t offset) : reader(reader), offset(offset) { }
17+
};
18+
19+
template <typename T>
20+
auto get( const RegisterFromReader &rfr ) -> T {
21+
T t = rfr.reader.readObj<T>(rfr.offset);
22+
return t;
2423
}
2524

26-
Elf::Addr
25+
gpreg
2726
StackFrame::rawIP() const
2827
{
28+
return
2929
#ifdef __aarch64__
30-
// remove RA signing artefacts.
31-
return 0xffffffffffff & Elf::getReg(regs, IPREG);
32-
#else
33-
return Elf::getReg(regs, IPREG);
30+
0xffffffffffff &
3431
#endif
32+
std::get<gpreg>(regs.getDwarf(IPREG));
3533
}
3634

3735
ProcessLocation
@@ -57,7 +55,7 @@ StackFrame::scopeIP(Process &proc) const
5755
// Finally, for the function that was running when the signal was invoked -
5856
// The signal was invoked asynchronously, so again, we have no call
5957
// instruction to walk back into.
60-
auto raw = rawIP();
58+
auto raw = Elf::Addr(rawIP());
6159
if (raw == 0)
6260
return { proc, raw };
6361
if (mechanism == UnwindMechanism::MACHINEREGS
@@ -283,7 +281,7 @@ ExpressionStack::eval(Process &proc, Dwarf::DWARFReader &r, const StackFrame *fr
283281
case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27:
284282
case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31: {
285283
auto offset = r.getsleb128();
286-
push(Elf::getReg(frame->regs, op - DW_OP_breg0) + offset);
284+
push(std::get<gpreg>(frame->regs.getDwarf(op - DW_OP_breg0)) + offset);
287285
break;
288286
}
289287

@@ -444,10 +442,10 @@ ExpressionStack::eval(Process &proc, Dwarf::DWARFReader &r, const StackFrame *fr
444442
case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31:
445443
isValue = true;
446444
inReg = op - DW_OP_reg0;
447-
push(Elf::getReg(frame->regs, op - DW_OP_reg0));
445+
push(std::get<gpreg>(frame->regs.getDwarf(op - DW_OP_reg0)));
448446
break;
449447
case DW_OP_regx:
450-
push(Elf::getReg(frame->regs, int(r.getsleb128())));
448+
push(std::get<gpreg>(frame->regs.getDwarf(size_t(r.getsleb128()))));
451449
break;
452450

453451
case DW_OP_entry_value:
@@ -505,14 +503,14 @@ ExpressionStack::eval(Process &proc, Dwarf::DWARFReader &r, const StackFrame *fr
505503
}
506504

507505

508-
StackFrame::StackFrame(UnwindMechanism mechanism, const Elf::CoreRegisters &regs_)
506+
StackFrame::StackFrame(UnwindMechanism mechanism, const CoreRegisters &regs_)
509507
: regs(regs_)
510508
, cfa(0)
511509
, mechanism(mechanism)
512510
{
513511
}
514512

515-
std::optional<Elf::CoreRegisters> StackFrame::unwind(Process &p) {
513+
std::optional<CoreRegisters> StackFrame::unwind(Process &p) {
516514
ProcessLocation location = scopeIP(p);
517515

518516
const Dwarf::CFI *cfi = location.cfi();
@@ -541,20 +539,20 @@ std::optional<Elf::CoreRegisters> StackFrame::unwind(Process &p) {
541539

542540
// Given the registers available, and the state of the call unwind data,
543541
// calculate the CFA at this point.
544-
Elf::CoreRegisters out;
542+
CoreRegisters out;
545543
switch (dcf.cfaValue.type) {
546544
case SAME:
547545
case UNDEF:
548546
case ARCH:
549-
cfa = Elf::getReg(regs, dcf.cfaReg);
547+
cfa = std::get<gpreg>(regs.getDwarf(dcf.cfaReg));
550548
break;
551549
case VAL_OFFSET:
552550
case VAL_EXPRESSION:
553551
case REG:
554552
throw (Exception() << "unhandled CFA value type " << dcf.cfaValue.type);
555553

556554
case OFFSET:
557-
cfa = Elf::getReg(regs, dcf.cfaReg) + dcf.cfaValue.u.offset;
555+
cfa = std::get<gpreg>(regs.getDwarf(dcf.cfaReg)) + dcf.cfaValue.u.offset;
558556
break;
559557

560558
case EXPRESSION: {
@@ -567,48 +565,51 @@ std::optional<Elf::CoreRegisters> StackFrame::unwind(Process &p) {
567565
}
568566
default:
569567
cfa = -1;
568+
break;
570569
}
571570
auto rarInfo = dcf.registers.find(cie->rar);
572571

573-
for (const auto &entry : dcf.registers) {
574-
const RegisterUnwind &unwind = entry.second;
575-
int regno = entry.first;
576-
try {
577-
switch (unwind.type) {
578-
case ARCH:
572+
573+
out = regs;
579574
#ifdef CFA_RESTORE_REGNO
580-
// "The CFA is defined to be the stack pointer in the calling frame."
581-
if (regno == CFA_RESTORE_REGNO)
582-
Elf::setReg(out, regno, cfa);
583-
else
584-
Elf::setReg(out, regno, Elf::getReg(regs, regno));
585-
break;
575+
// "The CFA is defined to be the stack pointer in the calling frame."
576+
out.setDwarf(CFA_RESTORE_REGNO, RegisterValue{cfa} );
586577
#endif
587-
case UNDEF:
588-
case SAME:
589-
Elf::setReg(out, regno, Elf::getReg(regs, regno));
590-
break;
591-
case OFFSET: // XXX: assume addrLen = sizeof Elf_Addr
592-
Elf::setReg(out, regno, p.io->readObj<Elf::Addr>(cfa + unwind.u.offset));
578+
for (const auto &[regno, unwind] : dcf.registers) {
579+
try {
580+
switch (unwind.type) {
581+
case OFFSET: {
582+
RegisterFromReader rfr(*p.io, cfa + unwind.u.offset);
583+
out.setDwarf(regno, rfr);
593584
break;
585+
}
586+
594587
case REG:
595-
Elf::setReg(out, regno, Elf::getReg(out,unwind.u.reg));
588+
out.setDwarf(regno, regs.getDwarf(unwind.u.reg));
596589
break;
590+
597591
case VAL_EXPRESSION:
598592
case EXPRESSION: {
599593
ExpressionStack stack;
600594
stack.push(cfa);
601595
DWARFReader reader(cfi->io, unwind.u.expression.offset,
602596
unwind.u.expression.offset + unwind.u.expression.length);
603-
auto val = stack.eval(p, reader, this, location.elfReloc());
597+
auto val = gpreg(stack.eval(p, reader, this, location.elfReloc()));
604598
// EXPRESSIONs give an address, VAL_EXPRESSION gives a literal.
605599
if (unwind.type == EXPRESSION)
606600
p.io->readObj(val, &val);
607-
Elf::setReg(out, regno, val);
601+
out.setDwarf(regno, RegisterValue{val});
608602
break;
609603
}
604+
605+
case SAME:
606+
out.setDwarf(regno, regs.getDwarf(regno));
607+
break;
608+
609+
case ARCH:
610610
default:
611611
break;
612+
612613
}
613614
}
614615
catch (const Exception &ex) {
@@ -620,13 +621,12 @@ std::optional<Elf::CoreRegisters> StackFrame::unwind(Process &p) {
620621
}
621622

622623
// If the return address isn't defined, then we can't unwind.
623-
if (rarInfo == dcf.registers.end() || rarInfo->second.type == UNDEF || cfa == 0) {
624+
if ((rarInfo != dcf.registers.end() && rarInfo->second.type == UNDEF) || cfa == 0) {
624625
if (p.context.verbose > 1) {
625626
*p.context.debug << "DWARF unwinding stopped at "
626627
<< std::hex << location.location() << std::dec
627628
<< ": " <<
628-
(rarInfo == dcf.registers.end() ? "no RAR register found"
629-
: rarInfo->second.type == UNDEF ? "RAR register undefined"
629+
(rarInfo == dcf.registers.end() ? "RAR register undefined"
630630
: "null CFA for frame")
631631
<< std::endl;
632632
}
@@ -636,7 +636,7 @@ std::optional<Elf::CoreRegisters> StackFrame::unwind(Process &p) {
636636
// We know the RAR is defined, so make that the instruction pointer in the
637637
// new frame.
638638
if (cie && cie->rar != IPREG)
639-
Elf::setReg(out, IPREG, Elf::getReg(out, cie->rar));
639+
out.setDwarf(IPREG, out.getDwarf(cie->rar));
640640
return out;
641641
}
642642

heap.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,8 @@ getframe(void ***bp, void ***ip) {
351351
void
352352
getframe(void ***bp, void ***ip) {
353353
//XXX: TODO: support aarch64
354+
(void)bp;
355+
(void)ip;
354356
}
355357
#else
356358

0 commit comments

Comments
 (0)