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