1use core::fmt::Write;
8
9#[inline(never)]
18unsafe fn unsanitized_copy(src: *const u8, dest: *mut u8, chunk_len: usize) {
19 for i in 0..chunk_len {
20 unsafe {
21 *dest.add(i) = *src.add(i);
22 }
23 }
24}
25
26pub fn hexdump_very_ex_rs<W: Write>(
31 writer: &mut W,
32 data: &[u8],
33 disp_addr: u64,
34) -> core::fmt::Result {
35 unsafe { hexdump_very_ex_raw(writer, data.as_ptr(), data.len(), disp_addr) }
37}
38
39pub unsafe fn hexdump_very_ex_raw<W: Write>(
46 writer: &mut W,
47 ptr: *const u8,
48 len: usize,
49 disp_addr: u64,
50) -> core::fmt::Result {
51 for count in (0..len).step_by(16) {
52 let chunk_len = core::cmp::min(len - count, 16);
53 let s = chunk_len.next_multiple_of(4);
55
56 let mut buf = [0u8; 16];
58 unsafe {
60 unsanitized_copy(ptr.add(count), buf.as_mut_ptr(), chunk_len);
61 }
62
63 if disp_addr + len as u64 > 0xFFFFFFFF {
64 core::write!(writer, "0x{:016x}: ", disp_addr + count as u64)?;
65 } else {
66 core::write!(writer, "0x{:08x}: ", disp_addr + count as u64)?;
67 }
68
69 let words = s / 4;
70 let (chunks, _) = buf[..s].as_chunks::<4>();
71 for chunk in chunks {
72 let val = u32::from_ne_bytes(*chunk);
75 core::write!(writer, "{:08x} ", val)?;
76 }
77 for _ in words..4 {
78 core::write!(writer, " ")?;
79 }
80 core::write!(writer, "|")?;
81
82 for i in 0..16 {
83 let c = buf[i];
84 if i < s && (c.is_ascii_graphic() || c == b' ') {
85 core::write!(writer, "{}", c as char)?;
86 } else {
87 core::write!(writer, ".")?;
88 }
89 }
90 core::write!(writer, "|\n")?;
91 }
92 Ok(())
93}
94
95pub fn hexdump8_very_ex_rs<W: Write>(
98 writer: &mut W,
99 data: &[u8],
100 disp_addr: u64,
101) -> core::fmt::Result {
102 unsafe { hexdump8_very_ex_raw(writer, data.as_ptr(), data.len(), disp_addr) }
104}
105
106pub unsafe fn hexdump8_very_ex_raw<W: Write>(
113 writer: &mut W,
114 ptr: *const u8,
115 len: usize,
116 disp_addr: u64,
117) -> core::fmt::Result {
118 for count in (0..len).step_by(16) {
119 let chunk_len = core::cmp::min(len - count, 16);
120
121 let mut buf = [0u8; 16];
123 unsafe {
125 unsanitized_copy(ptr.add(count), buf.as_mut_ptr(), chunk_len);
126 }
127
128 if disp_addr + len as u64 > 0xFFFFFFFF {
129 core::write!(writer, "0x{:016x}: ", disp_addr + count as u64)?;
130 } else {
131 core::write!(writer, "0x{:08x}: ", disp_addr + count as u64)?;
132 }
133
134 for i in 0..chunk_len {
135 core::write!(writer, "{:02x} ", buf[i])?;
136 }
137 for _ in chunk_len..16 {
138 core::write!(writer, " ")?;
139 }
140
141 core::write!(writer, "|")?;
142
143 for i in 0..chunk_len {
144 let c = buf[i];
145 if c.is_ascii_graphic() || c == b' ' {
146 core::write!(writer, "{}", c as char)?;
147 } else {
148 core::write!(writer, ".")?;
149 }
150 }
151 core::write!(writer, "\n")?;
152 }
153 Ok(())
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159 extern crate std;
160 use std::string::String;
161
162 #[test]
163 fn test_hexdump_very_ex() {
164 let input = [0u8, 1, 2, 3, b'a', b'b', b'c', b'd'];
165 let test_display_addr = 0x1000;
166 let expected = "0x00001000: 03020100 64636261 |....abcd........|\n";
167
168 let mut output = String::new();
169 hexdump_very_ex_rs(&mut output, &input, test_display_addr).unwrap();
170 assert_eq!(output, expected);
171 }
172
173 #[test]
174 fn test_hexdump_very_ex_raw() {
175 let input = [0u8, 1, 2, 3, b'a', b'b', b'c', b'd'];
176 let test_display_addr = 0x1000;
177 let expected = "0x00001000: 03020100 64636261 |....abcd........|\n";
178
179 let mut output = String::new();
180 unsafe {
182 hexdump_very_ex_raw(&mut output, input.as_ptr(), input.len(), test_display_addr)
183 .unwrap();
184 }
185 assert_eq!(output, expected);
186 }
187
188 #[test]
189 fn test_hexdump8_very_ex() {
190 let input = [0u8, 1, 2, 3, b'a', b'b', b'c', b'd'];
191 let test_display_addr = 0x1000;
192 let expected = "0x00001000: 00 01 02 03 61 62 63 64 |....abcd\n";
193
194 let mut output = String::new();
195 hexdump8_very_ex_rs(&mut output, &input, test_display_addr).unwrap();
196 assert_eq!(output, expected);
197 }
198
199 #[test]
200 fn test_hexdump8_very_ex_raw() {
201 let input = [0u8, 1, 2, 3, b'a', b'b', b'c', b'd'];
202 let test_display_addr = 0x1000;
203 let expected = "0x00001000: 00 01 02 03 61 62 63 64 |....abcd\n";
204
205 let mut output = String::new();
206 unsafe {
208 hexdump8_very_ex_raw(&mut output, input.as_ptr(), input.len(), test_display_addr)
209 .unwrap();
210 }
211 assert_eq!(output, expected);
212 }
213}