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