Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 1 | //===-- ProcFileReader.cpp --------------------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
| 10 | #include "Plugins/Process/Linux/ProcFileReader.h" |
| 11 | |
| 12 | // C Headers |
| 13 | #include <fcntl.h> |
| 14 | #include <inttypes.h> |
| 15 | #include <limits.h> |
| 16 | #include <stdio.h> |
| 17 | #include <sys/stat.h> |
| 18 | |
| 19 | // C++ Headers |
| 20 | #include <fstream> |
| 21 | |
| 22 | // LLDB Headers |
| 23 | #include "lldb/Core/DataBufferHeap.h" |
| 24 | #include "lldb/Core/Error.h" |
| 25 | |
Tamas Berghammer | db264a6 | 2015-03-31 09:52:22 +0000 | [diff] [blame] | 26 | using namespace lldb_private; |
| 27 | using namespace lldb_private::process_linux; |
| 28 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 29 | lldb::DataBufferSP ProcFileReader::ReadIntoDataBuffer(lldb::pid_t pid, |
| 30 | const char *name) { |
| 31 | int fd; |
| 32 | char path[PATH_MAX]; |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 33 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 34 | // Make sure we've got a nil terminated buffer for all the folks calling |
| 35 | // GetBytes() directly off our returned DataBufferSP if we hit an error. |
| 36 | lldb::DataBufferSP buf_sp(new DataBufferHeap(1, 0)); |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 37 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 38 | // Ideally, we would simply create a FileSpec and call ReadFileContents. |
| 39 | // However, files in procfs have zero size (since they are, in general, |
| 40 | // dynamically generated by the kernel) which is incompatible with the |
| 41 | // current ReadFileContents implementation. Therefore we simply stream the |
| 42 | // data into a DataBuffer ourselves. |
| 43 | if (snprintf(path, PATH_MAX, "/proc/%" PRIu64 "/%s", pid, name) > 0) { |
| 44 | if ((fd = open(path, O_RDONLY, 0)) >= 0) { |
| 45 | size_t bytes_read = 0; |
| 46 | std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0)); |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 47 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 48 | for (;;) { |
| 49 | size_t avail = buf_ap->GetByteSize() - bytes_read; |
| 50 | ssize_t status = read(fd, buf_ap->GetBytes() + bytes_read, avail); |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 51 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 52 | if (status < 0) |
| 53 | break; |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 54 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 55 | if (status == 0) { |
| 56 | buf_ap->SetByteSize(bytes_read); |
| 57 | buf_sp.reset(buf_ap.release()); |
| 58 | break; |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 59 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 60 | |
| 61 | bytes_read += status; |
| 62 | |
| 63 | if (avail - status == 0) |
| 64 | buf_ap->SetByteSize(2 * buf_ap->GetByteSize()); |
| 65 | } |
| 66 | |
| 67 | close(fd); |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 68 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | return buf_sp; |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 72 | } |
| 73 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 74 | Error ProcFileReader::ProcessLineByLine( |
| 75 | lldb::pid_t pid, const char *name, |
| 76 | std::function<bool(const std::string &line)> line_parser) { |
| 77 | Error error; |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 78 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 79 | // Try to open the /proc/{pid}/maps entry. |
| 80 | char filename[PATH_MAX]; |
| 81 | snprintf(filename, sizeof(filename), "/proc/%" PRIu64 "/%s", pid, name); |
| 82 | filename[sizeof(filename) - 1] = '\0'; |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 83 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 84 | std::ifstream proc_file(filename); |
| 85 | if (proc_file.fail()) { |
| 86 | error.SetErrorStringWithFormat("failed to open file '%s'", filename); |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 87 | return error; |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | // Read the file line by line, processing until either end of file or when the |
| 91 | // line_parser returns false. |
| 92 | std::string line; |
| 93 | bool should_continue = true; |
| 94 | |
| 95 | while (should_continue && std::getline(proc_file, line)) { |
| 96 | // Pass the line over to the line_parser for processing. If the line_parser |
| 97 | // returns false, we |
| 98 | // stop processing. |
| 99 | should_continue = line_parser(line); |
| 100 | } |
| 101 | |
| 102 | return error; |
Todd Fiala | 3dc2fb2 | 2014-06-30 04:14:13 +0000 | [diff] [blame] | 103 | } |