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