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