Skip to content

Instantly share code, notes, and snippets.

@jam1garner
Created April 25, 2020 17:31
Show Gist options
  • Save jam1garner/4cdb386426d77f7e0ed25f8e025044ee to your computer and use it in GitHub Desktop.
Save jam1garner/4cdb386426d77f7e0ed25f8e025044ee to your computer and use it in GitHub Desktop.
Rust hex dumping
const CHUNK_SIZE: usize = 0x10;
const NUMBERING_HEX: &str = "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ";
const NUMBERING_SEP: &str = "│";
const NUMBERING_ASCII: &str = " 0123456789ABCDEF";
fn hex_num_len(val: usize) -> usize {
((val as f64).log2() / (0x10 as f64).log2()) as usize + 1
}
fn to_ascii_dots(x: u8) -> char {
match x {
0..=0x1F | 0x7F..=0xA0 | 0xAD => '.',
x => x as char,
}
}
fn dump_hex_line((line, addr): (&[u8], usize)) {
print!("{:08X}", addr);
line.chunks(8)
.for_each(|half|{
print!(" ");
half.iter()
.for_each(|x| print!("{:02X} ", x))
});
print!("│ ");
line.iter().for_each(|&x| print!("{}", to_ascii_dots(x)));
println!();
}
fn hex_dump<T>(addr: *const T) {
let addr = addr as usize;
let aligned_addr = addr & !0xF;
let start = aligned_addr.saturating_sub(CHUNK_SIZE * 3);
let byte_slice = unsafe { core::slice::from_raw_parts(start as *const u8, CHUNK_SIZE * 7) };
let num_spaces = hex_num_len(start.saturating_add(CHUNK_SIZE * 6)) + 1;
(0..num_spaces).for_each(|_| print!(" "));
println!("{}{}{}", NUMBERING_HEX, NUMBERING_SEP, NUMBERING_ASCII);
(0..num_spaces).for_each(|_| print!(" "));
(0..NUMBERING_HEX.len()).for_each(|_| print!("─"));
print!("┼");
(0..NUMBERING_ASCII.len()).for_each(|_| print!("─"));
println!();
byte_slice
.chunks(CHUNK_SIZE)
.zip((0..).map(|x| (x * CHUNK_SIZE) + start))
.for_each(dump_hex_line)
}
fn main() {
let x = b"AAA TEST \0\x01\x02\x03\x04";
let x = x.as_ptr();
println!("{:?}", x);
hex_dump(x);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment