From 78d1d59889bcecfdc3cdc6b7d41859d6849a929b Mon Sep 17 00:00:00 2001 From: Dmitri Makarov Date: Fri, 9 Apr 2021 11:44:19 +0200 Subject: [PATCH] Augment BPF binary dumps to resolve call instruction targets --- Cargo.lock | 21 +++---- sdk/cargo-build-bpf/Cargo.toml | 1 + sdk/cargo-build-bpf/src/main.rs | 103 +++++++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c7cb7f4e..61181376b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "Inflector" version = "0.11.4" @@ -3298,14 +3300,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.3.9" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" dependencies = [ "aho-corasick", "memchr 2.3.3", "regex-syntax", - "thread_local", ] [[package]] @@ -3319,9 +3320,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.18" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" [[package]] name = "remove_dir_all" @@ -4066,6 +4067,7 @@ dependencies = [ "bzip2", "cargo_metadata", "clap", + "regex", "solana-download-utils", "solana-sdk", "tar", @@ -5785,15 +5787,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcbb6aa301e5d3b0b5ef639c9a9c7e2f1c944f177b460c04dc24c69b1fa2bd99" -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -dependencies = [ - "lazy_static", -] - [[package]] name = "time" version = "0.1.43" diff --git a/sdk/cargo-build-bpf/Cargo.toml b/sdk/cargo-build-bpf/Cargo.toml index 565f8e70a..46d84c6d2 100644 --- a/sdk/cargo-build-bpf/Cargo.toml +++ b/sdk/cargo-build-bpf/Cargo.toml @@ -12,6 +12,7 @@ publish = false [dependencies] bzip2 = "0.3.3" clap = "2.33.3" +regex = "1.4.5" cargo_metadata = "0.12.0" solana-sdk = { path = "..", version = "=1.7.0" } solana-download-utils = { path = "../../download-utils", version = "=1.7.0" } diff --git a/sdk/cargo-build-bpf/src/main.rs b/sdk/cargo-build-bpf/src/main.rs index 9ea688a9b..0d9f19c94 100644 --- a/sdk/cargo-build-bpf/src/main.rs +++ b/sdk/cargo-build-bpf/src/main.rs @@ -3,16 +3,19 @@ use { clap::{ crate_description, crate_name, crate_version, value_t, value_t_or_exit, values_t, App, Arg, }, + regex::Regex, solana_download_utils::download_file, solana_sdk::signature::{write_keypair_file, Keypair}, std::{ + collections::HashMap, env, ffi::OsStr, fs::{self, File}, - io::BufReader, + io::{prelude::*, BufReader, BufWriter}, path::{Path, PathBuf}, process::exit, process::{Command, Stdio}, + str::FromStr, }, tar::Archive, }; @@ -150,6 +153,103 @@ fn install_if_missing( Ok(()) } +// Process dump file attributing call instructions with callee function names +fn postprocess_dump(program_dump: &Path) { + if !program_dump.exists() { + return; + } + let postprocessed_dump = program_dump.with_extension("postprocessed"); + let head_re = Regex::new(r"(^[0-9a-f]{16}) (.+)").unwrap(); + let insn_re = Regex::new(r"^ +([0-9]+)((\s[0-9a-f]{2})+)\s.+").unwrap(); + let call_re = Regex::new(r"^ +([0-9]+)(\s[0-9a-f]{2})+\scall (-?)0x([0-9a-f]+)").unwrap(); + let relo_re = Regex::new(r"^([0-9a-f]{16}) [0-9a-f]{16} R_BPF_64_32 +0{16} (.+)").unwrap(); + let mut a2n: HashMap = HashMap::new(); + let mut rel: HashMap = HashMap::new(); + let mut name = String::from(""); + let mut state = 0; + let file = match File::open(program_dump) { + Ok(x) => x, + _ => return, + }; + for line_result in BufReader::new(file).lines() { + let line = line_result.unwrap(); + let line = line.trim_end(); + if line == "Disassembly of section .text" { + state = 1; + } + if state == 0 { + if relo_re.is_match(line) { + let captures = relo_re.captures(line).unwrap(); + let address = u64::from_str_radix(&captures[1], 16).unwrap(); + let symbol = captures[2].to_string(); + rel.insert(address, symbol); + } + } else if state == 1 { + if head_re.is_match(line) { + state = 2; + let captures = head_re.captures(line).unwrap(); + name = captures[2].to_string(); + } + } else if state == 2 { + state = 1; + if insn_re.is_match(line) { + let captures = insn_re.captures(line).unwrap(); + let address = i64::from_str(&captures[1]).unwrap(); + a2n.insert(address, name.clone()); + } + } + } + let file = match File::create(&postprocessed_dump) { + Ok(x) => x, + _ => return, + }; + let mut out = BufWriter::new(file); + let file = match File::open(program_dump) { + Ok(x) => x, + _ => return, + }; + let mut pc = 0u64; + let mut step = 0u64; + for line_result in BufReader::new(file).lines() { + let line = line_result.unwrap(); + let line = line.trim_end(); + if head_re.is_match(line) { + let captures = head_re.captures(line).unwrap(); + pc = u64::from_str_radix(&captures[1], 16).unwrap(); + writeln!(out, "{}", line).unwrap(); + continue; + } + if insn_re.is_match(line) { + let captures = insn_re.captures(line).unwrap(); + step = if captures[2].len() > 24 { 16 } else { 8 }; + } + if call_re.is_match(line) { + if rel.contains_key(&pc) { + writeln!(out, "{} ; {}", line, rel[&pc]).unwrap(); + } else { + let captures = call_re.captures(line).unwrap(); + let pc = i64::from_str(&captures[1]).unwrap().checked_add(1).unwrap(); + let offset = i64::from_str_radix(&captures[4], 16).unwrap(); + let offset = if &captures[3] == "-" { + offset.checked_neg().unwrap() + } else { + offset + }; + let address = pc.checked_add(offset).unwrap(); + if a2n.contains_key(&address) { + writeln!(out, "{} ; {}", line, a2n[&address]).unwrap(); + } else { + writeln!(out, "{}", line).unwrap(); + } + } + } else { + writeln!(out, "{}", line).unwrap(); + } + pc = pc.checked_add(step).unwrap(); + } + fs::rename(postprocessed_dump, program_dump).unwrap(); +} + // check whether custom BPF toolchain is linked, and link it if it is not. fn link_bpf_toolchain(config: &Config) { let toolchain_path = config @@ -366,6 +466,7 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m &config.bpf_sdk.join("scripts").join("dump.sh"), &[&program_unstripped_so, &program_dump], ); + postprocess_dump(&program_dump); } println!();