1 /*
2 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include <TeamDebugger.h>
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/stat.h>
12
13 #include <string.h>
14
15 #include <Path.h>
16 #include <String.h>
17
18 #include <libroot_private.h>
19 #include <syscalls.h>
20 #include <syscall_load_image.h>
21
22
BTeamDebugger()23 BTeamDebugger::BTeamDebugger()
24 :
25 fDebuggerPort(-1)
26 {
27 }
28
29
~BTeamDebugger()30 BTeamDebugger::~BTeamDebugger()
31 {
32 Uninstall();
33 }
34
35
36 status_t
Install(team_id team)37 BTeamDebugger::Install(team_id team)
38 {
39 Uninstall();
40
41 // create a debugger port
42 char name[B_OS_NAME_LENGTH];
43 snprintf(name, sizeof(name), "debugger for team %" B_PRId32, team);
44 fDebuggerPort = create_port(100, name);
45 if (fDebuggerPort < 0)
46 return fDebuggerPort;
47
48 port_id nubPort = install_team_debugger(team, fDebuggerPort);
49 if (nubPort < 0) {
50 delete_port(fDebuggerPort);
51 fDebuggerPort = -1;
52 return nubPort;
53 }
54
55 status_t error = BDebugContext::Init(team, nubPort);
56 if (error != B_OK) {
57 remove_team_debugger(team);
58 delete_port(fDebuggerPort);
59 fDebuggerPort = -1;
60 return error;
61 }
62
63 return B_OK;
64 }
65
66
67 status_t
Uninstall()68 BTeamDebugger::Uninstall()
69 {
70 if (Team() < 0)
71 return B_BAD_VALUE;
72
73 remove_team_debugger(Team());
74
75 delete_port(fDebuggerPort);
76
77 BDebugContext::Uninit();
78
79 fDebuggerPort = -1;
80
81 return B_OK;
82 }
83
84
85 status_t
LoadProgram(const char * const * args,int32 argCount,bool traceLoading)86 BTeamDebugger::LoadProgram(const char* const* args, int32 argCount,
87 bool traceLoading)
88 {
89 // load the program
90 thread_id thread = _LoadProgram(args, argCount, traceLoading);
91 if (thread < 0)
92 return thread;
93
94 // install the debugger
95 status_t error = Install(thread);
96 if (error != B_OK) {
97 kill_team(thread);
98 return error;
99 }
100
101 return B_OK;
102 }
103
104
105 status_t
ReadDebugMessage(int32 & _messageCode,debug_debugger_message_data & messageBuffer)106 BTeamDebugger::ReadDebugMessage(int32& _messageCode,
107 debug_debugger_message_data& messageBuffer)
108 {
109 ssize_t bytesRead = read_port(fDebuggerPort, &_messageCode, &messageBuffer,
110 sizeof(messageBuffer));
111 if (bytesRead < 0)
112 return bytesRead;
113
114 return B_OK;
115 }
116
117
118
119 /*static*/ thread_id
_LoadProgram(const char * const * args,int32 argCount,bool traceLoading)120 BTeamDebugger::_LoadProgram(const char* const* args, int32 argCount,
121 bool traceLoading)
122 {
123 // clone the argument vector so that we can change it
124 const char** mutableArgs = new const char*[argCount];
125 for (int i = 0; i < argCount; i++)
126 mutableArgs[i] = args[i];
127
128 // resolve the program path
129 BPath programPath;
130 status_t error = _FindProgram(args[0], programPath);
131 if (error != B_OK) {
132 delete[] mutableArgs;
133 return error;
134 }
135 mutableArgs[0] = programPath.Path();
136
137 // count environment variables
138 int32 envCount = 0;
139 while (environ[envCount] != NULL)
140 envCount++;
141
142 // flatten the program args and environment
143 char** flatArgs = NULL;
144 size_t flatArgsSize;
145 error = __flatten_process_args(mutableArgs, argCount, environ, &envCount,
146 mutableArgs[0], &flatArgs, &flatArgsSize);
147
148 // load the program
149 thread_id thread;
150 if (error == B_OK) {
151 thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount,
152 B_NORMAL_PRIORITY, (traceLoading ? 0 : B_WAIT_TILL_LOADED), -1, 0);
153
154 free(flatArgs);
155 } else
156 thread = error;
157
158 delete[] mutableArgs;
159
160 return thread;
161 }
162
163
164 /*static*/ status_t
_FindProgram(const char * programName,BPath & resolvedPath)165 BTeamDebugger::_FindProgram(const char* programName, BPath& resolvedPath)
166 {
167 // If the program name is absolute, then there's nothing to do.
168 // If the program name consists of more than one path element, then we
169 // consider it a relative path and don't search in PATH either.
170 if (*programName == '/' || strchr(programName, '/'))
171 return resolvedPath.SetTo(programName);
172
173 // get the PATH environment variable
174 const char* paths = getenv("PATH");
175 if (!paths)
176 return B_ENTRY_NOT_FOUND;
177
178 // iterate through the paths
179 do {
180 const char* pathEnd = strchr(paths, ':');
181 int pathLen = (pathEnd ? pathEnd - paths : strlen(paths));
182
183 // We skip empty paths.
184 if (pathLen > 0) {
185 // get the program path
186 BString directory(paths, pathLen);
187 if (directory.Length() == 0)
188 return B_NO_MEMORY;
189
190 BPath path;
191 status_t error = path.SetTo(directory, programName);
192 if (error != B_OK)
193 continue;
194
195 // stat() the path to be sure, there is a file
196 struct stat st;
197 if (stat(path.Path(), &st) == 0 && S_ISREG(st.st_mode)) {
198 resolvedPath = path;
199 return B_OK;
200 }
201 }
202
203 paths = (pathEnd ? pathEnd + 1 : NULL);
204 } while (paths);
205
206 // not found in PATH
207 return B_ENTRY_NOT_FOUND;
208 }
209