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 | |
| 26 | lldb::DataBufferSP |
| 27 | lldb_private::ProcFileReader::ReadIntoDataBuffer (lldb::pid_t pid, const char *name) |
| 28 | { |
| 29 | int fd; |
| 30 | char path[PATH_MAX]; |
| 31 | |
| 32 | // Make sure we've got a nil terminated buffer for all the folks calling |
| 33 | // GetBytes() directly off our returned DataBufferSP if we hit an error. |
| 34 | lldb::DataBufferSP buf_sp (new DataBufferHeap(1, 0)); |
| 35 | |
| 36 | // Ideally, we would simply create a FileSpec and call ReadFileContents. |
| 37 | // However, files in procfs have zero size (since they are, in general, |
| 38 | // dynamically generated by the kernel) which is incompatible with the |
| 39 | // current ReadFileContents implementation. Therefore we simply stream the |
| 40 | // data into a DataBuffer ourselves. |
| 41 | if (snprintf (path, PATH_MAX, "/proc/%" PRIu64 "/%s", pid, name) > 0) |
| 42 | { |
| 43 | if ((fd = open (path, O_RDONLY, 0)) >= 0) |
| 44 | { |
| 45 | size_t bytes_read = 0; |
| 46 | std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0)); |
| 47 | |
| 48 | for (;;) |
| 49 | { |
| 50 | size_t avail = buf_ap->GetByteSize() - bytes_read; |
| 51 | ssize_t status = read (fd, buf_ap->GetBytes() + bytes_read, avail); |
| 52 | |
| 53 | if (status < 0) |
| 54 | break; |
| 55 | |
| 56 | if (status == 0) |
| 57 | { |
| 58 | buf_ap->SetByteSize (bytes_read); |
| 59 | buf_sp.reset (buf_ap.release()); |
| 60 | break; |
| 61 | } |
| 62 | |
| 63 | bytes_read += status; |
| 64 | |
| 65 | if (avail - status == 0) |
| 66 | buf_ap->SetByteSize (2 * buf_ap->GetByteSize()); |
| 67 | } |
| 68 | |
| 69 | close (fd); |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | return buf_sp; |
| 74 | } |
| 75 | |
| 76 | lldb_private::Error |
| 77 | lldb_private::ProcFileReader::ProcessLineByLine (lldb::pid_t pid, const char *name, std::function<bool (const std::string &line)> line_parser) |
| 78 | { |
| 79 | lldb_private::Error error; |
| 80 | |
| 81 | // Try to open the /proc/{pid}/maps entry. |
| 82 | char filename [PATH_MAX]; |
| 83 | snprintf (filename, sizeof(filename), "/proc/%" PRIu64 "/%s", pid, name); |
| 84 | filename[sizeof (filename) - 1] = '\0'; |
| 85 | |
| 86 | std::ifstream proc_file (filename); |
| 87 | if (proc_file.fail ()) |
| 88 | { |
| 89 | error.SetErrorStringWithFormat ("failed to open file '%s'", filename); |
| 90 | return error; |
| 91 | } |
| 92 | |
| 93 | // Read the file line by line, processing until either end of file or when the line_parser returns false. |
| 94 | std::string line; |
| 95 | bool should_continue = true; |
| 96 | |
| 97 | while (should_continue && std::getline (proc_file, line)) |
| 98 | { |
| 99 | // Pass the line over to the line_parser for processing. If the line_parser returns false, we |
| 100 | // stop processing. |
| 101 | should_continue = line_parser (line); |
| 102 | } |
| 103 | |
| 104 | return error; |
| 105 | } |