gdbstub/target/ext/host_io.rs
1//! Provide Host I/O operations for the target.
2use crate::arch::Arch;
3use crate::target::Target;
4use bitflags::bitflags;
5
6/// Host flags for opening files.
7///
8/// Extracted from the GDB documentation at
9/// [Open Flags](https://sourceware.org/gdb/current/onlinedocs/gdb/Open-Flags.html#Open-Flags),
10/// and the LLDB source code at
11/// [`lldb/include/lldb/Host/File.h`](https://github.com/llvm/llvm-project/blob/ec642ceebc1aacc8b16249df7734b8cf90ae2963/lldb/include/lldb/Host/File.h#L47-L66)
12#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
13#[repr(transparent)]
14pub struct HostIoOpenFlags(u32);
15
16bitflags! {
17 impl HostIoOpenFlags: u32 {
18 /// A read-only file.
19 const O_RDONLY = 0x0;
20 /// A write-only file.
21 const O_WRONLY = 0x1;
22 /// A read-write file.
23 const O_RDWR = 0x2;
24 /// Append to an existing file.
25 const O_APPEND = 0x8;
26 /// Create a non-existent file.
27 const O_CREAT = 0x200;
28 /// Truncate an existing file.
29 const O_TRUNC = 0x400;
30 /// Exclusive access.
31 const O_EXCL = 0x800;
32
33 /// LLDB extension: Do not block.
34 const O_NONBLOCK = 1 << 28;
35 /// LLDB extension: Do not follow symlinks.
36 const O_DONT_FOLLOW_SYMLINKS = 1 << 29;
37 /// LLDB extension: Close the file when executing a new process.
38 const O_CLOSE_ON_EXEC = 1 << 30;
39 /// LLDB extension: Invalid value.
40 const O_INVALID = 1 << 31;
41 }
42}
43
44/// Host file permissions.
45///
46/// Extracted from the GDB documentation at
47/// [mode_t Values](https://sourceware.org/gdb/current/onlinedocs/gdb/mode_005ft-Values.html#mode_005ft-Values)
48#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
49#[repr(transparent)]
50pub struct HostIoOpenMode(u32);
51
52bitflags! {
53 impl HostIoOpenMode: u32 {
54 /// A regular file.
55 const S_IFREG = 0o100000;
56 /// A directory.
57 const S_IFDIR = 0o40000;
58 /// User read permissions.
59 const S_IRUSR = 0o400;
60 /// User write permissions.
61 const S_IWUSR = 0o200;
62 /// User execute permissions.
63 const S_IXUSR = 0o100;
64 /// Group read permissions.
65 const S_IRGRP = 0o40;
66 /// Group write permissions
67 const S_IWGRP = 0o20;
68 /// Group execute permissions.
69 const S_IXGRP = 0o10;
70 /// World read permissions.
71 const S_IROTH = 0o4;
72 /// World write permissions
73 const S_IWOTH = 0o2;
74 /// World execute permissions.
75 const S_IXOTH = 0o1;
76 }
77}
78
79/// Data returned by a host fstat request.
80///
81/// Extracted from the GDB documentation at
82/// [struct stat](https://sourceware.org/gdb/current/onlinedocs/gdb/struct-stat.html#struct-stat)
83#[derive(Debug)]
84pub struct HostIoStat {
85 /// The device.
86 pub st_dev: u32,
87 /// The inode.
88 pub st_ino: u32,
89 /// Protection bits.
90 pub st_mode: HostIoOpenMode,
91 /// The number of hard links.
92 pub st_nlink: u32,
93 /// The user id of the owner.
94 pub st_uid: u32,
95 /// The group id of the owner.
96 pub st_gid: u32,
97 /// The device type, if an inode device.
98 pub st_rdev: u32,
99 /// The size of the file in bytes.
100 pub st_size: u64,
101 /// The blocksize for the filesystem.
102 pub st_blksize: u64,
103 /// The number of blocks allocated.
104 pub st_blocks: u64,
105 /// The last time the file was accessed, in seconds since the epoch.
106 pub st_atime: u32,
107 /// The last time the file was modified, in seconds since the epoch.
108 pub st_mtime: u32,
109 /// The last time the file was changed, in seconds since the epoch.
110 pub st_ctime: u32,
111}
112
113/// Select the filesystem vFile operations will operate on. Used by vFile setfs
114/// command.
115#[derive(Debug)]
116pub enum FsKind {
117 /// Select the filesystem as seen by the remote stub.
118 Stub,
119 /// Select the filesystem as seen by process pid.
120 Pid(crate::common::Pid),
121}
122
123/// Errno values for Host I/O operations.
124///
125/// Extracted from the GDB documentation at
126/// <https://sourceware.org/gdb/onlinedocs/gdb/Errno-Values.html>
127#[derive(Debug)]
128pub enum HostIoErrno {
129 /// Operation not permitted (POSIX.1-2001).
130 EPERM = 1,
131 /// No such file or directory (POSIX.1-2001).
132 ///
133 /// Typically, this error results when a specified pathname does not exist,
134 /// or one of the components in the directory prefix of a pathname does not
135 /// exist, or the specified pathname is a dangling symbolic link.
136 ENOENT = 2,
137 /// Interrupted function call (POSIX.1-2001); see signal(7).
138 EINTR = 4,
139 /// Input/output error (POSIX.1-2001).
140 EIO = 5,
141 /// Bad file descriptor (POSIX.1-2001).
142 EBADF = 9,
143 /// Permission denied (POSIX.1-2001).
144 EACCES = 13,
145 /// Bad address (POSIX.1-2001).
146 EFAULT = 14,
147 /// Device or resource busy (POSIX.1-2001).
148 EBUSY = 16,
149 /// File exists (POSIX.1-2001).
150 EEXIST = 17,
151 /// No such device (POSIX.1-2001).
152 ENODEV = 19,
153 /// Not a directory (POSIX.1-2001).
154 ENOTDIR = 20,
155 /// Is a directory (POSIX.1-2001).
156 EISDIR = 21,
157 /// Invalid argument (POSIX.1-2001).
158 EINVAL = 22,
159 /// Too many open files in system (POSIX.1-2001). On Linux, this is probably
160 /// a result of encountering the /proc/sys/fs/file-max limit (see proc(5)).
161 ENFILE = 23,
162 /// Too many open files (POSIX.1-2001). Commonly caused by exceeding the
163 /// RLIMIT_NOFILE resource limit described in getrlimit(2).
164 EMFILE = 24,
165 /// File too large (POSIX.1-2001).
166 EFBIG = 27,
167 /// No space left on device (POSIX.1-2001).
168 ENOSPC = 28,
169 /// Invalid seek (POSIX.1-2001).
170 ESPIPE = 29,
171 /// Read-only filesystem (POSIX.1-2001).
172 EROFS = 30,
173 /// Function not implemented (POSIX.1-2001).
174 ENOSYS = 88,
175 /// Filename too long (POSIX.1-2001).
176 ENAMETOOLONG = 91,
177 /// Unknown errno - there may not be a GDB mapping for this value
178 EUNKNOWN = 9999,
179}
180
181/// The error type for Host I/O operations.
182pub enum HostIoError<E> {
183 /// An operation-specific non-fatal error code.
184 ///
185 /// See [`HostIoErrno`] for more details.
186 Errno(HostIoErrno),
187 /// A target-specific fatal error.
188 ///
189 /// **WARNING:** Returning this error will immediately halt the target's
190 /// execution and return a [`GdbStubError`](crate::stub::GdbStubError)!
191 ///
192 /// Note that returning this error will _not_ notify the GDB client that the
193 /// debugging session has been terminated, making it possible to resume
194 /// execution after resolving the error and/or setting up a post-mortem
195 /// debugging environment.
196 Fatal(E),
197}
198
199/// When the `std` feature is enabled, `HostIoError` implements
200/// `From<std::io::Error>`, mapping [`std::io::ErrorKind`] to the appropriate
201/// [`HostIoErrno`] when possible, and falling back to [`HostIoErrno::EUNKNOWN`]
202/// when no mapping exists.
203#[cfg(feature = "std")]
204impl<E> From<std::io::Error> for HostIoError<E> {
205 fn from(e: std::io::Error) -> HostIoError<E> {
206 use std::io::ErrorKind::*;
207 let errno = match e.kind() {
208 PermissionDenied => HostIoErrno::EPERM,
209 NotFound => HostIoErrno::ENOENT,
210 Interrupted => HostIoErrno::EINTR,
211 AlreadyExists => HostIoErrno::EEXIST,
212 InvalidInput => HostIoErrno::EINVAL,
213 _ => HostIoErrno::EUNKNOWN,
214 };
215 HostIoError::Errno(errno)
216 }
217}
218
219/// A specialized `Result` type for Host I/O operations. Supports reporting
220/// non-fatal errors back to the GDB client.
221///
222/// See [`HostIoError`] for more details.
223pub type HostIoResult<T, Tgt> = Result<T, HostIoError<<Tgt as Target>::Error>>;
224
225/// Target Extension - Perform I/O operations on host
226pub trait HostIo: Target {
227 /// Support `open` operation.
228 #[inline(always)]
229 fn support_open(&mut self) -> Option<HostIoOpenOps<'_, Self>> {
230 None
231 }
232
233 /// Support `close` operation.
234 #[inline(always)]
235 fn support_close(&mut self) -> Option<HostIoCloseOps<'_, Self>> {
236 None
237 }
238
239 /// Support `pread` operation.
240 #[inline(always)]
241 fn support_pread(&mut self) -> Option<HostIoPreadOps<'_, Self>> {
242 None
243 }
244
245 /// Support `pwrite` operation.
246 #[inline(always)]
247 fn support_pwrite(&mut self) -> Option<HostIoPwriteOps<'_, Self>> {
248 None
249 }
250
251 /// Support `fstat` operation.
252 #[inline(always)]
253 fn support_fstat(&mut self) -> Option<HostIoFstatOps<'_, Self>> {
254 None
255 }
256
257 /// Support `unlink` operation.
258 #[inline(always)]
259 fn support_unlink(&mut self) -> Option<HostIoUnlinkOps<'_, Self>> {
260 None
261 }
262
263 /// Support `readlink` operation.
264 #[inline(always)]
265 fn support_readlink(&mut self) -> Option<HostIoReadlinkOps<'_, Self>> {
266 None
267 }
268
269 /// Support `setfs` operation.
270 #[inline(always)]
271 fn support_setfs(&mut self) -> Option<HostIoSetfsOps<'_, Self>> {
272 None
273 }
274}
275
276define_ext!(HostIoOps, HostIo);
277
278/// Nested Target Extension - Host I/O open operation.
279pub trait HostIoOpen: HostIo {
280 /// Open a file at `filename` and return a file descriptor for it, or return
281 /// [`HostIoError::Errno`] if an error occurs.
282 ///
283 /// `flags` are the flags used when opening the file (see
284 /// [`HostIoOpenFlags`]), and `mode` is the mode used if the file is
285 /// created (see [`HostIoOpenMode`]).
286 fn open(
287 &mut self,
288 filename: &[u8],
289 flags: HostIoOpenFlags,
290 mode: HostIoOpenMode,
291 ) -> HostIoResult<u32, Self>;
292}
293
294define_ext!(HostIoOpenOps, HostIoOpen);
295
296/// Nested Target Extension - Host I/O close operation.
297pub trait HostIoClose: HostIo {
298 /// Close the open file corresponding to `fd`.
299 fn close(&mut self, fd: u32) -> HostIoResult<(), Self>;
300}
301
302define_ext!(HostIoCloseOps, HostIoClose);
303
304/// Nested Target Extension - Host I/O pread operation.
305pub trait HostIoPread: HostIo {
306 /// Read data from the open file corresponding to `fd`.
307 ///
308 /// Up to `count` bytes will be read from the file, starting at `offset`
309 /// relative to the start of the file.
310 ///
311 /// Return the number of bytes written into `buf` (which may be less than
312 /// `count`).
313 ///
314 /// If `offset` is greater than the length of the underlying data, return
315 /// `Ok(0)`.
316 fn pread(
317 &mut self,
318 fd: u32,
319 count: usize,
320 offset: u64,
321 buf: &mut [u8],
322 ) -> HostIoResult<usize, Self>;
323}
324
325define_ext!(HostIoPreadOps, HostIoPread);
326
327/// Nested Target Extension - Host I/O pwrite operation.
328pub trait HostIoPwrite: HostIo {
329 /// Write `data` to the open file corresponding to `fd`.
330 ///
331 /// Start the write at `offset` from the start of the file.
332 ///
333 /// Return the number of bytes written, which may be shorter
334 /// than the length of data, or [`HostIoError::Errno`] if an error occurred.
335 fn pwrite(
336 &mut self,
337 fd: u32,
338 offset: <Self::Arch as Arch>::Usize,
339 data: &[u8],
340 ) -> HostIoResult<<Self::Arch as Arch>::Usize, Self>;
341}
342
343define_ext!(HostIoPwriteOps, HostIoPwrite);
344
345/// Nested Target Extension - Host I/O fstat operation.
346pub trait HostIoFstat: HostIo {
347 /// Get information about the open file corresponding to `fd`.
348 ///
349 /// On success return a [`HostIoStat`] struct.
350 /// Return [`HostIoError::Errno`] if an error occurs.
351 fn fstat(&mut self, fd: u32) -> HostIoResult<HostIoStat, Self>;
352}
353
354define_ext!(HostIoFstatOps, HostIoFstat);
355
356/// Nested Target Extension - Host I/O unlink operation.
357pub trait HostIoUnlink: HostIo {
358 /// Delete the file at `filename` on the target.
359 fn unlink(&mut self, filename: &[u8]) -> HostIoResult<(), Self>;
360}
361
362define_ext!(HostIoUnlinkOps, HostIoUnlink);
363
364/// Nested Target Extension - Host I/O readlink operation.
365pub trait HostIoReadlink: HostIo {
366 /// Read value of symbolic link `filename` on the target.
367 ///
368 /// Return the number of bytes written into `buf`.
369 ///
370 /// Unlike most other Host IO handlers, if the resolved file path exceeds
371 /// the length of the provided `buf`, the target should NOT return a
372 /// partial response, and MUST return a `Err(HostIoErrno::ENAMETOOLONG)`.
373 fn readlink(&mut self, filename: &[u8], buf: &mut [u8]) -> HostIoResult<usize, Self>;
374}
375
376define_ext!(HostIoReadlinkOps, HostIoReadlink);
377
378/// Nested Target Extension - Host I/O setfs operation.
379pub trait HostIoSetfs: HostIo {
380 /// Select the filesystem on which vFile operations with filename arguments
381 /// will operate. This is required for GDB to be able to access files on
382 /// remote targets where the remote stub does not share a common filesystem
383 /// with the inferior(s).
384 ///
385 /// See [`FsKind`] for the meaning of `fs`.
386 ///
387 /// If setfs indicates success, the selected filesystem remains selected
388 /// until the next successful setfs operation.
389 fn setfs(&mut self, fs: FsKind) -> HostIoResult<(), Self>;
390}
391
392define_ext!(HostIoSetfsOps, HostIoSetfs);