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