gdbmi/
raw.rs

1use std::collections::HashMap;
2
3use camino::Utf8PathBuf;
4use tracing::{error, warn};
5
6use crate::{address::Address, parser, Error, GdbError, ParseHexError};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum Message {
10    Response(Response),
11    General(GeneralMessage),
12}
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum Response {
16    Notify(NotifyResponse),
17    Result(ResultResponse),
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct ResultResponse {
22    message: String,
23    payload: Option<Dict>,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct NotifyResponse {
28    message: String,
29    payload: Dict,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub enum GeneralMessage {
34    Console(String),
35    Log(String),
36    Target(String),
37    Done,
38    /// Not the output of gdbmi, so probably the inferior being debugged printed
39    /// this to its stdout.
40    InferiorStdout(String),
41    InferiorStderr(String),
42}
43
44#[derive(Debug, Clone, Eq, PartialEq)]
45pub enum Value {
46    String(String),
47    List(List),
48    Dict(Dict),
49}
50
51#[derive(Debug, Clone, Eq, PartialEq)]
52pub struct Dict(HashMap<String, Value>);
53
54pub type List = Vec<Value>;
55
56impl Response {
57    pub fn expect_result(self) -> Result<ResultResponse, Error> {
58        if let Self::Result(result) = self {
59            Ok(result)
60        } else {
61            error!("Expected Response to be Result, got: {:?}", self);
62            Err(Error::ExpectedResultResponse)
63        }
64    }
65
66    pub(crate) fn from_parsed(response: parser::Response) -> Result<Self, Error> {
67        match response {
68            parser::Response::Notify {
69                message, payload, ..
70            } => Ok(Self::Notify(NotifyResponse { message, payload })),
71            parser::Response::Result {
72                message, payload, ..
73            } => {
74                if message == "error" {
75                    let gdb_error = Self::_into_error(payload)?;
76                    Err(Error::Gdb(gdb_error))
77                } else {
78                    Ok(Self::Result(ResultResponse { message, payload }))
79                }
80            }
81        }
82    }
83
84    fn _into_error(payload: Option<Dict>) -> Result<GdbError, Error> {
85        let mut payload = if let Some(payload) = payload {
86            payload
87        } else {
88            return Err(Error::ExpectedPayload);
89        };
90
91        let code = payload
92            .remove("code")
93            .map(Value::expect_string)
94            .transpose()?;
95        let msg = payload
96            .remove("msg")
97            .map(Value::expect_string)
98            .transpose()?;
99
100        Ok(GdbError { code, msg })
101    }
102}
103
104impl ResultResponse {
105    pub fn expect_payload(self) -> Result<Dict, Error> {
106        self.payload.ok_or(Error::ExpectedPayload)
107    }
108
109    pub fn expect_msg_is(&self, msg: &str) -> Result<(), Error> {
110        if self.message == msg {
111            Ok(())
112        } else {
113            Err(Error::UnexpectedResponseMessage {
114                expected: msg.to_owned(),
115                actual: self.message.clone(),
116            })
117        }
118    }
119}
120
121impl Dict {
122    #[must_use]
123    pub fn new(map: HashMap<String, Value>) -> Self {
124        Self(map)
125    }
126
127    #[must_use]
128    pub fn as_map(&self) -> &HashMap<String, Value> {
129        &self.0
130    }
131
132    pub fn as_map_mut(&mut self) -> &mut HashMap<String, Value> {
133        &mut self.0
134    }
135
136    pub fn remove_expect(&mut self, key: &str) -> Result<Value, Error> {
137        self.0.remove(key).map_or_else(
138            || {
139                warn!("Expected key {} to be present in {:?}", key, self);
140                Err(Error::ExpectedDifferentPayload)
141            },
142            Ok,
143        )
144    }
145
146    pub fn remove(&mut self, key: &str) -> Option<Value> {
147        self.0.remove(key)
148    }
149}
150
151impl Value {
152    pub(crate) fn into_appended(self, other: Self) -> Self {
153        let mut list = match self {
154            val @ Self::String(_) => vec![val],
155            Self::List(list) => list,
156            Self::Dict(_) => panic!(
157                "Attempted to workaround duplicate key bug, but can't combine dict with anything"
158            ),
159        };
160
161        let mut other = match other {
162            val @ Self::String(_) => vec![val],
163            Self::List(list) => list,
164            Self::Dict(_) => panic!(
165                "Attempted to workaround duplicate key bug, but can't combine anything with dict"
166            ),
167        };
168
169        for val in other.drain(..) {
170            list.push(val);
171        }
172
173        Self::List(list)
174    }
175
176    pub fn expect_string(self) -> Result<String, Error> {
177        if let Self::String(val) = self {
178            Ok(val)
179        } else {
180            error!("Expected string, got: {:?}", self);
181            Err(Error::ExpectedDifferentPayload)
182        }
183    }
184
185    pub fn expect_dict(self) -> Result<Dict, Error> {
186        if let Self::Dict(val) = self {
187            Ok(val)
188        } else {
189            error!("Expected dict, got: {:?}", self);
190            Err(Error::ExpectedDifferentPayload)
191        }
192    }
193
194    pub fn expect_list(self) -> Result<List, Error> {
195        if let Self::List(val) = self {
196            Ok(val)
197        } else {
198            error!("Expected dict, got: {:?}", self);
199            Err(Error::ExpectedDifferentPayload)
200        }
201    }
202
203    pub fn expect_number(self) -> Result<u32, Error> {
204        let val = if let Self::String(val) = self {
205            Ok(val)
206        } else {
207            error!("Expected dict, got: {:?}", self);
208            Err(Error::ExpectedDifferentPayload)
209        }?;
210
211        Ok(val.parse()?)
212    }
213
214    pub fn expect_path(self) -> Result<Utf8PathBuf, Error> {
215        let path = self.expect_string()?.into();
216        Ok(path)
217    }
218
219    pub fn expect_hex(self) -> Result<u64, Error> {
220        parse_hex(&self.expect_string()?)
221    }
222
223    pub fn expect_address(self) -> Result<Address, Error> {
224        self.expect_hex().map(Address)
225    }
226}
227
228pub fn parse_hex(s: &str) -> Result<u64, Error> {
229    if let Some(hex) = s.strip_prefix("0x") {
230        let num = u64::from_str_radix(hex, 16)?;
231        Ok(num)
232    } else {
233        Err(ParseHexError::InvalidPrefix.into())
234    }
235}