reverie/tests/backtrace.rs
Jason White 60e67eab1b Add file and line info to backtraces
Summary:
Adds file and line number resolution to backtraces. This also adds a 1GB limit on the amount of in-memory symbols at any given time. If the internal symbol cache exceeds this, the oldest entries will be discarded until we're under that limit again. We may need to tweak this and make it more configurable in the future.

Follow-up: Auxiliary debug files, such as `.debug` files, are not supported. This should be easy to support by reading the `gnu_debuglink` section and finding the `.debug` file.

Reviewed By: johnhurt

Differential Revision: D33086623

fbshipit-source-id: 43112e3bdd135a1a43ca75c10756cc8ec101c9b8
2022-01-26 14:23:10 -08:00

69 lines
1.8 KiB
Rust

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
//! Tests for getting backtraces from the guest.
#![cfg(not(sanitized))]
use reverie::syscalls::Syscall;
use reverie::Error;
use reverie::ExitStatus;
use reverie::Guest;
use reverie::Tool;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
struct TestTool;
#[reverie::tool]
impl Tool for TestTool {
async fn handle_syscall_event<T: Guest<Self>>(
&self,
guest: &mut T,
syscall: Syscall,
) -> Result<i64, Error> {
if let Syscall::Getpid(_) = &syscall {
let backtrace = guest
.backtrace()
.expect("failed to get backtrace from guest");
// There's no guarantee our function is at the top of the stack, so
// we simply assert that it is *somewhere* in the stack.
assert!(
backtrace.iter().any(|frame| {
if let Some(symbol) = &frame.symbol {
// Due to name mangling, there won't be an exact match.
symbol.name.contains("funky_function")
} else {
false
}
}),
"guest backtrace did not contain our expected function:\n{}",
backtrace.pretty().unwrap()
);
}
Ok(guest.inject(syscall).await?)
}
}
#[inline(never)]
fn funky_function() {
let _ = unsafe { libc::getpid() };
}
#[test]
fn smoke() {
use reverie_ptrace::testing::test_fn;
let (output, _) = test_fn::<TestTool, _>(funky_function).unwrap();
assert_eq!(output.status, ExitStatus::Exited(0));
}