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