1/*
2 * Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2013, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7#include "debug_utils.h"
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <sys/stat.h>
12
13#include <string>
14#include <string.h>
15
16#include <debugger.h>
17
18#include <libroot_private.h>
19#include <syscalls.h>
20#include <syscall_load_image.h>
21
22
23extern const char* __progname;
24static const char* kCommandName = __progname;
25
26
27// find_program
28static status_t
29find_program(const char* programName, std::string& resolvedPath)
30{
31    // If the program name is absolute, then there's nothing to do.
32    // If the program name consists of more than one path element, then we
33    // consider it a relative path and don't search in PATH either.
34    if (*programName == '/' || strchr(programName, '/')) {
35        resolvedPath = programName;
36        return B_OK;
37    }
38
39    // get the PATH environment variable
40    const char* paths = getenv("PATH");
41    if (!paths)
42        return B_ENTRY_NOT_FOUND;
43
44    // iterate through the paths
45    do {
46        const char* pathEnd = strchr(paths, ':');
47        int pathLen = (pathEnd ? pathEnd - paths : strlen(paths));
48
49        // We skip empty paths.
50        if (pathLen > 0) {
51            // get the program path
52            std::string path(paths, pathLen);
53            path += "/";
54            path += programName;
55
56            // stat() the path to be sure, there is a file
57            struct stat st;
58            if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
59            	resolvedPath = path;
60                return B_OK;
61            }
62        }
63
64        paths = (pathEnd ? pathEnd + 1 : NULL);
65    } while (paths);
66
67    // not found in PATH
68    return B_ENTRY_NOT_FOUND;
69}
70
71
72// #pragma mark -
73
74
75// load_program
76thread_id
77load_program(const char* const* args, int32 argCount, bool traceLoading)
78{
79	// clone the argument vector so that we can change it
80	const char** mutableArgs = new const char*[argCount];
81	for (int i = 0; i < argCount; i++)
82		mutableArgs[i] = args[i];
83
84	// resolve the program path
85	std::string programPath;
86	status_t error = find_program(args[0], programPath);
87	if (error != B_OK) {
88		delete[] mutableArgs;
89		return error;
90	}
91	mutableArgs[0] = programPath.c_str();
92
93	// count environment variables
94	int32 envCount = 0;
95	while (environ[envCount] != NULL)
96		envCount++;
97
98	// flatten the program args and environment
99	char** flatArgs = NULL;
100	size_t flatArgsSize;
101	error = __flatten_process_args(mutableArgs, argCount, environ, &envCount,
102		mutableArgs[0], &flatArgs, &flatArgsSize);
103
104	// load the program
105	thread_id thread;
106	if (error == B_OK) {
107		thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount,
108			B_NORMAL_PRIORITY, (traceLoading ? 0 : B_WAIT_TILL_LOADED), -1, 0);
109
110		free(flatArgs);
111	} else
112		thread = error;
113
114	delete[] mutableArgs;
115
116	return thread;
117}
118
119
120// set_team_debugging_flags
121status_t
122set_team_debugging_flags(port_id nubPort, int32 flags)
123{
124	debug_nub_set_team_flags message;
125	message.flags = flags;
126
127	status_t error = B_OK;
128	do {
129		error = write_port(nubPort, B_DEBUG_MESSAGE_SET_TEAM_FLAGS,
130			&message, sizeof(message));
131	} while (error == B_INTERRUPTED);
132
133	if (error != B_OK) {
134		fprintf(stderr, "%s: Failed to set team debug flags: %s\n",
135			kCommandName, strerror(error));
136	}
137
138	return error;
139}
140
141
142// set_thread_debugging_flags
143status_t
144set_thread_debugging_flags(port_id nubPort, thread_id thread, int32 flags)
145{
146	debug_nub_set_thread_flags message;
147	message.thread = thread;
148	message.flags = flags;
149
150	status_t error = B_OK;
151	do {
152		error = write_port(nubPort, B_DEBUG_MESSAGE_SET_THREAD_FLAGS,
153			&message, sizeof(message));
154	} while (error == B_INTERRUPTED);
155
156	if (error != B_OK) {
157		fprintf(stderr, "%s: Failed to set thread debug flags: %s\n",
158			kCommandName, strerror(error));
159	}
160
161	return error;
162}
163
164
165// continue_thread
166status_t
167continue_thread(port_id nubPort, thread_id thread)
168{
169	debug_nub_continue_thread message;
170	message.thread = thread;
171	message.handle_event = B_THREAD_DEBUG_HANDLE_EVENT;
172	message.single_step = false;
173
174	status_t error = B_OK;
175
176	do {
177		error = write_port(nubPort, B_DEBUG_MESSAGE_CONTINUE_THREAD,
178			&message, sizeof(message));
179	} while (error == B_INTERRUPTED);
180
181	if (error != B_OK) {
182		fprintf(stderr, "%s: Failed to run thread %" B_PRId32 ": %s\n",
183			kCommandName, thread, strerror(error));
184	}
185
186	return error;
187}
188