xref: /haiku/src/bin/debug/debug_utils.cpp (revision 4466b89c65970de4c7236ac87faa2bee4589f413)
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 
21 extern const char* __progname;
22 static const char* kCommandName = __progname;
23 
24 
25 // find_program
26 static status_t
27 find_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
74 thread_id
75 load_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
119 void
120 set_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
141 void
142 set_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
164 void
165 continue_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 %ld: %s\n",
180 				kCommandName, thread, strerror(error));
181 			exit(1);
182 		}
183 	}
184 }
185