Skip to content
This repository has been archived by the owner on Nov 1, 2023. It is now read-only.

Add context to coverage tracing errors #979

Merged
merged 6 commits into from
Jun 10, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 35 additions & 15 deletions src/agent/coverage/src/block/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,28 @@ impl<'c> Recorder<'c> {
options.remove(Options::PTRACE_O_TRACEFORK);
options.remove(Options::PTRACE_O_TRACEVFORK);
options.remove(Options::PTRACE_O_TRACEEXEC);
tracee.set_options(options)?;
tracee
.set_options(options)
.context("setting tracee options")?;

self.images = Some(Images::new(tracee.pid.as_raw()));
self.update_images(&mut tracee)?;
self.update_images(&mut tracee)
.context("initial update of module images")?;

self.tracer.restart(tracee, Restart::Syscall)?;
self.tracer
.restart(tracee, Restart::Syscall)
.context("initial tracer restart")?;

while let Some(mut tracee) = self.tracer.wait()? {
while let Some(mut tracee) = self.tracer.wait().context("main tracing loop")? {
match tracee.stop {
Stop::SyscallEnterStop(..) => log::trace!("syscall-enter: {:?}", tracee.stop),
Stop::SyscallExitStop(..) => {
self.update_images(&mut tracee)?;
self.update_images(&mut tracee)
.context("updating module images after syscall-stop")?;
}
Stop::SignalDeliveryStop(_pid, Signal::SIGTRAP) => {
self.on_breakpoint(&mut tracee)?;
self.on_breakpoint(&mut tracee)
.context("calling breakpoint handler")?;
}
Stop::Clone(pid, tid) => {
// Only seen when the `VM_CLONE` flag is set, as of Linux 4.15.
Expand Down Expand Up @@ -113,7 +120,8 @@ impl<'c> Recorder<'c> {

for (_base, image) in &events.loaded {
if self.filter.includes_module(image.path()) {
self.on_module_load(tracee, image)?;
self.on_module_load(tracee, image)
.context("module load callback")?;
}
}

Expand All @@ -137,12 +145,16 @@ impl<'c> Recorder<'c> {
.find_va_image(pc)
.ok_or_else(|| format_err!("unable to find image for va = {:x}", pc))?;

let offset = image.va_to_offset(pc)?;
let offset = image
.va_to_offset(pc)
.context("converting PC to module offset")?;
self.coverage.increment(image.path(), offset);

// Execute clobbered instruction on restart.
regs.rip = pc;
tracee.set_registers(regs)?;
tracee
.set_registers(regs)
.context("resetting PC in breakpoint handler")?;
} else {
// Assume the tracee concurrently executed an `int3` that we restored
// in another handler.
Expand All @@ -151,7 +163,9 @@ impl<'c> Recorder<'c> {
// clearing, but making their value a state.
log::debug!("no breakpoint at {:x}, assuming race", pc);
regs.rip = pc;
tracee.set_registers(regs)?;
tracee
.set_registers(regs)
.context("resetting PC after ignoring spurious breakpoint")?;
}

Ok(())
Expand Down Expand Up @@ -233,11 +247,11 @@ impl Images {
}

pub fn update(&mut self) -> Result<LoadEvents> {
let proc = Process::new(self.pid)?;
let proc = Process::new(self.pid).context("getting procinfo")?;

let mut new = BTreeMap::default();

for map in proc.maps()? {
for map in proc.maps().context("getting maps for process")? {
if let Ok(image) = ModuleImage::new(map) {
new.insert(image.base(), image);
}
Expand Down Expand Up @@ -374,7 +388,9 @@ impl Breakpoints {
let mut data = [0u8];
tracee.read_memory_mut(va, &mut data)?;
self.saved.insert(va, data[0]);
tracee.write_memory(va, &[0xcc])?;
tracee
.write_memory(va, &[0xcc])
.context("setting breakpoint, writing int3")?;

Ok(())
}
Expand All @@ -383,7 +399,9 @@ impl Breakpoints {
let data = self.saved.remove(&va);

let cleared = if let Some(data) = data {
tracee.write_memory(va, &[data])?;
tracee
.write_memory(va, &[data])
.context("clearing breakpoint, restoring byte")?;
true
} else {
false
Expand All @@ -399,7 +417,9 @@ fn continue_to_init_execve(tracer: &mut Ptracer) -> Result<Tracee> {
return Ok(tracee);
}

tracer.restart(tracee, Restart::Continue)?;
tracer
.restart(tracee, Restart::Continue)
.context("restarting tracee pre-execve()")?;
}

anyhow::bail!("did not see initial execve() in tracee while recording coverage");
Expand Down
15 changes: 9 additions & 6 deletions src/agent/coverage/src/block/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::collections::BTreeMap;
use std::process::Command;
use std::time::{Duration, Instant};

use anyhow::Result;
use anyhow::{Context, Result};
use debugger::{BreakpointId, BreakpointType, DebugEventHandler, Debugger, ModuleLoadInfo};

use crate::block::CommandBlockCov;
Expand Down Expand Up @@ -50,8 +50,8 @@ impl<'r, 'c> RecorderEventHandler<'r, 'c> {
}

pub fn run(&mut self, cmd: Command) -> Result<()> {
let (mut dbg, _child) = Debugger::init(cmd, self)?;
dbg.run(self)?;
let (mut dbg, _child) = Debugger::init(cmd, self).context("initializing debugger")?;
dbg.run(self).context("running debuggee")?;
Ok(())
}

Expand Down Expand Up @@ -129,7 +129,9 @@ impl<'c> Recorder<'c> {
if log::max_level() == log::Level::Trace {
let name = breakpoint.module.name().to_string_lossy();
let offset = breakpoint.offset;
let pc = dbg.read_program_counter()?;
let pc = dbg
.read_program_counter()
.context("reading PC on breakpoint")?;

if let Ok(sym) = dbg.get_symbol(pc) {
log::trace!(
Expand Down Expand Up @@ -161,7 +163,7 @@ impl<'c> Recorder<'c> {
}

fn insert_module(&mut self, dbg: &mut Debugger, module: &ModuleLoadInfo) -> Result<()> {
let path = ModulePath::new(module.path().to_owned())?;
let path = ModulePath::new(module.path().to_owned()).context("parsing module path")?;

if !self.filter.includes_module(&path) {
log::debug!("skipping module: {}", path);
Expand All @@ -182,7 +184,8 @@ impl<'c> Recorder<'c> {
}

self.breakpoints
.set(dbg, module, info.blocks.iter().copied())?;
.set(dbg, module, info.blocks.iter().copied())
.context("setting breakpoints for module")?;

log::debug!("set {} breakpoints for module {}", info.blocks.len(), path);
}
Expand Down