diff --git a/Cargo.lock b/Cargo.lock index 8a01d56..4d63eed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,6 +120,17 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -135,7 +146,7 @@ dependencies = [ "bitflags 2.4.2", "cexpr", "clang-sys", - "itertools", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -234,6 +245,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.0.90" @@ -286,6 +303,17 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags 1.3.2", + "textwrap", + "unicode-width", +] + [[package]] name = "clap" version = "4.5.4" @@ -368,6 +396,42 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +dependencies = [ + "atty", + "cast", + "clap 2.34.0", + "criterion-plot", + "csv", + "itertools 0.10.5", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools 0.10.5", +] + [[package]] name = "crossbeam-channel" version = "0.5.12" @@ -377,12 +441,52 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + [[package]] name = "dashmap" version = "5.5.3" @@ -607,6 +711,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "half" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" + [[package]] name = "hamming" version = "0.1.3" @@ -631,6 +741,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.4" @@ -692,7 +811,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "321f0f839cd44a4686e9504b0a62b4d69a50b62072144c71c68f5873c167b8d9" dependencies = [ "ahash", - "clap", + "clap 4.5.4", "crossbeam-channel", "crossbeam-utils", "dashmap", @@ -727,11 +846,20 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.4", "libc", "windows-sys 0.52.0", ] +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -749,9 +877,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -776,7 +904,7 @@ checksum = "9a58dfb8194a9b8ff960890a8d71e905b4635aa89c3dad4ce6c1a99c2eec759f" dependencies = [ "anyhow", "cargo_metadata", - "clap", + "clap 4.5.4", "libbpf-rs", "libbpf-sys", "memmap2 0.5.10", @@ -844,7 +972,8 @@ dependencies = [ "bindgen", "blazesym", "chrono", - "clap", + "clap 4.5.4", + "criterion", "data-encoding", "errno", "gimli", @@ -1046,7 +1175,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.4", "libc", ] @@ -1088,6 +1217,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + [[package]] name = "overload" version = "0.1.1" @@ -1150,6 +1285,34 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "plotters" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" + +[[package]] +name = "plotters-svg" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +dependencies = [ + "plotters-backend", +] + [[package]] name = "predicates" version = "3.1.0" @@ -1296,6 +1459,26 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -1450,6 +1633,15 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1491,6 +1683,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.195" @@ -1633,6 +1835,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.58" @@ -1663,6 +1874,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "toml_datetime" version = "0.6.5" @@ -1753,6 +1974,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-width" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" + [[package]] name = "untrusted" version = "0.9.0" @@ -1796,6 +2023,16 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1804,9 +2041,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1814,9 +2051,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", @@ -1829,9 +2066,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1839,9 +2076,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", @@ -1852,9 +2089,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "which" @@ -1884,6 +2131,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 188c2cd..a355717 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,12 +32,20 @@ nix = { version = "0.28.0", features = ["user"]} assert_cmd = { version = "2.0.14" } insta = { version = "1.38.0", features = ["yaml"] } rstest = "0.18.2" +criterion = "0.3" [build-dependencies] bindgen = "0.69.4" libbpf-cargo = "0.22.1" glob = "0.3.1" +[[bench]] +name = "unwind_info" +harness = false + +[lib] +bench = false + [profile.dev.package] insta.opt-level = 3 similar.opt-level = 3 diff --git a/benches/unwind_info.rs b/benches/unwind_info.rs new file mode 100644 index 0000000..337979f --- /dev/null +++ b/benches/unwind_info.rs @@ -0,0 +1,17 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use lightswitch::unwind_info::{remove_redundant, remove_unnecesary_markers, to_vec}; + +const NODE_EXE: &'static str = "/opt/redpanda/libexec/redpanda"; + +pub fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("unwind info + sorting", |b| { + b.iter(|| { + let mut found_unwind_info = to_vec(NODE_EXE).unwrap(); + remove_unnecesary_markers(&mut found_unwind_info); + black_box(remove_redundant(&mut found_unwind_info)); + }) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/src/main.rs b/src/main.rs index 1477292..3c01389 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,10 @@ use tracing_subscriber::FmtSubscriber; use lightswitch::collector::Collector; use lightswitch::object::ObjectFile; use lightswitch::profiler::Profiler; -use lightswitch::unwind_info::{compact_printing_callback, UnwindInfoBuilder}; +use lightswitch::unwind_info::remove_redundant; +use lightswitch::unwind_info::remove_unnecesary_markers; +use lightswitch::unwind_info::to_vec; +use lightswitch::unwind_info::UnwindInfoBuilder; const SAMPLE_FREQ_RANGE: RangeInclusive = 1..=1009; @@ -138,7 +141,13 @@ fn main() -> Result<(), Box> { tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); if let Some(path) = args.show_unwind_info { - UnwindInfoBuilder::with_callback(&path, compact_printing_callback)?.process()?; + let mut unwind_info = to_vec(&path).unwrap(); + remove_unnecesary_markers(&mut unwind_info); + remove_redundant(&mut unwind_info); + + for compact_row in unwind_info { + println!("{:?}", compact_row); + } return Ok(()); } diff --git a/src/profiler.rs b/src/profiler.rs index eb1dd51..f01919e 100644 --- a/src/profiler.rs +++ b/src/profiler.rs @@ -21,7 +21,7 @@ use crate::bpf::tracers_skel::{TracersSkel, TracersSkelBuilder}; use crate::collector::*; use crate::object::{BuildId, ObjectFile}; use crate::perf_events::setup_perf_event; -use crate::unwind_info::{in_memory_unwind_info, remove_redundant, remove_unnecesary_markers}; +use crate::unwind_info::{remove_redundant, remove_unnecesary_markers, to_vec}; use crate::util::summarize_address_range; pub enum TracerEvent { @@ -732,7 +732,7 @@ impl Profiler<'_> { let mut found_unwind_info: Vec; - match in_memory_unwind_info(&first_mapping.path.to_string_lossy()) { + match to_vec(&first_mapping.path.to_string_lossy()) { Ok(unwind_info) => { found_unwind_info = unwind_info; } @@ -752,17 +752,9 @@ impl Profiler<'_> { } span.exit(); - let span: span::EnteredSpan = span!(Level::DEBUG, "sort unwind info").entered(); - found_unwind_info.sort_by(|a, b| { - let a_pc = a.pc; - let b_pc = b.pc; - a_pc.cmp(&b_pc) - }); - span.exit(); - let span: span::EnteredSpan = span!(Level::DEBUG, "optimize unwind info").entered(); - let found_unwind_info = remove_unnecesary_markers(&found_unwind_info); - let found_unwind_info = remove_redundant(&found_unwind_info); + remove_unnecesary_markers(&mut found_unwind_info); + remove_redundant(&mut found_unwind_info); span.exit(); debug!( diff --git a/src/unwind_info.rs b/src/unwind_info.rs index b5d4a63..7790e46 100644 --- a/src/unwind_info.rs +++ b/src/unwind_info.rs @@ -9,7 +9,7 @@ use thiserror::Error; use crate::bpf::profiler_bindings::stack_unwind_row_t; use anyhow::anyhow; -use tracing::error; +use tracing::{error, span, Level}; #[repr(u8)] pub enum CfaType { @@ -252,8 +252,8 @@ impl<'a> UnwindInfoBuilder<'a> { let eh_frame = EhFrame::new(eh_frame_data, endian); let mut entries_iter = eh_frame.entries(&bases); - let mut ctx = Box::new(UnwindContext::new()); let mut cur_cie = None; + let mut pc_and_fde_offset = Vec::new(); while let Ok(Some(entry)) = entries_iter.next() { match entry { @@ -261,7 +261,7 @@ impl<'a> UnwindInfoBuilder<'a> { cur_cie = Some(cie); } CieOrFde::Fde(partial_fde) => { - if let Ok(fde) = partial_fde.parse(|eh_frame, bases, cie_offset| { + let fde = partial_fde.parse(|eh_frame, bases, cie_offset| { if let Some(cie) = &cur_cie { if cie.offset() == cie_offset.0 { return Ok(cie.clone()); @@ -272,111 +272,125 @@ impl<'a> UnwindInfoBuilder<'a> { cur_cie = Some(cie.clone()); } cie - }) { - (self.callback)(&UnwindData::Function( - fde.initial_address(), - fde.initial_address() + fde.len(), - )); - - let mut table = fde.rows(&eh_frame, &bases, &mut ctx)?; - - loop { - let mut compact_row = CompactUnwindRow::default(); - - match table.next_row() { - Ok(None) => break, - Ok(Some(row)) => { - compact_row.pc = row.start_address(); - match row.cfa() { - CfaRule::RegisterAndOffset { register, offset } => { - if register == &RBP_X86 { - compact_row.cfa_type = - CfaType::FramePointerOffset as u8; - } else if register == &RSP_X86 { - compact_row.cfa_type = - CfaType::StackPointerOffset as u8; - } else { - compact_row.cfa_type = - CfaType::UnsupportedRegisterOffset as u8; - } - - match u16::try_from(*offset) { - Ok(off) => { - compact_row.cfa_offset = off; - } - Err(_) => { - compact_row.cfa_type = - CfaType::OffsetDidNotFit as u8; - } - } - } - CfaRule::Expression(exp) => { - let found_expression = exp.0.slice(); - - if found_expression == *PLT1 { - compact_row.cfa_offset = PltType::Plt1 as u16; - } else if found_expression == *PLT2 { - compact_row.cfa_offset = PltType::Plt2 as u16; - } - - compact_row.cfa_type = CfaType::Expression as u8; - } - }; - - match row.register(RBP_X86) { - gimli::RegisterRule::Undefined => {} - gimli::RegisterRule::Offset(offset) => { - compact_row.rbp_type = RbpType::CfaOffset as u8; - compact_row.rbp_offset = - i16::try_from(offset).expect("convert rbp offset"); - } - gimli::RegisterRule::Register(_reg) => { - compact_row.rbp_type = RbpType::Register as u8; - } - gimli::RegisterRule::Expression(_) => { - compact_row.rbp_type = RbpType::Expression as u8; - } - _ => { - // print!(", rbp unsupported {:?}", rbp); - } - } + }); + + if let Ok(fde) = fde { + pc_and_fde_offset.push((fde.initial_address(), fde.offset())); + } + } + } + } - if row.register(fde.cie().return_address_register()) - == gimli::RegisterRule::Undefined - { - compact_row.rbp_type = - RbpType::UndefinedReturnAddress as u8; + let span = span!(Level::DEBUG, "sort pc and fdes").entered(); + pc_and_fde_offset.sort_by_key(|(pc, _)| *pc); + span.exit(); + + let mut ctx = Box::new(UnwindContext::new()); + for (_, fde_offset) in pc_and_fde_offset { + let fde = eh_frame.fde_from_offset( + &bases, + gimli::EhFrameOffset(fde_offset), + EhFrame::cie_from_offset, + )?; + + (self.callback)(&UnwindData::Function( + fde.initial_address(), + fde.initial_address() + fde.len(), + )); + + let mut table = fde.rows(&eh_frame, &bases, &mut ctx)?; + + loop { + let mut compact_row = CompactUnwindRow::default(); + + match table.next_row() { + Ok(None) => break, + Ok(Some(row)) => { + compact_row.pc = row.start_address(); + match row.cfa() { + CfaRule::RegisterAndOffset { register, offset } => { + if register == &RBP_X86 { + compact_row.cfa_type = CfaType::FramePointerOffset as u8; + } else if register == &RSP_X86 { + compact_row.cfa_type = CfaType::StackPointerOffset as u8; + } else { + compact_row.cfa_type = CfaType::UnsupportedRegisterOffset as u8; + } + + match u16::try_from(*offset) { + Ok(off) => { + compact_row.cfa_offset = off; } + Err(_) => { + compact_row.cfa_type = CfaType::OffsetDidNotFit as u8; + } + } + } + CfaRule::Expression(exp) => { + let found_expression = exp.0.slice(); - // print!(", ra {:?}", row.register(fde.cie().return_address_register())); + if found_expression == *PLT1 { + compact_row.cfa_offset = PltType::Plt1 as u16; + } else if found_expression == *PLT2 { + compact_row.cfa_offset = PltType::Plt2 as u16; } - _ => continue, + + compact_row.cfa_type = CfaType::Expression as u8; } + }; - (self.callback)(&UnwindData::Instruction(compact_row)); + match row.register(RBP_X86) { + gimli::RegisterRule::Undefined => {} + gimli::RegisterRule::Offset(offset) => { + compact_row.rbp_type = RbpType::CfaOffset as u8; + compact_row.rbp_offset = + i16::try_from(offset).expect("convert rbp offset"); + } + gimli::RegisterRule::Register(_reg) => { + compact_row.rbp_type = RbpType::Register as u8; + } + gimli::RegisterRule::Expression(_) => { + compact_row.rbp_type = RbpType::Expression as u8; + } + _ => { + // print!(", rbp unsupported {:?}", rbp); + } } - // start_addresses.push(fde.initial_address() as u32); - // end_addresses.push((fde.initial_address() + fde.len()) as u32); + + if row.register(fde.cie().return_address_register()) + == gimli::RegisterRule::Undefined + { + compact_row.rbp_type = RbpType::UndefinedReturnAddress as u8; + } + + // print!(", ra {:?}", row.register(fde.cie().return_address_register())); } + _ => continue, } + + (self.callback)(&UnwindData::Instruction(compact_row)); } + // start_addresses.push(fde.initial_address() as u32); + // end_addresses.push((fde.initial_address() + fde.len()) as u32); } Ok(()) } } // Must be sorted. Also, not very optimized as of now. -pub fn remove_unnecesary_markers(info: &Vec) -> Vec { - let mut unwind_info = Vec::with_capacity(info.len()); +pub fn remove_unnecesary_markers(unwind_info: &mut Vec) { let mut last_row: Option = None; + let mut new_i: usize = 0; + + for i in 0..unwind_info.len() { + let row = unwind_info[i]; - for row in info { if let Some(last_row_unwrapped) = last_row { let previous_is_redundant_marker = (last_row_unwrapped.cfa_type == CfaType::EndFdeMarker as u8) && last_row_unwrapped.pc == row.pc; if previous_is_redundant_marker { - unwind_info.pop(); + new_i -= 1; } } @@ -387,22 +401,25 @@ pub fn remove_unnecesary_markers(info: &Vec) -> Vec) -> Vec { - let mut unwind_info = Vec::with_capacity(info.len()); +// Must be sorted. +pub fn remove_redundant(unwind_info: &mut Vec) { let mut last_row: Option = None; + let mut new_i: usize = 0; - for row in info { + for i in 0..unwind_info.len() { let mut redundant = false; + let row = unwind_info[i]; + if let Some(last_row_unwrapped) = last_row { redundant = row.cfa_type == last_row_unwrapped.cfa_type && row.cfa_offset == last_row_unwrapped.cfa_offset @@ -411,16 +428,17 @@ pub fn remove_redundant(info: &Vec) -> Vec anyhow::Result> { +pub fn to_vec(path: &str) -> anyhow::Result> { let mut unwind_info = Vec::new(); let mut last_function_end_addr: Option = None; let mut last_row = None;