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