/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Host/File.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- File.h --------------------------------------------------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #ifndef LLDB_HOST_FILE_H |
10 | | #define LLDB_HOST_FILE_H |
11 | | |
12 | | #include "lldb/Host/PosixApi.h" |
13 | | #include "lldb/Host/Terminal.h" |
14 | | #include "lldb/Utility/IOObject.h" |
15 | | #include "lldb/Utility/Status.h" |
16 | | #include "lldb/lldb-private.h" |
17 | | #include "llvm/ADT/BitmaskEnum.h" |
18 | | |
19 | | #include <cstdarg> |
20 | | #include <cstdio> |
21 | | #include <mutex> |
22 | | #include <optional> |
23 | | #include <sys/types.h> |
24 | | |
25 | | namespace lldb_private { |
26 | | |
27 | | LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); |
28 | | |
29 | | /// \class File File.h "lldb/Host/File.h" |
30 | | /// An abstract base class for files. |
31 | | /// |
32 | | /// Files will often be NativeFiles, which provides a wrapper |
33 | | /// around host OS file functionality. But it |
34 | | /// is also possible to subclass file to provide objects that have file |
35 | | /// or stream functionality but are not backed by any host OS file. |
36 | | class File : public IOObject { |
37 | | public: |
38 | | static int kInvalidDescriptor; |
39 | | static FILE *kInvalidStream; |
40 | | |
41 | | // NB this enum is used in the lldb platform gdb-remote packet |
42 | | // vFile:open: and existing values cannot be modified. |
43 | | // |
44 | | // The first set of values is defined by gdb headers and can be found |
45 | | // in the documentation at: |
46 | | // * https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags |
47 | | // |
48 | | // The second half are LLDB extensions and use the highest uint32_t bits |
49 | | // to avoid risk of collisions with future gdb remote protocol changes. |
50 | | enum OpenOptions : uint32_t { |
51 | | eOpenOptionReadOnly = 0x0, // Open file for reading (only) |
52 | | eOpenOptionWriteOnly = 0x1, // Open file for writing (only) |
53 | | eOpenOptionReadWrite = 0x2, // Open file for both reading and writing |
54 | | eOpenOptionAppend = |
55 | | 0x8, // Don't truncate file when opening, append to end of file |
56 | | eOpenOptionCanCreate = 0x200, // Create file if doesn't already exist |
57 | | eOpenOptionTruncate = 0x400, // Truncate file when opening |
58 | | eOpenOptionCanCreateNewOnly = |
59 | | 0x800, // Can create file only if it doesn't already exist |
60 | | |
61 | | eOpenOptionNonBlocking = (1u << 28), // File reads |
62 | | eOpenOptionDontFollowSymlinks = (1u << 29), |
63 | | eOpenOptionCloseOnExec = |
64 | | (1u << 30), // Close the file when executing a new process |
65 | | eOpenOptionInvalid = (1u << 31), // Used as invalid value |
66 | | LLVM_MARK_AS_BITMASK_ENUM(/* largest_value= */ eOpenOptionInvalid) |
67 | | }; |
68 | | |
69 | | static mode_t ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options); |
70 | | static llvm::Expected<OpenOptions> GetOptionsFromMode(llvm::StringRef mode); |
71 | 4.02M | static bool DescriptorIsValid(int descriptor) { return descriptor >= 0; }; |
72 | | static llvm::Expected<const char *> |
73 | | GetStreamOpenModeFromOptions(OpenOptions options); |
74 | | |
75 | 46.1k | File() : IOObject(eFDTypeFile){}; |
76 | | |
77 | | /// Read bytes from a file from the current file position into buf. |
78 | | /// |
79 | | /// NOTE: This function is NOT thread safe. Use the read function |
80 | | /// that takes an "off_t &offset" to ensure correct operation in multi- |
81 | | /// threaded environments. |
82 | | /// |
83 | | /// \param[in,out] num_bytes |
84 | | /// Pass in the size of buf. Read will pass out the number |
85 | | /// of bytes read. Zero bytes read with no error indicates |
86 | | /// EOF. |
87 | | /// |
88 | | /// \return |
89 | | /// success, ENOTSUP, or another error. |
90 | | Status Read(void *buf, size_t &num_bytes) override; |
91 | | |
92 | | /// Write bytes from buf to a file at the current file position. |
93 | | /// |
94 | | /// NOTE: This function is NOT thread safe. Use the write function |
95 | | /// that takes an "off_t &offset" to ensure correct operation in multi- |
96 | | /// threaded environments. |
97 | | /// |
98 | | /// \param[in,out] num_bytes |
99 | | /// Pass in the size of buf. Write will pass out the number |
100 | | /// of bytes written. Write will attempt write the full number |
101 | | /// of bytes and will not return early except on error. |
102 | | /// |
103 | | /// \return |
104 | | /// success, ENOTSUP, or another error. |
105 | | Status Write(const void *buf, size_t &num_bytes) override; |
106 | | |
107 | | /// IsValid |
108 | | /// |
109 | | /// \return |
110 | | /// true iff the file is valid. |
111 | | bool IsValid() const override; |
112 | | |
113 | | /// Flush any buffers and release any resources owned by the file. |
114 | | /// After Close() the file will be invalid. |
115 | | /// |
116 | | /// \return |
117 | | /// success or an error. |
118 | | Status Close() override; |
119 | | |
120 | | /// Get a handle that can be used for OS polling interfaces, such |
121 | | /// as WaitForMultipleObjects, select, or epoll. This may return |
122 | | /// IOObject::kInvalidHandleValue if none is available. This will |
123 | | /// generally be the same as the file descriptor, this function |
124 | | /// is not interchangeable with GetDescriptor(). A WaitableHandle |
125 | | /// must only be used for polling, not actual I/O. |
126 | | /// |
127 | | /// \return |
128 | | /// a valid handle or IOObject::kInvalidHandleValue |
129 | | WaitableHandle GetWaitableHandle() override; |
130 | | |
131 | | /// Get the file specification for this file, if possible. |
132 | | /// |
133 | | /// \param[out] file_spec |
134 | | /// the file specification. |
135 | | /// \return |
136 | | /// ENOTSUP, success, or another error. |
137 | | virtual Status GetFileSpec(FileSpec &file_spec) const; |
138 | | |
139 | | /// Get underlying OS file descriptor for this file, or kInvalidDescriptor. |
140 | | /// If the descriptor is valid, then it may be used directly for I/O |
141 | | /// However, the File may also perform it's own buffering, so avoid using |
142 | | /// this if it is not necessary, or use Flush() appropriately. |
143 | | /// |
144 | | /// \return |
145 | | /// a valid file descriptor for this file or kInvalidDescriptor |
146 | | virtual int GetDescriptor() const; |
147 | | |
148 | | /// Get the underlying libc stream for this file, or NULL. |
149 | | /// |
150 | | /// Not all valid files will have a FILE* stream. This should only be |
151 | | /// used if absolutely necessary, such as to interact with 3rd party |
152 | | /// libraries that need FILE* streams. |
153 | | /// |
154 | | /// \return |
155 | | /// a valid stream or NULL; |
156 | | virtual FILE *GetStream(); |
157 | | |
158 | | /// Seek to an offset relative to the beginning of the file. |
159 | | /// |
160 | | /// NOTE: This function is NOT thread safe, other threads that |
161 | | /// access this object might also change the current file position. For |
162 | | /// thread safe reads and writes see the following functions: @see |
163 | | /// File::Read (void *, size_t, off_t &) \see File::Write (const void *, |
164 | | /// size_t, off_t &) |
165 | | /// |
166 | | /// \param[in] offset |
167 | | /// The offset to seek to within the file relative to the |
168 | | /// beginning of the file. |
169 | | /// |
170 | | /// \param[in] error_ptr |
171 | | /// A pointer to a lldb_private::Status object that will be |
172 | | /// filled in if non-nullptr. |
173 | | /// |
174 | | /// \return |
175 | | /// The resulting seek offset, or -1 on error. |
176 | | virtual off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr); |
177 | | |
178 | | /// Seek to an offset relative to the current file position. |
179 | | /// |
180 | | /// NOTE: This function is NOT thread safe, other threads that |
181 | | /// access this object might also change the current file position. For |
182 | | /// thread safe reads and writes see the following functions: @see |
183 | | /// File::Read (void *, size_t, off_t &) \see File::Write (const void *, |
184 | | /// size_t, off_t &) |
185 | | /// |
186 | | /// \param[in] offset |
187 | | /// The offset to seek to within the file relative to the |
188 | | /// current file position. |
189 | | /// |
190 | | /// \param[in] error_ptr |
191 | | /// A pointer to a lldb_private::Status object that will be |
192 | | /// filled in if non-nullptr. |
193 | | /// |
194 | | /// \return |
195 | | /// The resulting seek offset, or -1 on error. |
196 | | virtual off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr); |
197 | | |
198 | | /// Seek to an offset relative to the end of the file. |
199 | | /// |
200 | | /// NOTE: This function is NOT thread safe, other threads that |
201 | | /// access this object might also change the current file position. For |
202 | | /// thread safe reads and writes see the following functions: @see |
203 | | /// File::Read (void *, size_t, off_t &) \see File::Write (const void *, |
204 | | /// size_t, off_t &) |
205 | | /// |
206 | | /// \param[in,out] offset |
207 | | /// The offset to seek to within the file relative to the |
208 | | /// end of the file which gets filled in with the resulting |
209 | | /// absolute file offset. |
210 | | /// |
211 | | /// \param[in] error_ptr |
212 | | /// A pointer to a lldb_private::Status object that will be |
213 | | /// filled in if non-nullptr. |
214 | | /// |
215 | | /// \return |
216 | | /// The resulting seek offset, or -1 on error. |
217 | | virtual off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr); |
218 | | |
219 | | /// Read bytes from a file from the specified file offset. |
220 | | /// |
221 | | /// NOTE: This function is thread safe in that clients manager their |
222 | | /// own file position markers and reads on other threads won't mess up the |
223 | | /// current read. |
224 | | /// |
225 | | /// \param[in] dst |
226 | | /// A buffer where to put the bytes that are read. |
227 | | /// |
228 | | /// \param[in,out] num_bytes |
229 | | /// The number of bytes to read from the current file position |
230 | | /// which gets modified with the number of bytes that were read. |
231 | | /// |
232 | | /// \param[in,out] offset |
233 | | /// The offset within the file from which to read \a num_bytes |
234 | | /// bytes. This offset gets incremented by the number of bytes |
235 | | /// that were read. |
236 | | /// |
237 | | /// \return |
238 | | /// An error object that indicates success or the reason for |
239 | | /// failure. |
240 | | virtual Status Read(void *dst, size_t &num_bytes, off_t &offset); |
241 | | |
242 | | /// Write bytes to a file at the specified file offset. |
243 | | /// |
244 | | /// NOTE: This function is thread safe in that clients manager their |
245 | | /// own file position markers, though clients will need to implement their |
246 | | /// own locking externally to avoid multiple people writing to the file at |
247 | | /// the same time. |
248 | | /// |
249 | | /// \param[in] src |
250 | | /// A buffer containing the bytes to write. |
251 | | /// |
252 | | /// \param[in,out] num_bytes |
253 | | /// The number of bytes to write to the file at offset \a offset. |
254 | | /// \a num_bytes gets modified with the number of bytes that |
255 | | /// were read. |
256 | | /// |
257 | | /// \param[in,out] offset |
258 | | /// The offset within the file at which to write \a num_bytes |
259 | | /// bytes. This offset gets incremented by the number of bytes |
260 | | /// that were written. |
261 | | /// |
262 | | /// \return |
263 | | /// An error object that indicates success or the reason for |
264 | | /// failure. |
265 | | virtual Status Write(const void *src, size_t &num_bytes, off_t &offset); |
266 | | |
267 | | /// Flush the current stream |
268 | | /// |
269 | | /// \return |
270 | | /// An error object that indicates success or the reason for |
271 | | /// failure. |
272 | | virtual Status Flush(); |
273 | | |
274 | | /// Sync to disk. |
275 | | /// |
276 | | /// \return |
277 | | /// An error object that indicates success or the reason for |
278 | | /// failure. |
279 | | virtual Status Sync(); |
280 | | |
281 | | /// Output printf formatted output to the stream. |
282 | | /// |
283 | | /// NOTE: this is not virtual, because it just calls the va_list |
284 | | /// version of the function. |
285 | | /// |
286 | | /// Print some formatted output to the stream. |
287 | | /// |
288 | | /// \param[in] format |
289 | | /// A printf style format string. |
290 | | /// |
291 | | /// \param[in] ... |
292 | | /// Variable arguments that are needed for the printf style |
293 | | /// format string \a format. |
294 | | size_t Printf(const char *format, ...) __attribute__((format(printf, 2, 3))); |
295 | | |
296 | | /// Output printf formatted output to the stream. |
297 | | /// |
298 | | /// Print some formatted output to the stream. |
299 | | /// |
300 | | /// \param[in] format |
301 | | /// A printf style format string. |
302 | | /// |
303 | | /// \param[in] args |
304 | | /// Variable arguments that are needed for the printf style |
305 | | /// format string \a format. |
306 | | virtual size_t PrintfVarArg(const char *format, va_list args); |
307 | | |
308 | | /// Return the OpenOptions for this file. |
309 | | /// |
310 | | /// Some options like eOpenOptionDontFollowSymlinks only make |
311 | | /// sense when a file is being opened (or not at all) |
312 | | /// and may not be preserved for this method. But any valid |
313 | | /// File should return either eOpenOptionReadOnly, eOpenOptionWriteOnly |
314 | | /// or eOpenOptionReadWrite here. |
315 | | /// |
316 | | /// \return |
317 | | /// OpenOptions flags for this file, or an error. |
318 | | virtual llvm::Expected<OpenOptions> GetOptions() const; |
319 | | |
320 | 18 | llvm::Expected<const char *> GetOpenMode() const { |
321 | 18 | auto opts = GetOptions(); |
322 | 18 | if (!opts) |
323 | 0 | return opts.takeError(); |
324 | 18 | return GetStreamOpenModeFromOptions(opts.get()); |
325 | 18 | } |
326 | | |
327 | | /// Get the permissions for a this file. |
328 | | /// |
329 | | /// \return |
330 | | /// Bits logical OR'ed together from the permission bits defined |
331 | | /// in lldb_private::File::Permissions. |
332 | | uint32_t GetPermissions(Status &error) const; |
333 | | |
334 | | /// Return true if this file is interactive. |
335 | | /// |
336 | | /// \return |
337 | | /// True if this file is a terminal (tty or pty), false |
338 | | /// otherwise. |
339 | | bool GetIsInteractive(); |
340 | | |
341 | | /// Return true if this file from a real terminal. |
342 | | /// |
343 | | /// Just knowing a file is a interactive isn't enough, we also need to know |
344 | | /// if the terminal has a width and height so we can do cursor movement and |
345 | | /// other terminal manipulations by sending escape sequences. |
346 | | /// |
347 | | /// \return |
348 | | /// True if this file is a terminal (tty, not a pty) that has |
349 | | /// a non-zero width and height, false otherwise. |
350 | | bool GetIsRealTerminal(); |
351 | | |
352 | | /// Return true if this file is a terminal which supports colors. |
353 | | /// |
354 | | /// \return |
355 | | /// True iff this is a terminal and it supports colors. |
356 | | bool GetIsTerminalWithColors(); |
357 | | |
358 | 0 | operator bool() const { return IsValid(); }; |
359 | | |
360 | 36.8k | bool operator!() const { return !IsValid(); }; |
361 | | |
362 | | static char ID; |
363 | 38.3k | virtual bool isA(const void *classID) const { return classID == &ID; } |
364 | 0 | static bool classof(const File *file) { return file->isA(&ID); } |
365 | | |
366 | | protected: |
367 | | LazyBool m_is_interactive = eLazyBoolCalculate; |
368 | | LazyBool m_is_real_terminal = eLazyBoolCalculate; |
369 | | LazyBool m_supports_colors = eLazyBoolCalculate; |
370 | | |
371 | | void CalculateInteractiveAndTerminal(); |
372 | | |
373 | | private: |
374 | | File(const File &) = delete; |
375 | | const File &operator=(const File &) = delete; |
376 | | }; |
377 | | |
378 | | class NativeFile : public File { |
379 | | public: |
380 | 0 | NativeFile() : m_descriptor(kInvalidDescriptor), m_stream(kInvalidStream) {} |
381 | | |
382 | | NativeFile(FILE *fh, bool transfer_ownership) |
383 | 20.0k | : m_descriptor(kInvalidDescriptor), m_own_descriptor(false), m_stream(fh), |
384 | 20.0k | m_options(), m_own_stream(transfer_ownership) {} |
385 | | |
386 | | NativeFile(int fd, OpenOptions options, bool transfer_ownership) |
387 | 26.0k | : m_descriptor(fd), m_own_descriptor(transfer_ownership), |
388 | 26.0k | m_stream(kInvalidStream), m_options(options), m_own_stream(false) {} |
389 | | |
390 | 45.9k | ~NativeFile() override { Close(); } |
391 | | |
392 | | bool IsValid() const override; |
393 | | |
394 | | Status Read(void *buf, size_t &num_bytes) override; |
395 | | Status Write(const void *buf, size_t &num_bytes) override; |
396 | | Status Close() override; |
397 | | WaitableHandle GetWaitableHandle() override; |
398 | | Status GetFileSpec(FileSpec &file_spec) const override; |
399 | | int GetDescriptor() const override; |
400 | | FILE *GetStream() override; |
401 | | off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr) override; |
402 | | off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr) override; |
403 | | off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr) override; |
404 | | Status Read(void *dst, size_t &num_bytes, off_t &offset) override; |
405 | | Status Write(const void *src, size_t &num_bytes, off_t &offset) override; |
406 | | Status Flush() override; |
407 | | Status Sync() override; |
408 | | size_t PrintfVarArg(const char *format, va_list args) override; |
409 | | llvm::Expected<OpenOptions> GetOptions() const override; |
410 | | |
411 | | static char ID; |
412 | 38.3k | bool isA(const void *classID) const override { |
413 | 38.3k | return classID == &ID || File::isA(classID); |
414 | 38.3k | } |
415 | 0 | static bool classof(const File *file) { return file->isA(&ID); } |
416 | | |
417 | | protected: |
418 | | struct ValueGuard { |
419 | 2.02M | ValueGuard(std::mutex &m, bool b) : guard(m, std::adopt_lock), value(b) {} |
420 | | std::lock_guard<std::mutex> guard; |
421 | | bool value; |
422 | 2.02M | operator bool() { return value; } |
423 | | }; |
424 | | |
425 | 4.00M | bool DescriptorIsValidUnlocked() const { |
426 | | |
427 | 4.00M | return File::DescriptorIsValid(m_descriptor); |
428 | 4.00M | } |
429 | | |
430 | 656k | bool StreamIsValidUnlocked() const { return m_stream != kInvalidStream; } |
431 | | |
432 | 1.93M | ValueGuard DescriptorIsValid() const { |
433 | 1.93M | m_descriptor_mutex.lock(); |
434 | 1.93M | return ValueGuard(m_descriptor_mutex, DescriptorIsValidUnlocked()); |
435 | 1.93M | } |
436 | | |
437 | 98.7k | ValueGuard StreamIsValid() const { |
438 | 98.7k | m_stream_mutex.lock(); |
439 | 98.7k | return ValueGuard(m_stream_mutex, StreamIsValidUnlocked()); |
440 | 98.7k | } |
441 | | |
442 | | int m_descriptor; |
443 | | bool m_own_descriptor = false; |
444 | | mutable std::mutex m_descriptor_mutex; |
445 | | |
446 | | FILE *m_stream; |
447 | | mutable std::mutex m_stream_mutex; |
448 | | |
449 | | OpenOptions m_options{}; |
450 | | bool m_own_stream = false; |
451 | | std::mutex offset_access_mutex; |
452 | | |
453 | | private: |
454 | | NativeFile(const NativeFile &) = delete; |
455 | | const NativeFile &operator=(const NativeFile &) = delete; |
456 | | }; |
457 | | |
458 | | class SerialPort : public NativeFile { |
459 | | public: |
460 | | struct Options { |
461 | | std::optional<unsigned int> BaudRate; |
462 | | std::optional<Terminal::Parity> Parity; |
463 | | std::optional<Terminal::ParityCheck> ParityCheck; |
464 | | std::optional<unsigned int> StopBits; |
465 | | }; |
466 | | |
467 | | // Obtain Options corresponding to the passed URL query string |
468 | | // (i.e. the part after '?'). |
469 | | static llvm::Expected<Options> OptionsFromURL(llvm::StringRef urlqs); |
470 | | |
471 | | static llvm::Expected<std::unique_ptr<SerialPort>> |
472 | | Create(int fd, OpenOptions options, Options serial_options, |
473 | | bool transfer_ownership); |
474 | | |
475 | 331 | bool IsValid() const override { |
476 | 331 | return NativeFile::IsValid() && m_is_interactive == eLazyBoolYes286 ; |
477 | 331 | } |
478 | | |
479 | | Status Close() override; |
480 | | |
481 | | static char ID; |
482 | 0 | bool isA(const void *classID) const override { |
483 | 0 | return classID == &ID || File::isA(classID); |
484 | 0 | } |
485 | 0 | static bool classof(const File *file) { return file->isA(&ID); } |
486 | | |
487 | | private: |
488 | | SerialPort(int fd, OpenOptions options, Options serial_options, |
489 | | bool transfer_ownership); |
490 | | |
491 | | SerialPort(const SerialPort &) = delete; |
492 | | const SerialPort &operator=(const SerialPort &) = delete; |
493 | | |
494 | | TerminalState m_state; |
495 | | }; |
496 | | |
497 | | } // namespace lldb_private |
498 | | |
499 | | #endif // LLDB_HOST_FILE_H |