aboutsummaryrefslogtreecommitdiff
path: root/src/stub/core_impl/host_io.rs
blob: f62bf66270f3cf91944827ff12d877e98bb6fc7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use super::prelude::*;
use crate::arch::Arch;
use crate::protocol::commands::ext::HostIo;
use crate::target::ext::host_io::HostIoError;
use crate::target::ext::host_io::HostIoStat;

impl<T: Target, C: Connection> GdbStubImpl<T, C> {
    pub(crate) fn handle_host_io(
        &mut self,
        res: &mut ResponseWriter<'_, C>,
        target: &mut T,
        command: HostIo<'_>,
    ) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
        let ops = match target.support_host_io() {
            Some(ops) => ops,
            None => return Ok(HandlerStatus::Handled),
        };

        crate::__dead_code_marker!("host_io", "impl");

        macro_rules! handle_hostio_result {
            ( if let Ok($val:pat) = $ret:expr => $callback:block ) => {{
                match $ret {
                    Ok($val) => $callback,
                    Err(HostIoError::Errno(errno)) => {
                        res.write_str("F-1,")?;
                        res.write_num(errno as u32)?;
                    }
                    Err(HostIoError::Fatal(e)) => return Err(Error::TargetError(e)),
                }
            }};
        }

        let handler_status = match command {
            HostIo::vFileOpen(cmd) if ops.support_open().is_some() => {
                let ops = ops.support_open().unwrap();
                handle_hostio_result! {
                    if let Ok(fd) = ops.open(cmd.filename, cmd.flags, cmd.mode) => {
                        res.write_str("F")?;
                        res.write_num(fd)?;
                    }
                }
                HandlerStatus::Handled
            }
            HostIo::vFileClose(cmd) if ops.support_close().is_some() => {
                let ops = ops.support_close().unwrap();
                handle_hostio_result! {
                    if let Ok(()) = ops.close(cmd.fd) => {
                        res.write_str("F0")?;
                    }
                }
                HandlerStatus::Handled
            }
            HostIo::vFilePread(cmd) if ops.support_pread().is_some() => {
                let ops = ops.support_pread().unwrap();
                handle_hostio_result! {
                    if let Ok(ret) = ops.pread(cmd.fd, cmd.count, cmd.offset, cmd.buf) => {
                        res.write_str("F")?;
                        res.write_num(ret)?;
                        res.write_str(";")?;
                        res.write_binary(cmd.buf.get(..ret).ok_or(Error::PacketBufferOverflow)?)?;
                    }
                };

                HandlerStatus::Handled
            }
            HostIo::vFilePwrite(cmd) if ops.support_pwrite().is_some() => {
                let offset = <T::Arch as Arch>::Usize::from_be_bytes(cmd.offset)
                    .ok_or(Error::TargetMismatch)?;
                let ops = ops.support_pwrite().unwrap();
                handle_hostio_result! {
                    if let Ok(ret) = ops.pwrite(cmd.fd, offset, cmd.data) => {
                        res.write_str("F")?;
                        res.write_num(ret)?;
                    }
                };
                HandlerStatus::Handled
            }
            HostIo::vFileFstat(cmd) if ops.support_fstat().is_some() => {
                let ops = ops.support_fstat().unwrap();
                handle_hostio_result! {
                    if let Ok(stat) = ops.fstat(cmd.fd) => {
                        let size = core::mem::size_of::<HostIoStat>();
                        res.write_str("F")?;
                        res.write_num(size)?;
                        res.write_str(";")?;
                        res.write_binary(&stat.st_dev.to_be_bytes())?;
                        res.write_binary(&stat.st_ino.to_be_bytes())?;
                        res.write_binary(&(stat.st_mode.bits()).to_be_bytes())?;
                        res.write_binary(&stat.st_nlink.to_be_bytes())?;
                        res.write_binary(&stat.st_uid.to_be_bytes())?;
                        res.write_binary(&stat.st_gid.to_be_bytes())?;
                        res.write_binary(&stat.st_rdev.to_be_bytes())?;
                        res.write_binary(&stat.st_size.to_be_bytes())?;
                        res.write_binary(&stat.st_blksize.to_be_bytes())?;
                        res.write_binary(&stat.st_blocks.to_be_bytes())?;
                        res.write_binary(&stat.st_atime.to_be_bytes())?;
                        res.write_binary(&stat.st_mtime.to_be_bytes())?;
                        res.write_binary(&stat.st_ctime.to_be_bytes())?;
                    }
                };
                HandlerStatus::Handled
            }
            HostIo::vFileUnlink(cmd) if ops.support_unlink().is_some() => {
                let ops = ops.support_unlink().unwrap();
                handle_hostio_result! {
                    if let Ok(()) = ops.unlink(cmd.filename) => {
                        res.write_str("F0")?;
                    }
                };
                HandlerStatus::Handled
            }
            HostIo::vFileReadlink(cmd) if ops.support_readlink().is_some() => {
                let ops = ops.support_readlink().unwrap();
                handle_hostio_result! {
                    if let Ok(ret) = ops.readlink(cmd.filename, cmd.buf) => {
                        res.write_str("F")?;
                        res.write_num(ret)?;
                        res.write_str(";")?;
                        res.write_binary(cmd.buf.get(..ret).ok_or(Error::PacketBufferOverflow)?)?;
                    }
                };

                HandlerStatus::Handled
            }
            HostIo::vFileSetfs(cmd) if ops.support_setfs().is_some() => {
                let ops = ops.support_setfs().unwrap();
                handle_hostio_result! {
                    if let Ok(()) = ops.setfs(cmd.fs) => {
                        res.write_str("F0")?;
                    }
                };
                HandlerStatus::Handled
            }
            _ => HandlerStatus::Handled,
        };

        Ok(handler_status)
    }
}