Skip to content

Commit 0ece0f3

Browse files
khueyrocallahan
authored andcommitted
Use PT_INTERP to find the dynamic linker/program interpreter and record that information in the trace, for later use by --serve-files.
1 parent ef6c92a commit 0ece0f3

10 files changed

Lines changed: 155 additions & 7 deletions

src/AddressSpace.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,12 @@ class AddressSpace : public HasTaskSet {
359359
*/
360360
const std::string& exe_image() const { return exe; }
361361

362+
const std::string& interp_name() const { return interp_name_; }
363+
void set_interp_name(std::string name) { interp_name_ = name; }
364+
365+
remote_ptr<void> interp_base() const { return interp_base_; }
366+
void set_interp_base(remote_ptr<void> base) { interp_base_ = base; }
367+
362368
/**
363369
* Assuming the last retired instruction has raised a SIGTRAP
364370
* and might be a breakpoint trap instruction, return the type
@@ -1080,6 +1086,10 @@ class AddressSpace : public HasTaskSet {
10801086
/* Path of the real executable image this address space was
10811087
* exec()'d with. */
10821088
std::string exe;
1089+
/* Path of the intepreter, if any, of exe. */
1090+
std::string interp_name_;
1091+
/* Base address of the interpeter (might be null!) */
1092+
remote_ptr<void> interp_base_;
10831093
/* Pid of first task for this address space */
10841094
pid_t leader_tid_;
10851095
/* Serial number of first task for this address space */

src/ElfReader.cc

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class ElfReaderImplBase {
2424
virtual Debuglink read_debuglink() = 0;
2525
virtual Debugaltlink read_debugaltlink() = 0;
2626
virtual string read_buildid() = 0;
27+
virtual string read_interp() = 0;
2728
virtual bool addr_to_offset(uintptr_t addr, uintptr_t& offset) = 0;
2829
virtual SectionOffsets find_section_file_offsets(const char* name) = 0;
2930
virtual const vector<uint8_t>* decompress_section(SectionOffsets offsets) = 0;
@@ -44,15 +45,19 @@ template <typename Arch> class ElfReaderImpl : public ElfReaderImplBase {
4445
virtual Debuglink read_debuglink() override;
4546
virtual Debugaltlink read_debugaltlink() override;
4647
virtual string read_buildid() override;
48+
virtual string read_interp() override;
4749
virtual bool addr_to_offset(uintptr_t addr, uintptr_t& offset) override;
4850
virtual SectionOffsets find_section_file_offsets(const char* name) override;
4951
virtual const vector<uint8_t>* decompress_section(SectionOffsets offsets) override;
5052

5153
private:
5254
const typename Arch::ElfShdr* find_section(const char* n);
55+
const typename Arch::ElfPhdr* find_programheader(uint32_t pt);
5356

5457
const typename Arch::ElfEhdr* elfheader;
58+
const typename Arch::ElfPhdr* programheader;
5559
const typename Arch::ElfShdr* sections;
60+
size_t programheader_size;
5661
size_t sections_size;
5762
vector<char> section_names;
5863
};
@@ -75,11 +80,20 @@ ElfReaderImpl<Arch>::ElfReaderImpl(ElfReader& r) : ElfReaderImplBase(r) {
7580
elfheader->e_ident[EI_DATA] != Arch::elfendian ||
7681
elfheader->e_machine != Arch::elfmachine ||
7782
elfheader->e_shentsize != sizeof(typename Arch::ElfShdr) ||
83+
elfheader->e_phentsize != sizeof(typename Arch::ElfPhdr) ||
7884
elfheader->e_shstrndx >= elfheader->e_shnum) {
7985
LOG(debug) << "Invalid ELF file: invalid header";
8086
return;
8187
}
8288

89+
programheader =
90+
r.read<typename Arch::ElfPhdr>(elfheader->e_phoff, elfheader->e_phnum);
91+
if (!programheader || !elfheader->e_phnum) {
92+
LOG(debug) << "Invalid ELF file: no program headers";
93+
return;
94+
}
95+
programheader_size = elfheader->e_phnum;
96+
8397
sections =
8498
r.read<typename Arch::ElfShdr>(elfheader->e_shoff, elfheader->e_shnum);
8599
if (!sections || !elfheader->e_shnum) {
@@ -103,6 +117,23 @@ ElfReaderImpl<Arch>::ElfReaderImpl(ElfReader& r) : ElfReaderImplBase(r) {
103117
ok_ = true;
104118
}
105119

120+
template <typename Arch>
121+
const typename Arch::ElfPhdr* ElfReaderImpl<Arch>::find_programheader(uint32_t pt) {
122+
const typename Arch::ElfPhdr* ph = nullptr;
123+
124+
for (size_t i = 0; i < programheader_size; ++i) {
125+
auto& p = programheader[i];
126+
if (p.p_type == pt) {
127+
ph = &p;
128+
}
129+
}
130+
131+
if (!ph) {
132+
LOG(debug) << "Missing program header " << pt;
133+
}
134+
return ph;
135+
}
136+
106137
template <typename Arch>
107138
const typename Arch::ElfShdr* ElfReaderImpl<Arch>::find_section(const char* n) {
108139
const typename Arch::ElfShdr* section = nullptr;
@@ -438,6 +469,28 @@ string ElfReaderImpl<Arch>::read_buildid() {
438469
return result;
439470
}
440471

472+
template <typename Arch>
473+
string ElfReaderImpl<Arch>::read_interp() {
474+
string result;
475+
if (!ok()) {
476+
return result;
477+
}
478+
479+
const typename Arch::ElfPhdr* ph = find_programheader(PT_INTERP);
480+
if (!ph) {
481+
return result;
482+
}
483+
484+
const char* file_name = r.read<char>(ph->p_offset, ph->p_filesz);
485+
if (!file_name) {
486+
LOG(warn) << "Invalid ELF file: can't read PT_INTERP";
487+
return result;
488+
}
489+
490+
null_terminated(file_name, ph->p_filesz, result);
491+
return result;
492+
}
493+
441494
template <typename Arch>
442495
bool ElfReaderImpl<Arch>::addr_to_offset(uintptr_t addr, uintptr_t& offset) {
443496
for (size_t i = 0; i < sections_size; ++i) {
@@ -492,6 +545,7 @@ DwarfSpan ElfReader::dwarf_section(const char* name, bool known_to_be_compressed
492545
}
493546

494547
string ElfReader::read_buildid() { return impl().read_buildid(); }
548+
string ElfReader::read_interp() { return impl().read_interp(); }
495549

496550
bool ElfReader::addr_to_offset(uintptr_t addr, uintptr_t& offset) {
497551
return impl().addr_to_offset(addr, offset);

src/ElfReader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ class ElfReader {
101101
Debuglink read_debuglink();
102102
Debugaltlink read_debugaltlink();
103103
std::string read_buildid();
104+
std::string read_interp();
104105
// Returns true and sets file |offset| if ELF address |addr| is mapped from
105106
// a section in the ELF file. Returns false if no section maps to
106107
// |addr|. |addr| is an address indicated by the ELF file, not its

src/GdbServer.cc

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2097,6 +2097,10 @@ int GdbServer::open_file(Session& session, Task* continue_task, const std::strin
20972097
// XXX should we require file_scope_pid == 0 here?
20982098
ScopedFd contents;
20992099

2100+
if (file_name.empty()) {
2101+
return -1;
2102+
}
2103+
21002104
LOG(debug) << "Trying to open " << file_name;
21012105

21022106
if (file_name.substr(0, 6) == "/proc/") {
@@ -2123,6 +2127,17 @@ int GdbServer::open_file(Session& session, Task* continue_task, const std::strin
21232127
} else {
21242128
return -1;
21252129
}
2130+
} else if (file_name == continue_task->vm()->interp_name()) {
2131+
remote_ptr<void> interp_base = continue_task->vm()->interp_base();
2132+
auto m = continue_task->vm()->mapping_of(interp_base);
2133+
LOG(debug) << "Found dynamic linker as memory mapping " << m.recorded_map;
2134+
int ret_fd = 0;
2135+
while (files.find(ret_fd) != files.end() ||
2136+
memory_files.find(ret_fd) != memory_files.end()) {
2137+
++ret_fd;
2138+
}
2139+
memory_files.insert(make_pair(ret_fd, FileId(m.recorded_map)));
2140+
return ret_fd;
21262141
} else {
21272142
// See if we can find the file by serving one of our mappings
21282143
std::string normalized_file_name = file_name;
@@ -2132,9 +2147,8 @@ int GdbServer::open_file(Session& session, Task* continue_task, const std::strin
21322147
// kernel when the process image gets loaded. We add a special case to
21332148
// substitute the correct mapping, so gdb can find the dynamic linker
21342149
// rendezvous structures.
2135-
// XXX: These don't tend to vary across systems, so hardcoding them here works
2136-
// ok, but it'd be better, to just read INTERP from the main executable
2137-
// and record which is the corresponding file.
2150+
// Use our old hack for ld from before we read PT_INTERP for backwards
2151+
// compat with older traces.
21382152
if (m.recorded_map.fsname().compare(0,
21392153
normalized_file_name.length(),
21402154
normalized_file_name) == 0

src/TraceStream.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,8 @@ void TraceWriter::write_task_event(const TraceTaskEvent& event) {
742742
cmd_line.set(i, str_to_data(event_cmd_line[i]));
743743
}
744744
exec.setExeBase(event.exe_base().as_int());
745+
exec.setInterpBase(event.interp_base().as_int());
746+
exec.setInterpName(str_to_data(event.interp_name()));;
745747
break;
746748
}
747749
case TraceTaskEvent::EXIT:
@@ -802,6 +804,8 @@ TraceTaskEvent TraceReader::read_task_event(FrameTime* time) {
802804
r.cmd_line_[i] = data_to_str(cmd_line[i]);
803805
}
804806
r.exe_base_ = exec.getExeBase();
807+
r.interp_base_ = exec.getInterpBase();
808+
r.interp_name_ = data_to_str(exec.getInterpName());
805809
break;
806810
}
807811
case trace::TaskEvent::Which::EXIT:

src/TraceTaskEvent.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,23 @@ class TraceTaskEvent {
8888
DEBUG_ASSERT(type() == EXEC);
8989
exe_base_ = ptr;
9090
}
91+
// May be zero at any time.
92+
remote_ptr<void> interp_base() const {
93+
DEBUG_ASSERT(type() == EXEC);
94+
return interp_base_;
95+
}
96+
void set_interp_base(remote_ptr<void> ptr) {
97+
DEBUG_ASSERT(type() == EXEC);
98+
interp_base_ = ptr;
99+
}
100+
const std::string& interp_name() const {
101+
DEBUG_ASSERT(type() == EXEC);
102+
return interp_name_;
103+
}
104+
void set_interp_name(std::string name) {
105+
DEBUG_ASSERT(type() == EXEC);
106+
interp_name_ = name;
107+
}
91108
WaitStatus exit_status() const {
92109
DEBUG_ASSERT(type() == EXIT);
93110
return exit_status_;
@@ -105,6 +122,8 @@ class TraceTaskEvent {
105122
std::string file_name_; // EXEC only
106123
std::vector<std::string> cmd_line_; // EXEC only
107124
remote_ptr<void> exe_base_; // EXEC only
125+
remote_ptr<void> interp_base_; // EXEC only
126+
std::string interp_name_; // EXEC only
108127
WaitStatus exit_status_; // EXIT only
109128
};
110129

src/kernel_abi.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,18 @@ struct WordSize32Defs {
241241
uint16_t e_shstrndx;
242242
} ElfEhdr;
243243
RR_VERIFY_TYPE_ARCH(RR_NATIVE_ARCH, ::Elf32_Ehdr, ElfEhdr);
244+
typedef struct
245+
{
246+
uint32_t p_type;
247+
uint32_t p_offset;
248+
uint32_t p_vaddr;
249+
uint32_t p_paddr;
250+
uint32_t p_filesz;
251+
uint32_t p_memsz;
252+
uint32_t p_flags;
253+
uint32_t p_align;
254+
} ElfPhdr;
255+
RR_VERIFY_TYPE_ARCH(RR_NATIVE_ARCH, ::Elf32_Phdr, ElfPhdr);
244256
typedef struct {
245257
uint32_t sh_name;
246258
uint32_t sh_type;
@@ -326,6 +338,18 @@ struct WordSize64Defs {
326338
uint16_t e_shstrndx;
327339
} ElfEhdr;
328340
RR_VERIFY_TYPE_ARCH(RR_NATIVE_ARCH, ::Elf64_Ehdr, ElfEhdr);
341+
typedef struct
342+
{
343+
uint32_t p_type;
344+
uint32_t p_flags;
345+
uint64_t p_offset;
346+
uint64_t p_vaddr;
347+
uint64_t p_paddr;
348+
uint64_t p_filesz;
349+
uint64_t p_memsz;
350+
uint64_t p_align;
351+
} ElfPhdr;
352+
RR_VERIFY_TYPE_ARCH(RR_NATIVE_ARCH, ::Elf64_Phdr, ElfPhdr);
329353
typedef struct {
330354
uint32_t sh_name;
331355
uint32_t sh_type;

src/record_syscall.cc

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5423,17 +5423,21 @@ static uint64_t word_at(uint8_t* buf, size_t wsize) {
54235423
return u.v;
54245424
}
54255425

5426-
static remote_ptr<void> get_exe_entry(Task* t) {
5426+
static pair<remote_ptr<void>, remote_ptr<void>> get_exe_entry_interp_base(Task* t) {
5427+
remote_ptr<void> exe_entry;
5428+
remote_ptr<void> interp_base;
54275429
vector<uint8_t> v = read_auxv(t);
54285430
size_t i = 0;
54295431
size_t wsize = word_size(t->arch());
54305432
while ((i + 1)*wsize*2 <= v.size()) {
54315433
if (word_at(v.data() + i*2*wsize, wsize) == AT_ENTRY) {
5432-
return word_at(v.data() + (i*2 + 1)*wsize, wsize);
5434+
exe_entry = word_at(v.data() + (i*2 + 1)*wsize, wsize);
5435+
} else if (word_at(v.data() + i*2*wsize, wsize) == AT_BASE) {
5436+
interp_base = word_at(v.data() + (i*2 + 1)*wsize, wsize);
54335437
}
54345438
++i;
54355439
}
5436-
return remote_ptr<void>();
5440+
return make_pair(exe_entry, interp_base);
54375441
}
54385442

54395443
/**
@@ -5469,6 +5473,7 @@ static void process_execve(RecordTask* t, TaskSyscallState& syscall_state) {
54695473
return;
54705474
}
54715475

5476+
string interp_name;
54725477
{
54735478
std::string exe_path = t->proc_exe_path();
54745479
ScopedFd fd(exe_path.c_str(), O_RDONLY);
@@ -5481,6 +5486,9 @@ static void process_execve(RecordTask* t, TaskSyscallState& syscall_state) {
54815486
FATAL() << "rr does not support the x32 ABI, but " << t->exe_path()
54825487
<< " is an x32 ABI program.";
54835488
}
5489+
5490+
ElfFileReader reader(fd);
5491+
interp_name = reader.read_interp();
54845492
}
54855493

54865494
t->post_exec_syscall();
@@ -5513,8 +5521,11 @@ static void process_execve(RecordTask* t, TaskSyscallState& syscall_state) {
55135521

55145522
// get the remote executable entry point
55155523
// with the pointer, we find out which mapping is the executable
5516-
auto exe_entry = get_exe_entry(t);
5524+
auto auxv_pointers = get_exe_entry_interp_base(t);
5525+
auto exe_entry = auxv_pointers.first;
5526+
auto interp_base = auxv_pointers.second;
55175527
ASSERT(t, !exe_entry.is_null()) << "AT_ENTRY not found";
5528+
// NB: A binary is not required to have an interpreter.
55185529

55195530
// Write out stack mappings first since during replay we need to set up the
55205531
// stack before any files get mapped.
@@ -5534,6 +5545,12 @@ static void process_execve(RecordTask* t, TaskSyscallState& syscall_state) {
55345545
ASSERT(t, km.prot() & PROT_EXEC) << "Entry point not in executable code?";
55355546
syscall_state.exec_saved_event->set_exe_base(km.start());
55365547
}
5548+
if (km.start() == interp_base) {
5549+
t->vm()->set_interp_base(interp_base);
5550+
syscall_state.exec_saved_event->set_interp_base(interp_base);
5551+
t->vm()->set_interp_name(interp_name);
5552+
syscall_state.exec_saved_event->set_interp_name(interp_name);
5553+
}
55375554
}
55385555
ASSERT(t, !syscall_state.exec_saved_event->exe_base().is_null());
55395556

src/replay_syscall.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,8 @@ static void process_execve(ReplayTask* t, const TraceFrame& trace_frame,
448448
? kms[exe_km].fsname()
449449
: datas[exe_km].file_name;
450450
t->post_exec_syscall(exe_name, kms[exe_km].fsname());
451+
t->vm()->set_interp_base(tte.interp_base());
452+
t->vm()->set_interp_name(tte.interp_name());
451453

452454
t->fd_table()->close_after_exec(
453455
t, t->current_trace_frame().event().Syscall().exec_fds_to_close);

src/rr_trace.capnp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ struct TaskEvent {
196196
# Never null (in traces that support the field)
197197
# Added after 5.0.0
198198
exeBase @8 :RemotePtr;
199+
interpBase @10 :RemotePtr;
200+
# Not a Path since it is only meaningful during recording
201+
interpName @11 :CString;
199202
}
200203
# Most frame 'exit' events generate one of these, but these are not
201204
# generated if rr ends abnormally so the tasks did not in fact exit during

0 commit comments

Comments
 (0)