xref: /haiku/src/bin/debug/debug_utils.cpp (revision 475172337b217fc506feeec8d9fd8258c2d7c97c)
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>
20*47517233SAugustin Cavalier #include <syscall_load_image.h>
218df6a8dbSIngo Weinhold 
228df6a8dbSIngo Weinhold 
238df6a8dbSIngo Weinhold extern const char* __progname;
248df6a8dbSIngo Weinhold static const char* kCommandName = __progname;
258df6a8dbSIngo Weinhold 
268df6a8dbSIngo Weinhold 
278df6a8dbSIngo Weinhold // find_program
288df6a8dbSIngo Weinhold static status_t
find_program(const char * programName,std::string & resolvedPath)298df6a8dbSIngo Weinhold find_program(const char* programName, std::string& resolvedPath)
308df6a8dbSIngo Weinhold {
318df6a8dbSIngo Weinhold     // If the program name is absolute, then there's nothing to do.
328df6a8dbSIngo Weinhold     // If the program name consists of more than one path element, then we
338df6a8dbSIngo Weinhold     // consider it a relative path and don't search in PATH either.
348df6a8dbSIngo Weinhold     if (*programName == '/' || strchr(programName, '/')) {
358df6a8dbSIngo Weinhold         resolvedPath = programName;
368df6a8dbSIngo Weinhold         return B_OK;
378df6a8dbSIngo Weinhold     }
388df6a8dbSIngo Weinhold 
398df6a8dbSIngo Weinhold     // get the PATH environment variable
408df6a8dbSIngo Weinhold     const char* paths = getenv("PATH");
418df6a8dbSIngo Weinhold     if (!paths)
428df6a8dbSIngo Weinhold         return B_ENTRY_NOT_FOUND;
438df6a8dbSIngo Weinhold 
448df6a8dbSIngo Weinhold     // iterate through the paths
458df6a8dbSIngo Weinhold     do {
468df6a8dbSIngo Weinhold         const char* pathEnd = strchr(paths, ':');
478df6a8dbSIngo Weinhold         int pathLen = (pathEnd ? pathEnd - paths : strlen(paths));
488df6a8dbSIngo Weinhold 
498df6a8dbSIngo Weinhold         // We skip empty paths.
508df6a8dbSIngo Weinhold         if (pathLen > 0) {
518df6a8dbSIngo Weinhold             // get the program path
528df6a8dbSIngo Weinhold             std::string path(paths, pathLen);
538df6a8dbSIngo Weinhold             path += "/";
548df6a8dbSIngo Weinhold             path += programName;
558df6a8dbSIngo Weinhold 
568df6a8dbSIngo Weinhold             // stat() the path to be sure, there is a file
578df6a8dbSIngo Weinhold             struct stat st;
588df6a8dbSIngo Weinhold             if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
598df6a8dbSIngo Weinhold             	resolvedPath = path;
608df6a8dbSIngo Weinhold                 return B_OK;
618df6a8dbSIngo Weinhold             }
628df6a8dbSIngo Weinhold         }
638df6a8dbSIngo Weinhold 
648df6a8dbSIngo Weinhold         paths = (pathEnd ? pathEnd + 1 : NULL);
658df6a8dbSIngo Weinhold     } while (paths);
668df6a8dbSIngo Weinhold 
678df6a8dbSIngo Weinhold     // not found in PATH
688df6a8dbSIngo Weinhold     return B_ENTRY_NOT_FOUND;
698df6a8dbSIngo Weinhold }
708df6a8dbSIngo Weinhold 
718df6a8dbSIngo Weinhold 
728df6a8dbSIngo Weinhold // #pragma mark -
738df6a8dbSIngo Weinhold 
748df6a8dbSIngo Weinhold 
758df6a8dbSIngo Weinhold // load_program
768df6a8dbSIngo Weinhold thread_id
load_program(const char * const * args,int32 argCount,bool traceLoading)778df6a8dbSIngo Weinhold load_program(const char* const* args, int32 argCount, bool traceLoading)
788df6a8dbSIngo Weinhold {
798df6a8dbSIngo Weinhold 	// clone the argument vector so that we can change it
808df6a8dbSIngo Weinhold 	const char** mutableArgs = new const char*[argCount];
818df6a8dbSIngo Weinhold 	for (int i = 0; i < argCount; i++)
828df6a8dbSIngo Weinhold 		mutableArgs[i] = args[i];
838df6a8dbSIngo Weinhold 
848df6a8dbSIngo Weinhold 	// resolve the program path
858df6a8dbSIngo Weinhold 	std::string programPath;
868df6a8dbSIngo Weinhold 	status_t error = find_program(args[0], programPath);
878df6a8dbSIngo Weinhold 	if (error != B_OK) {
888df6a8dbSIngo Weinhold 		delete[] mutableArgs;
898df6a8dbSIngo Weinhold 		return error;
908df6a8dbSIngo Weinhold 	}
918df6a8dbSIngo Weinhold 	mutableArgs[0] = programPath.c_str();
928df6a8dbSIngo Weinhold 
938df6a8dbSIngo Weinhold 	// count environment variables
94e551626fSIngo Weinhold 	int32 envCount = 0;
958df6a8dbSIngo Weinhold 	while (environ[envCount] != NULL)
968df6a8dbSIngo Weinhold 		envCount++;
978df6a8dbSIngo Weinhold 
988df6a8dbSIngo Weinhold 	// flatten the program args and environment
998df6a8dbSIngo Weinhold 	char** flatArgs = NULL;
1008df6a8dbSIngo Weinhold 	size_t flatArgsSize;
101e551626fSIngo Weinhold 	error = __flatten_process_args(mutableArgs, argCount, environ, &envCount,
102e551626fSIngo Weinhold 		mutableArgs[0], &flatArgs, &flatArgsSize);
1038df6a8dbSIngo Weinhold 
1048df6a8dbSIngo Weinhold 	// load the program
1058df6a8dbSIngo Weinhold 	thread_id thread;
1068df6a8dbSIngo Weinhold 	if (error == B_OK) {
1078df6a8dbSIngo Weinhold 		thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount,
1088df6a8dbSIngo Weinhold 			B_NORMAL_PRIORITY, (traceLoading ? 0 : B_WAIT_TILL_LOADED), -1, 0);
1098df6a8dbSIngo Weinhold 
1108df6a8dbSIngo Weinhold 		free(flatArgs);
1118df6a8dbSIngo Weinhold 	} else
1128df6a8dbSIngo Weinhold 		thread = error;
1138df6a8dbSIngo Weinhold 
1148df6a8dbSIngo Weinhold 	delete[] mutableArgs;
1158df6a8dbSIngo Weinhold 
1168df6a8dbSIngo Weinhold 	return thread;
1178df6a8dbSIngo Weinhold }
1188df6a8dbSIngo Weinhold 
1198df6a8dbSIngo Weinhold 
1208df6a8dbSIngo Weinhold // set_team_debugging_flags
1214dc355e9SRene Gollent status_t
set_team_debugging_flags(port_id nubPort,int32 flags)1228df6a8dbSIngo Weinhold set_team_debugging_flags(port_id nubPort, int32 flags)
1238df6a8dbSIngo Weinhold {
1248df6a8dbSIngo Weinhold 	debug_nub_set_team_flags message;
1258df6a8dbSIngo Weinhold 	message.flags = flags;
1268df6a8dbSIngo Weinhold 
1274dc355e9SRene Gollent 	status_t error = B_OK;
1284dc355e9SRene Gollent 	do {
1294dc355e9SRene Gollent 		error = write_port(nubPort, B_DEBUG_MESSAGE_SET_TEAM_FLAGS,
1308df6a8dbSIngo Weinhold 			&message, sizeof(message));
1314dc355e9SRene Gollent 	} while (error == B_INTERRUPTED);
1328df6a8dbSIngo Weinhold 
1334dc355e9SRene Gollent 	if (error != B_OK) {
1348df6a8dbSIngo Weinhold 		fprintf(stderr, "%s: Failed to set team debug flags: %s\n",
1358df6a8dbSIngo Weinhold 			kCommandName, strerror(error));
1368df6a8dbSIngo Weinhold 	}
1374dc355e9SRene Gollent 
1384dc355e9SRene Gollent 	return error;
1398df6a8dbSIngo Weinhold }
1408df6a8dbSIngo Weinhold 
1418df6a8dbSIngo Weinhold 
1428df6a8dbSIngo Weinhold // set_thread_debugging_flags
1434dc355e9SRene Gollent status_t
set_thread_debugging_flags(port_id nubPort,thread_id thread,int32 flags)1448df6a8dbSIngo Weinhold set_thread_debugging_flags(port_id nubPort, thread_id thread, int32 flags)
1458df6a8dbSIngo Weinhold {
1468df6a8dbSIngo Weinhold 	debug_nub_set_thread_flags message;
1478df6a8dbSIngo Weinhold 	message.thread = thread;
1488df6a8dbSIngo Weinhold 	message.flags = flags;
1498df6a8dbSIngo Weinhold 
1504dc355e9SRene Gollent 	status_t error = B_OK;
1514dc355e9SRene Gollent 	do {
1524dc355e9SRene Gollent 		error = write_port(nubPort, B_DEBUG_MESSAGE_SET_THREAD_FLAGS,
1538df6a8dbSIngo Weinhold 			&message, sizeof(message));
1544dc355e9SRene Gollent 	} while (error == B_INTERRUPTED);
1558df6a8dbSIngo Weinhold 
1564dc355e9SRene Gollent 	if (error != B_OK) {
1578df6a8dbSIngo Weinhold 		fprintf(stderr, "%s: Failed to set thread debug flags: %s\n",
1588df6a8dbSIngo Weinhold 			kCommandName, strerror(error));
1598df6a8dbSIngo Weinhold 	}
1604dc355e9SRene Gollent 
1614dc355e9SRene Gollent 	return error;
1628df6a8dbSIngo Weinhold }
1638df6a8dbSIngo Weinhold 
1648df6a8dbSIngo Weinhold 
1658df6a8dbSIngo Weinhold // continue_thread
1664dc355e9SRene Gollent status_t
continue_thread(port_id nubPort,thread_id thread)1678df6a8dbSIngo Weinhold continue_thread(port_id nubPort, thread_id thread)
1688df6a8dbSIngo Weinhold {
1698df6a8dbSIngo Weinhold 	debug_nub_continue_thread message;
1708df6a8dbSIngo Weinhold 	message.thread = thread;
1718df6a8dbSIngo Weinhold 	message.handle_event = B_THREAD_DEBUG_HANDLE_EVENT;
1728df6a8dbSIngo Weinhold 	message.single_step = false;
1738df6a8dbSIngo Weinhold 
1744dc355e9SRene Gollent 	status_t error = B_OK;
1758df6a8dbSIngo Weinhold 
1764dc355e9SRene Gollent 	do {
1774dc355e9SRene Gollent 		error = write_port(nubPort, B_DEBUG_MESSAGE_CONTINUE_THREAD,
1784dc355e9SRene Gollent 			&message, sizeof(message));
1794dc355e9SRene Gollent 	} while (error == B_INTERRUPTED);
1804dc355e9SRene Gollent 
1814dc355e9SRene Gollent 	if (error != B_OK) {
1827483c98dSIngo Weinhold 		fprintf(stderr, "%s: Failed to run thread %" B_PRId32 ": %s\n",
1838df6a8dbSIngo Weinhold 			kCommandName, thread, strerror(error));
1848df6a8dbSIngo Weinhold 	}
1854dc355e9SRene Gollent 
1864dc355e9SRene Gollent 	return error;
1878df6a8dbSIngo Weinhold }
188