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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
|
//===-- source/Host/linux/Host.cpp ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
#include <stdio.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Error.h"
#include "lldb/Target/Process.h"
#include "lldb/Host/Host.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
using namespace lldb;
using namespace lldb_private;
namespace
{
lldb::DataBufferSP
ReadProcPseudoFile(lldb::pid_t pid, const char *name)
{
static const size_t path_size = 128;
static char path[path_size];
lldb::DataBufferSP buf_sp;
int fd;
// 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_size, "/proc/%" PRIu64 "/%s", pid, name) < 0)
return buf_sp;
if ((fd = open(path, O_RDONLY, 0)) < 0)
return buf_sp;
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;
bytes_read += status;
if (status == 0)
{
buf_ap->SetByteSize(bytes_read);
buf_sp.reset(buf_ap.release());
break;
}
if (avail - status == 0)
buf_ap->SetByteSize(2 * buf_ap->GetByteSize());
}
return buf_sp;
}
} // anonymous namespace
bool
Host::GetOSVersion(uint32_t &major,
uint32_t &minor,
uint32_t &update)
{
struct utsname un;
int status;
if (uname(&un))
return false;
status = sscanf(un.release, "%u.%u.%u", &major, &minor, &update);
return status == 3;
}
Error
Host::LaunchProcess (ProcessLaunchInfo &launch_info)
{
Error error;
assert(!"Not implemented yet!!!");
return error;
}
lldb::DataBufferSP
Host::GetAuxvData(lldb_private::Process *process)
{
return ReadProcPseudoFile(process->GetID(), "auxv");
}
bool
Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
{
process_info.Clear();
process_info.SetProcessID(pid);
// Architecture is intentionally omitted because that's better resolved
// in other places (see ProcessPOSIX::DoAttachWithID().
// Use special code here because proc/[pid]/exe is a symbolic link.
char link_path[PATH_MAX];
char exe_path[PATH_MAX] = "";
if (snprintf(link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", pid) > 0)
{
ssize_t len = readlink(link_path, exe_path, sizeof(exe_path) - 1);
if (len > 0)
exe_path[len] = 0;
static const ssize_t deleted_len = strlen(" (deleted)");
if (len > deleted_len &&
!strcmp(exe_path + len - deleted_len, " (deleted)"))
{
exe_path[len - deleted_len] = 0;
}
}
process_info.GetExecutableFile().SetFile(exe_path, false);
lldb::DataBufferSP buf_sp;
// Get the process environment.
buf_sp = ReadProcPseudoFile(pid, "environ");
Args &info_env = process_info.GetEnvironmentEntries();
char *next_var = (char *)buf_sp->GetBytes();
char *end_buf = next_var + buf_sp->GetByteSize();
while (next_var < end_buf && 0 != *next_var)
{
info_env.AppendArgument(next_var);
next_var += strlen(next_var) + 1;
}
// Get the commond line used to start the process.
buf_sp = ReadProcPseudoFile(pid, "cmdline");
// Grab Arg0 first.
char *cmd = (char *)buf_sp->GetBytes();
process_info.SetArg0(cmd);
// Now process any remaining arguments.
Args &info_args = process_info.GetArguments();
char *next_arg = cmd + strlen(cmd) + 1;
end_buf = cmd + buf_sp->GetByteSize();
while (next_arg < end_buf && 0 != *next_arg)
{
info_args.AppendArgument(next_arg);
next_arg += strlen(next_arg) + 1;
}
// FIXME: Parse /proc/<pid>/status to get uid, gid, euid, egid and parent_pid
return true;
}
void
Host::ThreadCreated (const char *thread_name)
{
if (!Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name))
{
// pthread_setname_np_func can fail if the thread name is longer than
// the supported limit on Linux. When this occurs, the error ERANGE is returned
// and SetThreadName will fail. Let's drop it down to 16 characters and try again.
char namebuf[16];
// Thread names are coming in like '<lldb.comm.debugger.edit>' and '<lldb.comm.debugger.editline>'
// So just chopping the end of the string off leads to a lot of similar named threads.
// Go through the thread name and search for the last dot and use that.
const char *lastdot = ::strrchr( thread_name, '.' );
if (lastdot && lastdot != thread_name)
thread_name = lastdot + 1;
::strncpy (namebuf, thread_name, sizeof(namebuf));
namebuf[ sizeof(namebuf) - 1 ] = 0;
int namebuflen = strlen(namebuf);
if (namebuflen > 0)
{
if (namebuf[namebuflen - 1] == '(' || namebuf[namebuflen - 1] == '>')
{
// Trim off trailing '(' and '>' characters for a bit more cleanup.
namebuflen--;
namebuf[namebuflen] = 0;
}
Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, namebuf);
}
}
}
void
Host::Backtrace (Stream &strm, uint32_t max_frames)
{
// TODO: Is there a way to backtrace the current process on linux?
}
size_t
Host::GetEnvironment (StringList &env)
{
// TODO: Is there a way to the host environment for this process on linux?
return 0;
}
|