This repository has been archived by the owner on Sep 11, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathLiveDebugger.cpp
102 lines (90 loc) · 2.87 KB
/
LiveDebugger.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* Copyright © 2016-2024 Byteduck */
#include "LiveDebugger.h"
#include <sys/ptrace.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <libduck/MappedBuffer.h>
using namespace Debug;
using Duck::Result, Duck::ResultRet;
Result LiveDebugger::attach(pid_t pid, tid_t tid) {
if (ptrace(PTRACE_ATTACH, tid, nullptr, nullptr) < 0)
return Result(errno);
m_pid = pid;
m_tid = tid;
TRYRES(reload_process_info());
return Result::SUCCESS;
}
ResultRet<uintptr_t> Debug::LiveDebugger::peek(size_t addr) {
if (!m_pid || !m_tid)
return Result("Not attached");
uintptr_t data;
if (ptrace(PTRACE_PEEK, m_tid, (void*) addr, &data) < 0)
return Result(errno);
return data;
}
Result LiveDebugger::poke(size_t addr, uintptr_t val) {
if (!m_pid || !m_tid)
return Result("Not attached");
if (ptrace(PTRACE_POKE, m_tid, (void*) addr, (void*) val) < 0)
return Result(errno);
return Result::SUCCESS;
}
ResultRet<Sys::Process::MemoryRegion> LiveDebugger::region_at(size_t addr) {
for (auto& region : m_memory_regions) {
if (region.start + region.size > addr) {
// Assume they're in order
if (region.start > addr)
return Result("No such memory region");
return region;
}
}
return Result("No such memory region");
}
ResultRet<Exec::Object*> LiveDebugger::object_at(size_t addr) {
auto reg = TRY(region_at(addr));
if (reg.type != Sys::Process::MemoryRegion::Inode)
return Result("Region not an object");
auto loadedobj = m_objects.find(reg.name);
if (loadedobj != m_objects.end()) {
auto obj = loadedobj->second.get();
if (!obj)
return Result("No object at region"); // Previously failed to load
return obj;
}
auto do_load = [&] () -> ResultRet<Duck::Ptr<Exec::Object>> {
auto objfile = TRY(Duck::File::open(reg.name, "r"));
auto mappedfile = TRY(Duck::MappedBuffer::make_file(objfile, Duck::MappedBuffer::R, Duck::MappedBuffer::SharedFile));
auto obj = std::make_shared<Exec::Object>();
obj->fd = objfile.fd();
obj->mapped_file = mappedfile->data<uint8_t>();
obj->mapped_size = mappedfile->size();
obj->memloc = reg.start;
obj->fd = objfile.fd();
obj->name = Duck::Path(reg.name).basename();
TRYRES(obj->load_for_debugger());
objfile.set_close_on_destroy(false);
mappedfile->set_unmap_on_destroy(false);
return obj;
};
auto load_res = do_load();
if (load_res.is_error()) {
m_objects[reg.name] = nullptr;
return load_res.result();
}
m_objects[reg.name] = load_res.value();
return load_res.value().get();
}
Duck::ResultRet<PTraceRegisters> LiveDebugger::get_registers() {
if (!m_pid || !m_tid)
return Result("Not attached");
PTraceRegisters ret;
if (ptrace(PTRACE_GETREGS, m_tid, nullptr, &ret) < 0)
return Result(errno);
return ret;
}
Result LiveDebugger::reload_process_info() {
m_process = TRY(Sys::Process::get(m_pid));
m_memory_regions = TRY(m_process.memory_regions());
return Result::SUCCESS;
}