/** * Find line by address (nearest). * * @returns VBox status. * @param pVM VM handle. * @param Address Address. * @param poffDisplacement Where to store the line displacement from Address. * @param pLine Where to store the line info. */ VMMR3DECL(int) DBGFR3LineByAddr(PVM pVM, RTGCUINTPTR Address, PRTGCINTPTR poffDisplacement, PDBGFLINE pLine) { /* * Lazy init. */ if (!pVM->dbgf.s.fSymInited) { int rc = dbgfR3SymLazyInit(pVM); if (RT_FAILURE(rc)) return rc; } /* * Look it up. */ #ifdef HAVE_DBGHELP IMAGEHLP_LINE64 Line = {0}; DWORD off = 0; Line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); if (SymGetLineFromAddr64(pVM, Address, &off, &Line)) { if (poffDisplacement) *poffDisplacement = (long)off; pLine->Address = (RTGCUINTPTR)Line.Address; pLine->uLineNo = Line.LineNumber; pLine->szFilename[0] = '\0'; strncat(pLine->szFilename, Line.FileName, sizeof(pLine->szFilename)); return VINF_SUCCESS; } return win32Error(pVM); #else return VERR_NOT_IMPLEMENTED; #endif }
/** * Adds a symbol to the debug info manager. * * @returns VBox status. * @param pVM VM Handle. * @param ModuleAddress Module address. Use 0 if no module. * @param SymbolAddress Symbol address * @param cbSymbol Size of the symbol. Use 0 if info not available. * @param pszSymbol Symbol name. */ VMMR3DECL(int) DBGFR3SymbolAdd(PVM pVM, RTGCUINTPTR ModuleAddress, RTGCUINTPTR SymbolAddress, RTUINT cbSymbol, const char *pszSymbol) { /* * Validate. */ if (!pszSymbol || !*pszSymbol) { AssertMsgFailed(("No symbol name!\n")); return VERR_INVALID_PARAMETER; } /* * Lazy init. */ if (!pVM->dbgf.s.fSymInited) { int rc = dbgfR3SymLazyInit(pVM); if (RT_FAILURE(rc)) return rc; } #ifdef HAVE_DBGHELP if (SymAddSymbol(pVM, ModuleAddress, (char *)(void *)pszSymbol, SymbolAddress, cbSymbol, 0)) return VINF_SUCCESS; return win32Error(pVM); #else /** @todo module lookup. */ return dbgfR3SymbolInsert(pVM, pszSymbol, SymbolAddress, cbSymbol, NULL); #endif }
JNIEXPORT jint JNICALL Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle) { DWORD exit_code; if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0) win32Error(env, "GetExitCodeProcess"); return exit_code; }
/* Responsible for correct initialization of the [pHolder] structure (that is used for handles recycling) if needs, and appropriate setup of IOE handle [phStd] for child process based on created pipe or Java handle. */ static BOOL initHolder( JNIEnv *env, jlong *pjhandles, /* IN OUT - the handle form Java, that can be a file, console or undefined */ STDHOLDER *pHolder, /* OUT - initialized structure that holds pipe handles */ HANDLE *phStd /* OUT - initialized handle for child process */ ) { /* Here we test the value from Java against invalid handle value. We are not using INVALID_HANDLE_VALUE macro due to double signed/unsigned and 32/64bit ambiguity. Otherwise it will be easy to get the wrong value 0x00000000FFFFFFFF instead 0xFFFFFFFFFFFFFFFF. */ if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) { /* Java file or console redirection */ *phStd = (HANDLE) *pjhandles; /* Here we set the related Java stream (Process.getXXXXStream()) to [ProcessBuilder.NullXXXXStream.INSTANCE] value. The initial Java handle [*pjhandles] will be closed in ANY case. It is not a handle leak. */ *pjhandles = JAVA_INVALID_HANDLE_VALUE; } else { /* Creation of parent-child pipe */ if (!CreatePipe( &pHolder->pipe[OFFSET_READ], &pHolder->pipe[OFFSET_WRITE], NULL, /* we would like to inherit default process access, instead of 'Everybody' access */ PIPE_SIZE)) { win32Error(env, L"CreatePipe"); return FALSE; } else { /* [thisProcessEnd] has no the inherit flag because the [lpPipeAttributes] param of [CreatePipe] had the NULL value. */ HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)]; *phStd = pHolder->pipe[pHolder->offset]; *pjhandles = (jlong) thisProcessEnd; } } /* Pipe handle will be closed in the [releaseHolder] call, file handle will be closed in Java. The long-live handle need to restore the inherit flag, we do it later in the [prepareIOEHandleState] call. */ SetHandleInformation( *phStd, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); return TRUE; }
JNIEXPORT void JNICALL Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle) { HANDLE events[2]; events[0] = (HANDLE) handle; events[1] = JVM_GetThreadInterruptEvent(); if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events, FALSE, /* Wait for ANY event */ INFINITE) /* Wait forever */ == WAIT_FAILED) win32Error(env, "WaitForMultipleObjects"); }
/** * Find symbol by name (first). * * @returns VBox status. * @param pVM VM handle. * @param pszSymbol Symbol name. * @param pSymbol Where to store the symbol info. */ VMMR3DECL(int) DBGFR3SymbolByName(PVM pVM, const char *pszSymbol, PDBGFSYMBOL pSymbol) { /* * Lazy init. */ if (!pVM->dbgf.s.fSymInited) { int rc = dbgfR3SymLazyInit(pVM); if (RT_FAILURE(rc)) return rc; } /* * Look it up. */ #ifdef HAVE_DBGHELP char achBuffer[sizeof(IMAGEHLP_SYMBOL64) + DBGF_SYMBOL_NAME_LENGTH * sizeof(TCHAR) + sizeof(ULONG64)]; PIMAGEHLP_SYMBOL64 pSym = (PIMAGEHLP_SYMBOL64)&achBuffer[0]; pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); pSym->MaxNameLength = DBGF_SYMBOL_NAME_LENGTH; if (SymGetSymFromName64(pVM, (char *)(void *)pszSymbol, pSym)) { pSymbol->Value = (RTGCUINTPTR)pSym->Address; pSymbol->cb = pSym->Size; pSymbol->fFlags = pSym->Flags; strcpy(pSymbol->szName, pSym->Name); return VINF_SUCCESS; } return win32Error(pVM); #else PDBGFSYM pSym = dbgfR3SymbolGetName(pVM, pszSymbol); if (pSym) { pSymbol->Value = pSym->Core.Key; pSymbol->cb = pSym->Core.KeyLast - pSym->Core.Key + 1; pSymbol->fFlags = 0; pSymbol->szName[0] = '\0'; strncat(pSymbol->szName, pSym->szName, sizeof(pSymbol->szName) - 1); return VINF_SUCCESS; } return VERR_SYMBOL_NOT_FOUND; #endif }
JNIEXPORT void JNICALL Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env, jclass ignored, jlong handle, jlong timeout) { HANDLE events[2]; DWORD dwTimeout = (DWORD)timeout; DWORD result; events[0] = (HANDLE) handle; events[1] = JVM_GetThreadInterruptEvent(); result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events, FALSE, /* Wait for ANY event */ dwTimeout); /* Wait for dwTimeout */ if (result == WAIT_FAILED) win32Error(env, L"WaitForMultipleObjects"); }
/** * We delay certain * Initialize the debug info for a VM. */ int dbgfR3SymLazyInit(PVM pVM) { if (pVM->dbgf.s.fSymInited) return VINF_SUCCESS; #ifdef HAVE_DBGHELP if (SymInitialize(pVM, NULL, FALSE)) { pVM->dbgf.s.fSymInited = true; SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS); /* * Enumerate all modules loaded by PDM and add them to the symbol database. */ PDMR3LdrEnumModules(pVM, dbgfR3EnumModules, NULL); return VINF_SUCCESS; } return win32Error(pVM); #else return VINF_SUCCESS; #endif }
JNIEXPORT jlong JNICALL Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, jstring cmd, jstring envBlock, jstring dir, jlongArray stdHandles, jboolean redirectErrorStream) { HANDLE inRead = INVALID_HANDLE_VALUE; HANDLE inWrite = INVALID_HANDLE_VALUE; HANDLE outRead = INVALID_HANDLE_VALUE; HANDLE outWrite = INVALID_HANDLE_VALUE; HANDLE errRead = INVALID_HANDLE_VALUE; HANDLE errWrite = INVALID_HANDLE_VALUE; SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi; STARTUPINFO si; LPTSTR pcmd = NULL; LPCTSTR pdir = NULL; LPVOID penvBlock = NULL; jlong *handles = NULL; jlong ret = 0; OSVERSIONINFO ver; jboolean onNT = JNI_FALSE; DWORD processFlag; ver.dwOSVersionInfoSize = sizeof(ver); GetVersionEx(&ver); if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) onNT = JNI_TRUE; assert(cmd != NULL); pcmd = (LPTSTR) JNU_GetStringPlatformChars(env, cmd, NULL); if (pcmd == NULL) goto Catch; if (dir != 0) { pdir = (LPCTSTR) JNU_GetStringPlatformChars(env, dir, NULL); if (pdir == NULL) goto Catch; pdir = (LPCTSTR) JVM_NativePath((char *)pdir); } if (envBlock != NULL) { penvBlock = onNT ? (LPVOID) ((*env)->GetStringChars(env, envBlock, NULL)) : (LPVOID) JNU_GetStringPlatformChars(env, envBlock, NULL); if (penvBlock == NULL) goto Catch; } assert(stdHandles != NULL); handles = (*env)->GetLongArrayElements(env, stdHandles, NULL); if (handles == NULL) goto Catch; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = 0; sa.bInheritHandle = TRUE; if (handles[0] != (jlong) -1) { si.hStdInput = (HANDLE) handles[0]; handles[0] = (jlong) -1; } else { if (! CreatePipe(&inRead, &inWrite, &sa, PIPE_SIZE)) { win32Error(env, "CreatePipe"); goto Catch; } si.hStdInput = inRead; SetHandleInformation(inWrite, HANDLE_FLAG_INHERIT, FALSE); handles[0] = (jlong) inWrite; } SetHandleInformation(si.hStdInput, HANDLE_FLAG_INHERIT, TRUE); if (handles[1] != (jlong) -1) { si.hStdOutput = (HANDLE) handles[1]; handles[1] = (jlong) -1; } else { if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) { win32Error(env, "CreatePipe"); goto Catch; } si.hStdOutput = outWrite; SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, FALSE); handles[1] = (jlong) outRead; } SetHandleInformation(si.hStdOutput, HANDLE_FLAG_INHERIT, TRUE); if (redirectErrorStream) { si.hStdError = si.hStdOutput; handles[2] = (jlong) -1; } else if (handles[2] != (jlong) -1) { si.hStdError = (HANDLE) handles[2]; handles[2] = (jlong) -1; } else { if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) { win32Error(env, "CreatePipe"); goto Catch; } si.hStdError = errWrite; SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, FALSE); handles[2] = (jlong) errRead; } SetHandleInformation(si.hStdError, HANDLE_FLAG_INHERIT, TRUE); if (onNT) processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; else processFlag = selectProcessFlag(env, cmd); /* Java and Windows are both pure Unicode systems at heart. * Windows has both a legacy byte-based API and a 16-bit Unicode * "W" API. The Right Thing here is to call CreateProcessW, since * that will allow all process-related information like command * line arguments to be passed properly to the child. We don't do * that currently, since we would first have to have "W" versions * of JVM_NativePath and perhaps other functions. In the * meantime, we can call CreateProcess with the magic flag * CREATE_UNICODE_ENVIRONMENT, which passes only the environment * in "W" mode. We will fix this later. */ ret = CreateProcess(0, /* executable name */ pcmd, /* command line */ 0, /* process security attribute */ 0, /* thread security attribute */ TRUE, /* inherits system handles */ processFlag, /* selected based on exe type */ penvBlock, /* environment block */ pdir, /* change to the new current directory */ &si, /* (in) startup information */ &pi); /* (out) process information */ if (!ret) { win32Error(env, "CreateProcess"); goto Catch; } CloseHandle(pi.hThread); ret = (jlong)pi.hProcess; Finally: /* Always clean up the child's side of the pipes */ closeSafely(inRead); closeSafely(outWrite); closeSafely(errWrite); if (pcmd != NULL) JNU_ReleaseStringPlatformChars(env, cmd, (char *) pcmd); if (pdir != NULL) JNU_ReleaseStringPlatformChars(env, dir, (char *) pdir); if (penvBlock != NULL) { if (onNT) (*env)->ReleaseStringChars(env, envBlock, (jchar *) penvBlock); else JNU_ReleaseStringPlatformChars(env, dir, (char *) penvBlock); } if (handles != NULL) (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0); return ret; Catch: /* Clean up the parent's side of the pipes in case of failure only */ closeSafely(inWrite); closeSafely(outRead); closeSafely(errRead); goto Finally; }
/* Please, read about the MS inheritance problem http://support.microsoft.com/kb/315939 and critical section/synchronized block solution. */ static jlong processCreate( JNIEnv *env, const jchar *pcmd, const jchar *penvBlock, const jchar *pdir, jlong *handles, jboolean redirectErrorStream) { jlong ret = 0L; STARTUPINFOW si = {sizeof(si)}; /* Handles for which the inheritance flag must be restored. */ HANDLE stdIOE[HANDLE_STORAGE_SIZE] = { /* Current process standard IOE handles: JDK-7147084 */ INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, /* Child process IOE handles: JDK-6921885 */ (HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]}; BOOL inherit[HANDLE_STORAGE_SIZE] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}; { /* Extraction of current process standard IOE handles */ DWORD idsIOE[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE}; int i; for (i = 0; i < 3; ++i) /* Should not be closed by CloseHandle! */ stdIOE[i] = GetStdHandle(idsIOE[i]); } prepareIOEHandleState(stdIOE, inherit); { /* Input */ STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ}; if (initHolder(env, &handles[0], &holderIn, &si.hStdInput)) { /* Output */ STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE}; if (initHolder(env, &handles[1], &holderOut, &si.hStdOutput)) { /* Error */ STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE}; BOOL success; if (redirectErrorStream) { si.hStdError = si.hStdOutput; /* Here we set the error stream to [ProcessBuilder.NullInputStream.INSTANCE] value. That is in accordance with Java Doc for the redirection case. The Java file for the [ handles[2] ] will be closed in ANY case. It is not a handle leak. */ handles[2] = JAVA_INVALID_HANDLE_VALUE; success = TRUE; } else { success = initHolder(env, &handles[2], &holderErr, &si.hStdError); } if (success) { PROCESS_INFORMATION pi; DWORD processFlag = CREATE_UNICODE_ENVIRONMENT; /* Suppress popping-up of a console window for non-console applications */ if (GetConsoleWindow() == NULL) processFlag |= CREATE_NO_WINDOW; si.dwFlags = STARTF_USESTDHANDLES; if (!CreateProcessW( NULL, /* executable name */ (LPWSTR)pcmd, /* command line */ NULL, /* process security attribute */ NULL, /* thread security attribute */ TRUE, /* inherits system handles */ processFlag, /* selected based on exe type */ (LPVOID)penvBlock,/* environment block */ (LPCWSTR)pdir, /* change to the new current directory */ &si, /* (in) startup information */ &pi)) /* (out) process information */ { win32Error(env, L"CreateProcess"); } else { closeSafely(pi.hThread); ret = (jlong)pi.hProcess; } } releaseHolder(ret == 0, &holderErr); releaseHolder(ret == 0, &holderOut); } releaseHolder(ret == 0, &holderIn); } } restoreIOEHandleState(stdIOE, inherit); return ret; }
/** * Load debug info, optionally related to a specific module. * * @returns VBox status. * @param pVM VM Handle. * @param pszFilename Path to the file containing the symbol information. * This can be the executable image, a flat symbol file of some kind or stripped debug info. * @param AddressDelta The value to add to the loaded symbols. * @param pszName Short hand name for the module. If not related to a module specify NULL. * @param ModuleAddress Address which the image is loaded at. This will be used to reference the module other places in the api. * Ignored when pszName is NULL. * @param cbImage Size of the image. * Ignored when pszName is NULL. */ VMMR3DECL(int) DBGFR3ModuleLoad(PVM pVM, const char *pszFilename, RTGCUINTPTR AddressDelta, const char *pszName, RTGCUINTPTR ModuleAddress, unsigned cbImage) { /* * Lazy init. */ if (!pVM->dbgf.s.fSymInited) { int rc = dbgfR3SymLazyInit(pVM); if (RT_FAILURE(rc)) return rc; } /* * Open the load file. */ FILE *pFile = NULL; char szFoundFile[RTPATH_MAX]; int rc = dbgfR3ModuleLocateAndOpen(pVM, pszFilename, szFoundFile, sizeof(szFoundFile), &pFile); if (pFile) { /* * Probe the file type. */ SYMFILETYPE enmType = dbgfR3ModuleProbe(pFile); if (enmType != SYMFILETYPE_UNKNOWN) { /* * Add the module. */ if (pszName) { #ifdef HAVE_DBGHELP /** @todo arg! checkout the inserting of modules and then loading them again.... Or just the module representation.... */ DWORD64 ImageBase = SymLoadModule64(pVM, NULL, (char *)(void *)szFoundFile, (char *)(void *)pszName, ModuleAddress, cbImage); if (!ImageBase) ImageBase = SymLoadModule64(pVM, NULL, (char *)(void *)pszName, (char *)(void *)pszName, ModuleAddress, cbImage); if (ImageBase) { AssertMsg(ModuleAddress == 0 || ModuleAddress == ImageBase, ("ModuleAddres=%RGv ImageBase=%llx\n", ModuleAddress, ImageBase)); ModuleAddress = ImageBase; } else rc = win32Error(pVM); #else rc = VERR_NOT_IMPLEMENTED; #endif } if (RT_SUCCESS(rc)) { /* * Seek to the start of the file. */ rc = fseek(pFile, 0, SEEK_SET); Assert(!rc); /* * Process the specific. */ switch (enmType) { case SYMFILETYPE_LINUX_SYSTEM_MAP: rc = dbgfR3LoadLinuxSystemMap(pVM, pFile, ModuleAddress, AddressDelta); break; case SYMFILETYPE_PDB: case SYMFILETYPE_DBG: case SYMFILETYPE_MZ: #ifdef HAVE_DBGHELP /* done it all above! */ break; #endif case SYMFILETYPE_LD_MAP: case SYMFILETYPE_MS_MAP: case SYMFILETYPE_OBJDUMP: case SYMFILETYPE_ELF: rc = VERR_NOT_SUPPORTED; break; default: AssertFailed(); rc = VERR_INTERNAL_ERROR; break; } /* file switch. */ } /* module added successfully. */ } /* format identified */ else rc = VERR_NOT_SUPPORTED; /** @todo check for read errors */ fclose(pFile); } return rc; }