xref: /haiku/src/kits/debug/TeamDebugger.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 
23 BTeamDebugger::BTeamDebugger()
24 	:
25 	fDebuggerPort(-1)
26 {
27 }
28 
29 
30 BTeamDebugger::~BTeamDebugger()
31 {
32 	Uninstall();
33 }
34 
35 
36 status_t
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
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
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
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
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
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