Skip to main content

reverie/
regs.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9//! Common code associated with ['libc::user_regs_struct']
10
11/// Trait providing reusable display formatting for registers
12pub trait RegDisplay {
13    /// Returns a display object associated with a trait implementor
14    fn display(&self) -> Display<'_> {
15        self.display_with_options(Default::default())
16    }
17
18    /// Return a display object associated with a trait implementor.
19    /// Additionally specifis ['RegDisplayOptions'] structure to adjust formatting
20    fn display_with_options(&self, options: RegDisplayOptions) -> Display<'_>;
21}
22
23impl RegDisplay for libc::user_regs_struct {
24    fn display_with_options(&self, options: RegDisplayOptions) -> Display<'_> {
25        Display {
26            options,
27            regs: self,
28        }
29    }
30}
31
32/// Options for how [`libc::user_regs_struct`] can be formatted for the
33/// [`std::fmt::Display`] implementation.
34#[derive(Default)]
35pub struct RegDisplayOptions {
36    /// whether to display registers in a single line or format on multiple lines
37    pub multiline: bool,
38}
39
40/// A wrapper defers and implements [`std::fmt::Display`] for
41/// [`libc::user_regs_struct`] according to the options represented by
42/// [`RegDisplayOptions`].
43pub struct Display<'a> {
44    options: RegDisplayOptions,
45    regs: &'a libc::user_regs_struct,
46}
47
48impl<'a> Display<'a> {
49    #[cfg(target_arch = "x86_64")]
50    fn fmt_single_line_x86(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        write!(
52            f,
53            "rax {:#x} rbx {:#x} rcx {:#x} rdx {:#x}",
54            self.regs.rax, self.regs.rbx, self.regs.rcx, self.regs.rdx
55        )?;
56        write!(
57            f,
58            " rsi {:#x} rdi {:#x} rbp {:#x} rsp {:#x}",
59            self.regs.rsi, self.regs.rdi, self.regs.rbp, self.regs.rsp
60        )?;
61        write!(
62            f,
63            " r8 {:#x}  r9 {:#x} r10 {:#x} r11 {:#x}",
64            self.regs.r8, self.regs.r9, self.regs.r10, self.regs.r11
65        )?;
66        write!(
67            f,
68            " r12 {:#x} r13 {:#x} r14 {:#x} r15 {:#x}",
69            self.regs.r12, self.regs.r13, self.regs.r14, self.regs.r15
70        )?;
71        write!(
72            f,
73            " rip {:#x} eflags {:#x}",
74            self.regs.rip, self.regs.eflags
75        )?;
76        write!(
77            f,
78            " cs {:#x} ss {:#x} ds {:#x} es {:#x}",
79            self.regs.cs, self.regs.ss, self.regs.ds, self.regs.es,
80        )?;
81        write!(f, " fs {:#x} gs {:#x}", self.regs.fs, self.regs.gs)
82    }
83    #[cfg(target_arch = "x86_64")]
84    fn fmt_multi_line_x86(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        writeln!(
86            f,
87            " rax {:#16x} rbx {:#16x} rcx {:#16x} rdx {:#16x}",
88            self.regs.rax, self.regs.rbx, self.regs.rcx, self.regs.rdx
89        )?;
90        writeln!(
91            f,
92            " rsi {:#16x} rdi {:#16x} rbp {:#16x} rsp {:#16x}",
93            self.regs.rsi, self.regs.rdi, self.regs.rbp, self.regs.rsp
94        )?;
95        writeln!(
96            f,
97            " r8 {:#16x}  r9 {:#16x} r10 {:#16x} r11 {:#16x}",
98            self.regs.r8, self.regs.r9, self.regs.r10, self.regs.r11
99        )?;
100        writeln!(
101            f,
102            " r12 {:#16x} r13 {:#16x} r14 {:#16x} r15 {:#16x}",
103            self.regs.r12, self.regs.r13, self.regs.r14, self.regs.r15
104        )?;
105        writeln!(
106            f,
107            " rip {:#16x} eflags {:#16x}",
108            self.regs.rip, self.regs.eflags
109        )?;
110        writeln!(
111            f,
112            " cs {:#16x} ss {:#16x} ds {:#16x} es {:#16x}",
113            self.regs.cs, self.regs.ss, self.regs.ds, self.regs.es,
114        )?;
115        writeln!(f, " fs {:#16x} gs {:#16x}", self.regs.fs, self.regs.gs)
116    }
117}
118
119#[cfg(target_arch = "x86_64")]
120impl<'a> std::fmt::Display for Display<'a> {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        if self.options.multiline {
123            self.fmt_multi_line_x86(f)
124        } else {
125            self.fmt_single_line_x86(f)
126        }
127    }
128}
129
130#[cfg(target_arch = "aarch64")]
131impl<'a> std::fmt::Display for Display<'a> {
132    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133        write!(f, "{:?}", self.regs)
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140
141    #[test]
142    #[cfg(target_arch = "x86_64")]
143    fn test_single_line_x86() {
144        let mut regs: libc::user_regs_struct = unsafe { std::mem::zeroed() };
145        regs.rax = 255;
146        let result = format!("{}", regs.display());
147        assert_eq!(
148            result,
149            "rax 0xff rbx 0x0 rcx 0x0 rdx 0x0 rsi 0x0 rdi 0x0 rbp 0x0 rsp 0x0 r8 0x0  r9 0x0 r10 0x0 r11 0x0 r12 0x0 r13 0x0 r14 0x0 r15 0x0 rip 0x0 eflags 0x0 cs 0x0 ss 0x0 ds 0x0 es 0x0 fs 0x0 gs 0x0"
150        );
151    }
152
153    #[test]
154    #[cfg(target_arch = "x86_64")]
155    fn test_multi_line_x86() {
156        let mut regs: libc::user_regs_struct = unsafe { std::mem::zeroed() };
157        regs.rax = 255;
158        let result = format!(
159            "{}",
160            regs.display_with_options(RegDisplayOptions { multiline: true })
161        );
162        let lines = vec![
163            " rax             0xff rbx              0x0 rcx              0x0 rdx              0x0",
164            " rsi              0x0 rdi              0x0 rbp              0x0 rsp              0x0",
165            " r8              0x0  r9              0x0 r10              0x0 r11              0x0",
166            " r12              0x0 r13              0x0 r14              0x0 r15              0x0",
167            " rip              0x0 eflags              0x0",
168            " cs              0x0 ss              0x0 ds              0x0 es              0x0",
169            " fs              0x0 gs              0x0",
170        ];
171
172        assert_eq!(result.lines().collect::<Vec<&str>>(), lines);
173    }
174}