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
23BTeamDebugger::BTeamDebugger()
24	:
25	fDebuggerPort(-1)
26{
27}
28
29
30BTeamDebugger::~BTeamDebugger()
31{
32	Uninstall();
33}
34
35
36status_t
37BTeamDebugger::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
67status_t
68BTeamDebugger::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
85status_t
86BTeamDebugger::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
105status_t
106BTeamDebugger::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
120BTeamDebugger::_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
165BTeamDebugger::_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