aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins/Process/Linux/ProcFileReader.cpp
blob: 4d1f231f4f9be017bc0fef58db94204fe64f2fff (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//===-- ProcFileReader.cpp --------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Plugins/Process/Linux/ProcFileReader.h"

// C Headers
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <sys/stat.h>

// C++ Headers
#include <fstream>

// LLDB Headers
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"

using namespace lldb_private;
using namespace lldb_private::process_linux;

lldb::DataBufferSP
ProcFileReader::ReadIntoDataBuffer (lldb::pid_t pid, const char *name)
{
    int fd;
    char path[PATH_MAX];

    // Make sure we've got a nil terminated buffer for all the folks calling
    // GetBytes() directly off our returned DataBufferSP if we hit an error.
    lldb::DataBufferSP buf_sp (new DataBufferHeap(1, 0));

    // Ideally, we would simply create a FileSpec and call ReadFileContents.
    // However, files in procfs have zero size (since they are, in general,
    // dynamically generated by the kernel) which is incompatible with the
    // current ReadFileContents implementation. Therefore we simply stream the
    // data into a DataBuffer ourselves.
    if (snprintf (path, PATH_MAX, "/proc/%" PRIu64 "/%s", pid, name) > 0)
    {
        if ((fd = open (path, O_RDONLY, 0)) >= 0)
        {
            size_t bytes_read = 0;
            std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));

            for (;;)
            {
                size_t avail = buf_ap->GetByteSize() - bytes_read;
                ssize_t status = read (fd, buf_ap->GetBytes() + bytes_read, avail);

                if (status < 0)
                    break;

                if (status == 0)
                {
                    buf_ap->SetByteSize (bytes_read);
                    buf_sp.reset (buf_ap.release());
                    break;
                }

                bytes_read += status;

                if (avail - status == 0)
                    buf_ap->SetByteSize (2 * buf_ap->GetByteSize());
            }
            
            close (fd);
        }
    }
    
    return buf_sp;
}

Error
ProcFileReader::ProcessLineByLine (lldb::pid_t pid, const char *name, std::function<bool (const std::string &line)> line_parser)
{
    Error error;

    // Try to open the /proc/{pid}/maps entry.
    char filename [PATH_MAX];
    snprintf (filename, sizeof(filename), "/proc/%" PRIu64 "/%s", pid, name);
    filename[sizeof (filename) - 1] = '\0';

    std::ifstream proc_file (filename);
    if (proc_file.fail ())
    {
        error.SetErrorStringWithFormat ("failed to open file '%s'", filename);
        return error;
    }

    // Read the file line by line, processing until either end of file or when the line_parser returns false.
    std::string line;
    bool should_continue = true;

    while (should_continue && std::getline (proc_file, line))
    {
        // Pass the line over to the line_parser for processing.  If the line_parser returns false, we
        // stop processing.
        should_continue = line_parser (line);
    }

    return error;
}