xref: /haiku/src/bin/debug/debug_utils.cpp (revision e551626f40c89e7ff5dcac8ce368690fcf382375)
18df6a8dbSIngo Weinhold /*
28df6a8dbSIngo Weinhold  * Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
34dc355e9SRene Gollent  * Copyright 2013, Rene Gollent, rene@gollent.com.
48df6a8dbSIngo Weinhold  * Distributed under the terms of the MIT License.
58df6a8dbSIngo Weinhold  */
68df6a8dbSIngo Weinhold 
78df6a8dbSIngo Weinhold #include "debug_utils.h"
88df6a8dbSIngo Weinhold 
98df6a8dbSIngo Weinhold #include <stdio.h>
108df6a8dbSIngo Weinhold #include <stdlib.h>
118df6a8dbSIngo Weinhold #include <sys/stat.h>
128df6a8dbSIngo Weinhold 
138df6a8dbSIngo Weinhold #include <string>
14fb3e35fcSMichael Lotz #include <string.h>
158df6a8dbSIngo Weinhold 
168df6a8dbSIngo Weinhold #include <debugger.h>
178df6a8dbSIngo Weinhold 
188df6a8dbSIngo Weinhold #include <libroot_private.h>
198df6a8dbSIngo Weinhold #include <syscalls.h>
208df6a8dbSIngo Weinhold 
218df6a8dbSIngo Weinhold 
228df6a8dbSIngo Weinhold extern const char* __progname;
238df6a8dbSIngo Weinhold static const char* kCommandName = __progname;
248df6a8dbSIngo Weinhold 
258df6a8dbSIngo Weinhold 
268df6a8dbSIngo Weinhold // find_program
278df6a8dbSIngo Weinhold static status_t
288df6a8dbSIngo Weinhold find_program(const char* programName, std::string& resolvedPath)
298df6a8dbSIngo Weinhold {
308df6a8dbSIngo Weinhold     // If the program name is absolute, then there's nothing to do.
318df6a8dbSIngo Weinhold     // If the program name consists of more than one path element, then we
328df6a8dbSIngo Weinhold     // consider it a relative path and don't search in PATH either.
338df6a8dbSIngo Weinhold     if (*programName == '/' || strchr(programName, '/')) {
348df6a8dbSIngo Weinhold         resolvedPath = programName;
358df6a8dbSIngo Weinhold         return B_OK;
368df6a8dbSIngo Weinhold     }
378df6a8dbSIngo Weinhold 
388df6a8dbSIngo Weinhold     // get the PATH environment variable
398df6a8dbSIngo Weinhold     const char* paths = getenv("PATH");
408df6a8dbSIngo Weinhold     if (!paths)
418df6a8dbSIngo Weinhold         return B_ENTRY_NOT_FOUND;
428df6a8dbSIngo Weinhold 
438df6a8dbSIngo Weinhold     // iterate through the paths
448df6a8dbSIngo Weinhold     do {
458df6a8dbSIngo Weinhold         const char* pathEnd = strchr(paths, ':');
468df6a8dbSIngo Weinhold         int pathLen = (pathEnd ? pathEnd - paths : strlen(paths));
478df6a8dbSIngo Weinhold 
488df6a8dbSIngo Weinhold         // We skip empty paths.
498df6a8dbSIngo Weinhold         if (pathLen > 0) {
508df6a8dbSIngo Weinhold             // get the program path
518df6a8dbSIngo Weinhold             std::string path(paths, pathLen);
528df6a8dbSIngo Weinhold             path += "/";
538df6a8dbSIngo Weinhold             path += programName;
548df6a8dbSIngo Weinhold 
558df6a8dbSIngo Weinhold             // stat() the path to be sure, there is a file
568df6a8dbSIngo Weinhold             struct stat st;
578df6a8dbSIngo Weinhold             if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
588df6a8dbSIngo Weinhold             	resolvedPath = path;
598df6a8dbSIngo Weinhold                 return B_OK;
608df6a8dbSIngo Weinhold             }
618df6a8dbSIngo Weinhold         }
628df6a8dbSIngo Weinhold 
638df6a8dbSIngo Weinhold         paths = (pathEnd ? pathEnd + 1 : NULL);
648df6a8dbSIngo Weinhold     } while (paths);
658df6a8dbSIngo Weinhold 
668df6a8dbSIngo Weinhold     // not found in PATH
678df6a8dbSIngo Weinhold     return B_ENTRY_NOT_FOUND;
688df6a8dbSIngo Weinhold }
698df6a8dbSIngo Weinhold 
708df6a8dbSIngo Weinhold 
718df6a8dbSIngo Weinhold // #pragma mark -
728df6a8dbSIngo Weinhold 
738df6a8dbSIngo Weinhold 
748df6a8dbSIngo Weinhold // load_program
758df6a8dbSIngo Weinhold thread_id
768df6a8dbSIngo Weinhold load_program(const char* const* args, int32 argCount, bool traceLoading)
778df6a8dbSIngo Weinhold {
788df6a8dbSIngo Weinhold 	// clone the argument vector so that we can change it
798df6a8dbSIngo Weinhold 	const char** mutableArgs = new const char*[argCount];
808df6a8dbSIngo Weinhold 	for (int i = 0; i < argCount; i++)
818df6a8dbSIngo Weinhold 		mutableArgs[i] = args[i];
828df6a8dbSIngo Weinhold 
838df6a8dbSIngo Weinhold 	// resolve the program path
848df6a8dbSIngo Weinhold 	std::string programPath;
858df6a8dbSIngo Weinhold 	status_t error = find_program(args[0], programPath);
868df6a8dbSIngo Weinhold 	if (error != B_OK) {
878df6a8dbSIngo Weinhold 		delete[] mutableArgs;
888df6a8dbSIngo Weinhold 		return error;
898df6a8dbSIngo Weinhold 	}
908df6a8dbSIngo Weinhold 	mutableArgs[0] = programPath.c_str();
918df6a8dbSIngo Weinhold 
928df6a8dbSIngo Weinhold 	// count environment variables
93*e551626fSIngo Weinhold 	int32 envCount = 0;
948df6a8dbSIngo Weinhold 	while (environ[envCount] != NULL)
958df6a8dbSIngo Weinhold 		envCount++;
968df6a8dbSIngo Weinhold 
978df6a8dbSIngo Weinhold 	// flatten the program args and environment
988df6a8dbSIngo Weinhold 	char** flatArgs = NULL;
998df6a8dbSIngo Weinhold 	size_t flatArgsSize;
100*e551626fSIngo Weinhold 	error = __flatten_process_args(mutableArgs, argCount, environ, &envCount,
101*e551626fSIngo Weinhold 		mutableArgs[0], &flatArgs, &flatArgsSize);
1028df6a8dbSIngo Weinhold 
1038df6a8dbSIngo Weinhold 	// load the program
1048df6a8dbSIngo Weinhold 	thread_id thread;
1058df6a8dbSIngo Weinhold 	if (error == B_OK) {
1068df6a8dbSIngo Weinhold 		thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount,
1078df6a8dbSIngo Weinhold 			B_NORMAL_PRIORITY, (traceLoading ? 0 : B_WAIT_TILL_LOADED), -1, 0);
1088df6a8dbSIngo Weinhold 
1098df6a8dbSIngo Weinhold 		free(flatArgs);
1108df6a8dbSIngo Weinhold 	} else
1118df6a8dbSIngo Weinhold 		thread = error;
1128df6a8dbSIngo Weinhold 
1138df6a8dbSIngo Weinhold 	delete[] mutableArgs;
1148df6a8dbSIngo Weinhold 
1158df6a8dbSIngo Weinhold 	return thread;
1168df6a8dbSIngo Weinhold }
1178df6a8dbSIngo Weinhold 
1188df6a8dbSIngo Weinhold 
1198df6a8dbSIngo Weinhold // set_team_debugging_flags
1204dc355e9SRene Gollent status_t
1218df6a8dbSIngo Weinhold set_team_debugging_flags(port_id nubPort, int32 flags)
1228df6a8dbSIngo Weinhold {
1238df6a8dbSIngo Weinhold 	debug_nub_set_team_flags message;
1248df6a8dbSIngo Weinhold 	message.flags = flags;
1258df6a8dbSIngo Weinhold 
1264dc355e9SRene Gollent 	status_t error = B_OK;
1274dc355e9SRene Gollent 	do {
1284dc355e9SRene Gollent 		error = write_port(nubPort, B_DEBUG_MESSAGE_SET_TEAM_FLAGS,
1298df6a8dbSIngo Weinhold 			&message, sizeof(message));
1304dc355e9SRene Gollent 	} while (error == B_INTERRUPTED);
1318df6a8dbSIngo Weinhold 
1324dc355e9SRene Gollent 	if (error != B_OK) {
1338df6a8dbSIngo Weinhold 		fprintf(stderr, "%s: Failed to set team debug flags: %s\n",
1348df6a8dbSIngo Weinhold 			kCommandName, strerror(error));
1358df6a8dbSIngo Weinhold 	}
1364dc355e9SRene Gollent 
1374dc355e9SRene Gollent 	return error;
1388df6a8dbSIngo Weinhold }
1398df6a8dbSIngo Weinhold 
1408df6a8dbSIngo Weinhold 
1418df6a8dbSIngo Weinhold // set_thread_debugging_flags
1424dc355e9SRene Gollent status_t
1438df6a8dbSIngo Weinhold set_thread_debugging_flags(port_id nubPort, thread_id thread, int32 flags)
1448df6a8dbSIngo Weinhold {
1458df6a8dbSIngo Weinhold 	debug_nub_set_thread_flags message;
1468df6a8dbSIngo Weinhold 	message.thread = thread;
1478df6a8dbSIngo Weinhold 	message.flags = flags;
1488df6a8dbSIngo Weinhold 
1494dc355e9SRene Gollent 	status_t error = B_OK;
1504dc355e9SRene Gollent 	do {
1514dc355e9SRene Gollent 		error = write_port(nubPort, B_DEBUG_MESSAGE_SET_THREAD_FLAGS,
1528df6a8dbSIngo Weinhold 			&message, sizeof(message));
1534dc355e9SRene Gollent 	} while (error == B_INTERRUPTED);
1548df6a8dbSIngo Weinhold 
1554dc355e9SRene Gollent 	if (error != B_OK) {
1568df6a8dbSIngo Weinhold 		fprintf(stderr, "%s: Failed to set thread debug flags: %s\n",
1578df6a8dbSIngo Weinhold 			kCommandName, strerror(error));
1588df6a8dbSIngo Weinhold 	}
1594dc355e9SRene Gollent 
1604dc355e9SRene Gollent 	return error;
1618df6a8dbSIngo Weinhold }
1628df6a8dbSIngo Weinhold 
1638df6a8dbSIngo Weinhold 
1648df6a8dbSIngo Weinhold // continue_thread
1654dc355e9SRene Gollent status_t
1668df6a8dbSIngo Weinhold continue_thread(port_id nubPort, thread_id thread)
1678df6a8dbSIngo Weinhold {
1688df6a8dbSIngo Weinhold 	debug_nub_continue_thread message;
1698df6a8dbSIngo Weinhold 	message.thread = thread;
1708df6a8dbSIngo Weinhold 	message.handle_event = B_THREAD_DEBUG_HANDLE_EVENT;
1718df6a8dbSIngo Weinhold 	message.single_step = false;
1728df6a8dbSIngo Weinhold 
1734dc355e9SRene Gollent 	status_t error = B_OK;
1748df6a8dbSIngo Weinhold 
1754dc355e9SRene Gollent 	do {
1764dc355e9SRene Gollent 		error = write_port(nubPort, B_DEBUG_MESSAGE_CONTINUE_THREAD,
1774dc355e9SRene Gollent 			&message, sizeof(message));
1784dc355e9SRene Gollent 	} while (error == B_INTERRUPTED);
1794dc355e9SRene Gollent 
1804dc355e9SRene Gollent 	if (error != B_OK) {
1817483c98dSIngo Weinhold 		fprintf(stderr, "%s: Failed to run thread %" B_PRId32 ": %s\n",
1828df6a8dbSIngo Weinhold 			kCommandName, thread, strerror(error));
1838df6a8dbSIngo Weinhold 	}
1844dc355e9SRene Gollent 
1854dc355e9SRene Gollent 	return error;
1868df6a8dbSIngo Weinhold }
187