Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration with binsider #45

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
1,577 changes: 1,418 additions & 159 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,14 @@ serde = { version = "1.0.164", features = ["derive"] }
toml = "0.8.13"
home = "0.5.9"
which = "6.0.1"
ratatui = { version = "0.28", optional = true }
binsider = { git = "https://github.com/godzie44/binsider.git", branch = "godzie44/run_as_widget", optional = true }

[dev-dependencies]
serial_test = "3.0.0"

[features]
default = ["libunwind"]
default = ["libunwind", "binsider-integration"]
libunwind = ["unwind"]
binsider-integration = ["binsider", "ratatui"]
int_test = []
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
* [Other commands](#other-commands)
* [Tui interface](#tui-interface)
* [Configuration](#configuration)
* [Integrations](#integrations)
* [Binsider](#binsider)
* [Oracles](#oracles)
- [Contributing](#contributing)

Expand Down Expand Up @@ -460,6 +462,18 @@ To override any of the defaults, begin by creating the corresponding file (from
`~/.config/bs/keymap.toml`.
You can change keybindings configuration file by exporting the `KEYMAP_FILE` environment variable.

## Integrations

BugStalker has integration with some useful tools that can help you when researching programs.

### Binsider

According to [official site](https://binsider.dev/), `binsider` offers powerful static and dynamic analysis tools,
similar to readelf(1) and strace(1).
It lets you inspect strings, examine linked libraries, and perform hexdumps, all within a user-friendly TUI.

- `binsider` - run binsider inside a debugger (alias: `bn`)

## Oracles

[demo console](https://github.com/godzie44/BugStalker/blob/master/doc/demo_oracle.gif)
Expand Down
21 changes: 21 additions & 0 deletions examples/vars/src/vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,25 @@ fn uuid() {
let nop: Option<u8> = None;
}

fn datetime() {
use std::ops::Add;
use std::time::{Duration, Instant, SystemTime};

let system_time = SystemTime::UNIX_EPOCH;
let instant = Instant::now().add(Duration::from_secs(10));

let nop: Option<u8> = None;
}

fn thread_local_const_init() {
thread_local! {
static CONSTANT_THREAD_LOCAL: i32 = const { 1337 }
}
CONSTANT_THREAD_LOCAL.with(|ctx| println!("const tls: {ctx}"));

let nop: Option<u8> = None;
}

pub fn main() {
scalar_types();
compound_types();
Expand Down Expand Up @@ -550,4 +569,6 @@ pub fn main() {
inner_static();
shadowing();
uuid();
datetime();
thread_local_const_init();
}
14 changes: 14 additions & 0 deletions src/debugger/debugee/dwarf/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::debugger::error::Error::{
};
use crate::debugger::register::{DwarfRegisterMap, RegisterMap};
use crate::debugger::{debugee, ExplorationContext};
use crate::version::Version;
use bytes::{BufMut, Bytes, BytesMut};
use gimli::{
DebugAddr, Encoding, EndianSlice, EvaluationResult, Expression, Location, Piece, Register,
Expand All @@ -24,8 +25,20 @@ use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::mem;

pub struct EvaluationContext<'a> {
pub evaluator: &'a ExpressionEvaluator<'a>,
pub expl_ctx: &'a ExplorationContext,
}

impl<'a> EvaluationContext<'a> {
pub fn rustc_version(&self) -> Option<Version> {
self.evaluator.unit().rustc_version()
}
}

/// Resolve requirements that the `ExpressionEvaluator` may need. Relevant for the current breakpoint.
/// Some options are lazy to avoid overhead on recalculation.
#[derive(Clone)]
struct RequirementsResolver<'a> {
debugee: &'a Debugee,
cfa: RefCell<HashMap<Pid, RelocatedAddress>>,
Expand Down Expand Up @@ -164,6 +177,7 @@ impl ExternalRequirementsResolver {
}
}

#[derive(Clone)]
pub struct ExpressionEvaluator<'a> {
encoding: Encoding,
unit: &'a Unit,
Expand Down
42 changes: 21 additions & 21 deletions src/debugger/debugee/dwarf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ pub use self::unwind::DwarfUnwinder;

use crate::debugger::address::{GlobalAddress, RelocatedAddress};
use crate::debugger::debugee::dwarf::eval::AddressKind;
use crate::debugger::debugee::dwarf::eval::EvaluationContext;
use crate::debugger::debugee::dwarf::location::Location as DwarfLocation;
use crate::debugger::debugee::dwarf::r#type::ComplexType;
use crate::debugger::debugee::dwarf::r#type::EvaluationContext;
use crate::debugger::debugee::dwarf::symbol::SymbolTab;
use crate::debugger::debugee::dwarf::unit::{
DieRef, DieVariant, DwarfUnitParser, Entry, FunctionDie, Node, ParameterDie,
Expand All @@ -26,7 +26,7 @@ use crate::debugger::error::Error::{
DebugIDFormat, FBANotAnExpression, FunctionNotFound, NoFBA, NoFunctionRanges, UnitNotFound,
};
use crate::debugger::register::{DwarfRegisterMap, RegisterMap};
use crate::debugger::variable::select::ObjectBinaryRepr;
use crate::debugger::variable::ObjectBinaryRepr;
use crate::debugger::ExplorationContext;
use crate::{muted_error, resolve_unit_call, version_switch, weak_error};
use fallible_iterator::FallibleIterator;
Expand Down Expand Up @@ -512,7 +512,7 @@ impl DebugInformation {
&self,
location: Location,
name: &str,
) -> Result<Vec<ContextualDieRef<'_, VariableDie>>, Error> {
) -> Result<Vec<ContextualDieRef<'_, '_, VariableDie>>, Error> {
let units = self.get_units()?;

let mut found = vec![];
Expand Down Expand Up @@ -884,7 +884,7 @@ impl AsAllocatedData for ParameterDie {
}
}

#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct NamespaceHierarchy(Vec<String>);

impl Deref for NamespaceHierarchy {
Expand Down Expand Up @@ -944,11 +944,11 @@ impl NamespaceHierarchy {
}
}

pub struct ContextualDieRef<'a, T> {
pub debug_info: &'a DebugInformation,
pub struct ContextualDieRef<'node, 'dbg: 'node, T> {
pub debug_info: &'dbg DebugInformation,
pub unit_idx: usize,
pub node: &'a Node,
pub die: &'a T,
pub node: &'node Node,
pub die: &'node T,
}

#[macro_export]
Expand All @@ -958,26 +958,26 @@ macro_rules! ctx_resolve_unit_call {
}};
}

impl<'a, T> Clone for ContextualDieRef<'a, T> {
impl<'node, 'dbg, T> Clone for ContextualDieRef<'node, 'dbg, T> {
fn clone(&self) -> Self {
*self
}
}

impl<'a, T> Copy for ContextualDieRef<'a, T> {}
impl<'node, 'dbg, T> Copy for ContextualDieRef<'node, 'dbg, T> {}

impl<'a, T> ContextualDieRef<'a, T> {
impl<'node, 'dbg, T> ContextualDieRef<'node, 'dbg, T> {
pub fn namespaces(&self) -> NamespaceHierarchy {
let entries = ctx_resolve_unit_call!(self, entries,);
NamespaceHierarchy::for_node(self.node, entries)
}

pub fn unit(&self) -> &'a Unit {
pub fn unit(&self) -> &'dbg Unit {
self.debug_info.unit_ensure(self.unit_idx)
}
}

impl<'ctx> ContextualDieRef<'ctx, FunctionDie> {
impl<'ctx> ContextualDieRef<'ctx, 'ctx, FunctionDie> {
pub fn full_name(&self) -> Option<String> {
self.die
.base_attributes
Expand Down Expand Up @@ -1007,7 +1007,7 @@ impl<'ctx> ContextualDieRef<'ctx, FunctionDie> {
pub fn local_variables<'this>(
&'this self,
pc: GlobalAddress,
) -> Vec<ContextualDieRef<'ctx, VariableDie>> {
) -> Vec<ContextualDieRef<'ctx, 'ctx, VariableDie>> {
let mut result = vec![];
let mut queue = VecDeque::from(self.node.children.clone());
while let Some(idx) = queue.pop_front() {
Expand All @@ -1033,7 +1033,7 @@ impl<'ctx> ContextualDieRef<'ctx, FunctionDie> {
&'this self,
pc: GlobalAddress,
needle: &str,
) -> Option<ContextualDieRef<'ctx, VariableDie>> {
) -> Option<ContextualDieRef<'ctx, 'ctx, VariableDie>> {
let mut queue = VecDeque::from(self.node.children.clone());
while let Some(idx) = queue.pop_front() {
let entry = ctx_resolve_unit_call!(self, entry, idx);
Expand All @@ -1054,7 +1054,7 @@ impl<'ctx> ContextualDieRef<'ctx, FunctionDie> {
None
}

pub fn parameters(&self) -> Vec<ContextualDieRef<'_, ParameterDie>> {
pub fn parameters(&self) -> Vec<ContextualDieRef<'ctx, 'ctx, ParameterDie>> {
let mut result = vec![];
for &idx in &self.node.children {
let entry = ctx_resolve_unit_call!(self, entry, idx);
Expand Down Expand Up @@ -1139,7 +1139,7 @@ impl<'ctx> ContextualDieRef<'ctx, FunctionDie> {
}
}

impl<'ctx> ContextualDieRef<'ctx, VariableDie> {
impl<'ctx> ContextualDieRef<'ctx, 'ctx, VariableDie> {
pub fn ranges(&self) -> Option<&[Range]> {
if let Some(lb_idx) = self.die.lexical_block_idx {
let entry = ctx_resolve_unit_call!(self, entry, lb_idx);
Expand All @@ -1160,7 +1160,7 @@ impl<'ctx> ContextualDieRef<'ctx, VariableDie> {
.unwrap_or(true)
}

pub fn assume_parent_function(&self) -> Option<ContextualDieRef<'_, FunctionDie>> {
pub fn assume_parent_function(&self) -> Option<ContextualDieRef<'_, '_, FunctionDie>> {
let mut mb_parent = self.node.parent;

while let Some(p) = mb_parent {
Expand All @@ -1181,7 +1181,7 @@ impl<'ctx> ContextualDieRef<'ctx, VariableDie> {
}
}

impl<'ctx> ContextualDieRef<'ctx, ParameterDie> {
impl<'ctx> ContextualDieRef<'ctx, 'ctx, ParameterDie> {
/// Return max range (with max `end` address) of an underlying function.
/// If it's possible, `end` address in range equals to function epilog begin.
pub fn max_range(&self) -> Option<Range> {
Expand All @@ -1205,7 +1205,7 @@ impl<'ctx> ContextualDieRef<'ctx, ParameterDie> {
}
}

impl<'ctx, D: AsAllocatedData> ContextualDieRef<'ctx, D> {
impl<'ctx, D: AsAllocatedData> ContextualDieRef<'ctx, 'ctx, D> {
pub fn r#type(&self) -> Option<ComplexType> {
let parser = r#type::TypeParser::new();
Some(parser.parse(*self, self.die.type_ref()?))
Expand All @@ -1227,7 +1227,7 @@ impl<'ctx, D: AsAllocatedData> ContextualDieRef<'ctx, D> {
evaluator: &evaluator,
expl_ctx: ctx,
},
r#type.root,
r#type.root(),
)? as usize;
let (address, raw_data) =
weak_error!(eval_result.into_raw_bytes(type_size, AddressKind::MemoryAddress))?;
Expand Down
Loading
Loading