1 //! Provide Host I/O operations for the target. 2 use crate::arch::Arch; 3 use crate::target::Target; 4 use 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)] 14 pub struct HostIoOpenFlags(u32); 15 16 bitflags! { 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)] 50 pub struct HostIoOpenMode(u32); 51 52 bitflags! { 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)] 84 pub 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)] 116 pub 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)] 128 pub 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 /// Bad file descriptor (POSIX.1-2001). 140 EBADF = 9, 141 /// Permission denied (POSIX.1-2001). 142 EACCES = 13, 143 /// Bad address (POSIX.1-2001). 144 EFAULT = 14, 145 /// Device or resource busy (POSIX.1-2001). 146 EBUSY = 16, 147 /// File exists (POSIX.1-2001). 148 EEXIST = 17, 149 /// No such device (POSIX.1-2001). 150 ENODEV = 19, 151 /// Not a directory (POSIX.1-2001). 152 ENOTDIR = 20, 153 /// Is a directory (POSIX.1-2001). 154 EISDIR = 21, 155 /// Invalid argument (POSIX.1-2001). 156 EINVAL = 22, 157 /// Too many open files in system (POSIX.1-2001). On Linux, this is probably 158 /// a result of encountering the /proc/sys/fs/file-max limit (see proc(5)). 159 ENFILE = 23, 160 /// Too many open files (POSIX.1-2001). Commonly caused by exceeding the 161 /// RLIMIT_NOFILE resource limit described in getrlimit(2). 162 EMFILE = 24, 163 /// File too large (POSIX.1-2001). 164 EFBIG = 27, 165 /// No space left on device (POSIX.1-2001). 166 ENOSPC = 28, 167 /// Invalid seek (POSIX.1-2001). 168 ESPIPE = 29, 169 /// Read-only filesystem (POSIX.1-2001). 170 EROFS = 30, 171 /// Filename too long (POSIX.1-2001). 172 ENAMETOOLONG = 91, 173 /// Unknown errno - there may not be a GDB mapping for this value 174 EUNKNOWN = 9999, 175 } 176 177 /// The error type for Host I/O operations. 178 pub enum HostIoError<E> { 179 /// An operation-specific non-fatal error code. 180 /// 181 /// See [`HostIoErrno`] for more details. 182 Errno(HostIoErrno), 183 /// A target-specific fatal error. 184 /// 185 /// **WARNING:** Returning this error will immediately halt the target's 186 /// execution and return a [`GdbStubError`](crate::stub::GdbStubError)! 187 /// 188 /// Note that returning this error will _not_ notify the GDB client that the 189 /// debugging session has been terminated, making it possible to resume 190 /// execution after resolving the error and/or setting up a post-mortem 191 /// debugging environment. 192 Fatal(E), 193 } 194 195 /// When the `std` feature is enabled, `HostIoError` implements 196 /// `From<std::io::Error>`, mapping [`std::io::ErrorKind`] to the appropriate 197 /// [`HostIoErrno`] when possible, and falling back to [`HostIoErrno::EUNKNOWN`] 198 /// when no mapping exists. 199 #[cfg(feature = "std")] 200 impl<E> From<std::io::Error> for HostIoError<E> { from(e: std::io::Error) -> HostIoError<E>201 fn from(e: std::io::Error) -> HostIoError<E> { 202 use std::io::ErrorKind::*; 203 let errno = match e.kind() { 204 PermissionDenied => HostIoErrno::EPERM, 205 NotFound => HostIoErrno::ENOENT, 206 Interrupted => HostIoErrno::EINTR, 207 AlreadyExists => HostIoErrno::EEXIST, 208 InvalidInput => HostIoErrno::EINVAL, 209 _ => HostIoErrno::EUNKNOWN, 210 }; 211 HostIoError::Errno(errno) 212 } 213 } 214 215 /// A specialized `Result` type for Host I/O operations. Supports reporting 216 /// non-fatal errors back to the GDB client. 217 /// 218 /// See [`HostIoError`] for more details. 219 pub type HostIoResult<T, Tgt> = Result<T, HostIoError<<Tgt as Target>::Error>>; 220 221 /// Target Extension - Perform I/O operations on host 222 pub trait HostIo: Target { 223 /// Support `open` operation. 224 #[inline(always)] support_open(&mut self) -> Option<HostIoOpenOps<'_, Self>>225 fn support_open(&mut self) -> Option<HostIoOpenOps<'_, Self>> { 226 None 227 } 228 229 /// Support `close` operation. 230 #[inline(always)] support_close(&mut self) -> Option<HostIoCloseOps<'_, Self>>231 fn support_close(&mut self) -> Option<HostIoCloseOps<'_, Self>> { 232 None 233 } 234 235 /// Support `pread` operation. 236 #[inline(always)] support_pread(&mut self) -> Option<HostIoPreadOps<'_, Self>>237 fn support_pread(&mut self) -> Option<HostIoPreadOps<'_, Self>> { 238 None 239 } 240 241 /// Support `pwrite` operation. 242 #[inline(always)] support_pwrite(&mut self) -> Option<HostIoPwriteOps<'_, Self>>243 fn support_pwrite(&mut self) -> Option<HostIoPwriteOps<'_, Self>> { 244 None 245 } 246 247 /// Support `fstat` operation. 248 #[inline(always)] support_fstat(&mut self) -> Option<HostIoFstatOps<'_, Self>>249 fn support_fstat(&mut self) -> Option<HostIoFstatOps<'_, Self>> { 250 None 251 } 252 253 /// Support `unlink` operation. 254 #[inline(always)] support_unlink(&mut self) -> Option<HostIoUnlinkOps<'_, Self>>255 fn support_unlink(&mut self) -> Option<HostIoUnlinkOps<'_, Self>> { 256 None 257 } 258 259 /// Support `readlink` operation. 260 #[inline(always)] support_readlink(&mut self) -> Option<HostIoReadlinkOps<'_, Self>>261 fn support_readlink(&mut self) -> Option<HostIoReadlinkOps<'_, Self>> { 262 None 263 } 264 265 /// Support `setfs` operation. 266 #[inline(always)] support_setfs(&mut self) -> Option<HostIoSetfsOps<'_, Self>>267 fn support_setfs(&mut self) -> Option<HostIoSetfsOps<'_, Self>> { 268 None 269 } 270 } 271 272 define_ext!(HostIoOps, HostIo); 273 274 /// Nested Target Extension - Host I/O open operation. 275 pub trait HostIoOpen: HostIo { 276 /// Open a file at `filename` and return a file descriptor for it, or return 277 /// [`HostIoError::Errno`] if an error occurs. 278 /// 279 /// `flags` are the flags used when opening the file (see 280 /// [`HostIoOpenFlags`]), and `mode` is the mode used if the file is 281 /// created (see [`HostIoOpenMode`]). open( &mut self, filename: &[u8], flags: HostIoOpenFlags, mode: HostIoOpenMode, ) -> HostIoResult<u32, Self>282 fn open( 283 &mut self, 284 filename: &[u8], 285 flags: HostIoOpenFlags, 286 mode: HostIoOpenMode, 287 ) -> HostIoResult<u32, Self>; 288 } 289 290 define_ext!(HostIoOpenOps, HostIoOpen); 291 292 /// Nested Target Extension - Host I/O close operation. 293 pub trait HostIoClose: HostIo { 294 /// Close the open file corresponding to `fd`. close(&mut self, fd: u32) -> HostIoResult<(), Self>295 fn close(&mut self, fd: u32) -> HostIoResult<(), Self>; 296 } 297 298 define_ext!(HostIoCloseOps, HostIoClose); 299 300 /// Nested Target Extension - Host I/O pread operation. 301 pub trait HostIoPread: HostIo { 302 /// Read data from the open file corresponding to `fd`. 303 /// 304 /// Up to `count` bytes will be read from the file, starting at `offset` 305 /// relative to the start of the file. 306 /// 307 /// Return the number of bytes written into `buf` (which may be less than 308 /// `count`). 309 /// 310 /// If `offset` is greater than the length of the underlying data, return 311 /// `Ok(0)`. pread( &mut self, fd: u32, count: usize, offset: u64, buf: &mut [u8], ) -> HostIoResult<usize, Self>312 fn pread( 313 &mut self, 314 fd: u32, 315 count: usize, 316 offset: u64, 317 buf: &mut [u8], 318 ) -> HostIoResult<usize, Self>; 319 } 320 321 define_ext!(HostIoPreadOps, HostIoPread); 322 323 /// Nested Target Extension - Host I/O pwrite operation. 324 pub trait HostIoPwrite: HostIo { 325 /// Write `data` to the open file corresponding to `fd`. 326 /// 327 /// Start the write at `offset` from the start of the file. 328 /// 329 /// Return the number of bytes written, which may be shorter 330 /// 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>331 fn pwrite( 332 &mut self, 333 fd: u32, 334 offset: <Self::Arch as Arch>::Usize, 335 data: &[u8], 336 ) -> HostIoResult<<Self::Arch as Arch>::Usize, Self>; 337 } 338 339 define_ext!(HostIoPwriteOps, HostIoPwrite); 340 341 /// Nested Target Extension - Host I/O fstat operation. 342 pub trait HostIoFstat: HostIo { 343 /// Get information about the open file corresponding to `fd`. 344 /// 345 /// On success return a [`HostIoStat`] struct. 346 /// Return [`HostIoError::Errno`] if an error occurs. fstat(&mut self, fd: u32) -> HostIoResult<HostIoStat, Self>347 fn fstat(&mut self, fd: u32) -> HostIoResult<HostIoStat, Self>; 348 } 349 350 define_ext!(HostIoFstatOps, HostIoFstat); 351 352 /// Nested Target Extension - Host I/O unlink operation. 353 pub trait HostIoUnlink: HostIo { 354 /// Delete the file at `filename` on the target. unlink(&mut self, filename: &[u8]) -> HostIoResult<(), Self>355 fn unlink(&mut self, filename: &[u8]) -> HostIoResult<(), Self>; 356 } 357 358 define_ext!(HostIoUnlinkOps, HostIoUnlink); 359 360 /// Nested Target Extension - Host I/O readlink operation. 361 pub trait HostIoReadlink: HostIo { 362 /// Read value of symbolic link `filename` on the target. 363 /// 364 /// Return the number of bytes written into `buf`. 365 /// 366 /// Unlike most other Host IO handlers, if the resolved file path exceeds 367 /// the length of the provided `buf`, the target should NOT return a 368 /// partial response, and MUST return a `Err(HostIoErrno::ENAMETOOLONG)`. readlink(&mut self, filename: &[u8], buf: &mut [u8]) -> HostIoResult<usize, Self>369 fn readlink(&mut self, filename: &[u8], buf: &mut [u8]) -> HostIoResult<usize, Self>; 370 } 371 372 define_ext!(HostIoReadlinkOps, HostIoReadlink); 373 374 /// Nested Target Extension - Host I/O setfs operation. 375 pub trait HostIoSetfs: HostIo { 376 /// Select the filesystem on which vFile operations with filename arguments 377 /// will operate. This is required for GDB to be able to access files on 378 /// remote targets where the remote stub does not share a common filesystem 379 /// with the inferior(s). 380 /// 381 /// See [`FsKind`] for the meaning of `fs`. 382 /// 383 /// If setfs indicates success, the selected filesystem remains selected 384 /// until the next successful setfs operation. setfs(&mut self, fs: FsKind) -> HostIoResult<(), Self>385 fn setfs(&mut self, fs: FsKind) -> HostIoResult<(), Self>; 386 } 387 388 define_ext!(HostIoSetfsOps, HostIoSetfs); 389