1 /* 2 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <TeamDebugger.h> 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <sys/stat.h> 12 13 #include <string.h> 14 15 #include <Path.h> 16 #include <String.h> 17 18 #include <libroot_private.h> 19 #include <syscalls.h> 20 #include <syscall_load_image.h> 21 22 23 BTeamDebugger::BTeamDebugger() 24 : 25 fDebuggerPort(-1) 26 { 27 } 28 29 30 BTeamDebugger::~BTeamDebugger() 31 { 32 Uninstall(); 33 } 34 35 36 status_t 37 BTeamDebugger::Install(team_id team) 38 { 39 Uninstall(); 40 41 // create a debugger port 42 char name[B_OS_NAME_LENGTH]; 43 snprintf(name, sizeof(name), "debugger for team %" B_PRId32, team); 44 fDebuggerPort = create_port(100, name); 45 if (fDebuggerPort < 0) 46 return fDebuggerPort; 47 48 port_id nubPort = install_team_debugger(team, fDebuggerPort); 49 if (nubPort < 0) { 50 delete_port(fDebuggerPort); 51 fDebuggerPort = -1; 52 return nubPort; 53 } 54 55 status_t error = BDebugContext::Init(team, nubPort); 56 if (error != B_OK) { 57 remove_team_debugger(team); 58 delete_port(fDebuggerPort); 59 fDebuggerPort = -1; 60 return error; 61 } 62 63 return B_OK; 64 } 65 66 67 status_t 68 BTeamDebugger::Uninstall() 69 { 70 if (Team() < 0) 71 return B_BAD_VALUE; 72 73 remove_team_debugger(Team()); 74 75 delete_port(fDebuggerPort); 76 77 BDebugContext::Uninit(); 78 79 fDebuggerPort = -1; 80 81 return B_OK; 82 } 83 84 85 status_t 86 BTeamDebugger::LoadProgram(const char* const* args, int32 argCount, 87 bool traceLoading) 88 { 89 // load the program 90 thread_id thread = _LoadProgram(args, argCount, traceLoading); 91 if (thread < 0) 92 return thread; 93 94 // install the debugger 95 status_t error = Install(thread); 96 if (error != B_OK) { 97 kill_team(thread); 98 return error; 99 } 100 101 return B_OK; 102 } 103 104 105 status_t 106 BTeamDebugger::ReadDebugMessage(int32& _messageCode, 107 debug_debugger_message_data& messageBuffer) 108 { 109 ssize_t bytesRead = read_port(fDebuggerPort, &_messageCode, &messageBuffer, 110 sizeof(messageBuffer)); 111 if (bytesRead < 0) 112 return bytesRead; 113 114 return B_OK; 115 } 116 117 118 119 /*static*/ thread_id 120 BTeamDebugger::_LoadProgram(const char* const* args, int32 argCount, 121 bool traceLoading) 122 { 123 // clone the argument vector so that we can change it 124 const char** mutableArgs = new const char*[argCount]; 125 for (int i = 0; i < argCount; i++) 126 mutableArgs[i] = args[i]; 127 128 // resolve the program path 129 BPath programPath; 130 status_t error = _FindProgram(args[0], programPath); 131 if (error != B_OK) { 132 delete[] mutableArgs; 133 return error; 134 } 135 mutableArgs[0] = programPath.Path(); 136 137 // count environment variables 138 int32 envCount = 0; 139 while (environ[envCount] != NULL) 140 envCount++; 141 142 // flatten the program args and environment 143 char** flatArgs = NULL; 144 size_t flatArgsSize; 145 error = __flatten_process_args(mutableArgs, argCount, environ, &envCount, 146 mutableArgs[0], &flatArgs, &flatArgsSize); 147 148 // load the program 149 thread_id thread; 150 if (error == B_OK) { 151 thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount, 152 B_NORMAL_PRIORITY, (traceLoading ? 0 : B_WAIT_TILL_LOADED), -1, 0); 153 154 free(flatArgs); 155 } else 156 thread = error; 157 158 delete[] mutableArgs; 159 160 return thread; 161 } 162 163 164 /*static*/ status_t 165 BTeamDebugger::_FindProgram(const char* programName, BPath& resolvedPath) 166 { 167 // If the program name is absolute, then there's nothing to do. 168 // If the program name consists of more than one path element, then we 169 // consider it a relative path and don't search in PATH either. 170 if (*programName == '/' || strchr(programName, '/')) 171 return resolvedPath.SetTo(programName); 172 173 // get the PATH environment variable 174 const char* paths = getenv("PATH"); 175 if (!paths) 176 return B_ENTRY_NOT_FOUND; 177 178 // iterate through the paths 179 do { 180 const char* pathEnd = strchr(paths, ':'); 181 int pathLen = (pathEnd ? pathEnd - paths : strlen(paths)); 182 183 // We skip empty paths. 184 if (pathLen > 0) { 185 // get the program path 186 BString directory(paths, pathLen); 187 if (directory.Length() == 0) 188 return B_NO_MEMORY; 189 190 BPath path; 191 status_t error = path.SetTo(directory, programName); 192 if (error != B_OK) 193 continue; 194 195 // stat() the path to be sure, there is a file 196 struct stat st; 197 if (stat(path.Path(), &st) == 0 && S_ISREG(st.st_mode)) { 198 resolvedPath = path; 199 return B_OK; 200 } 201 } 202 203 paths = (pathEnd ? pathEnd + 1 : NULL); 204 } while (paths); 205 206 // not found in PATH 207 return B_ENTRY_NOT_FOUND; 208 } 209