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 23BTeamDebugger::BTeamDebugger() 24 : 25 fDebuggerPort(-1) 26{ 27} 28 29 30BTeamDebugger::~BTeamDebugger() 31{ 32 Uninstall(); 33} 34 35 36status_t 37BTeamDebugger::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 67status_t 68BTeamDebugger::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 85status_t 86BTeamDebugger::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 105status_t 106BTeamDebugger::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 120BTeamDebugger::_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 165BTeamDebugger::_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