Dateien
rocm-systems/source/lib/rocprof-sys-rt/src/RTwinnt.c
T
David Galiffi d07bf508a9 Rename Omnitrace to ROCm Systems Profiler (#4)
The Omnitrace program is being renamed. 

Full name: "ROCm Systems Profiler"
Package name: "rocprofiler-systems"
Binary / Library names: "rocprof-sys-*"

---------
Co-authored-by: Xuan Chen <xuchen@amd.com>
Signed-off-by: David Galiffi <David.Galiffi@amd.com>
2024-10-15 11:20:40 -04:00

566 Zeilen
18 KiB
C

/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/************************************************************************
* $Id: RTwinnt.c,v 1.22 2006/06/09 03:50:49 jodom Exp $
* RTwinnt.c: runtime instrumentation functions for Windows NT
************************************************************************/
#include "RTcommon.h"
#include "h/dyninstAPI_RT.h"
#include <Dbghelp.h>
#include <Psapi.h>
#include <WS2tcpip.h>
#include <WinSock2.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <limits.h>
#include <mmsystem.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <windows.h>
extern unsigned long dyninstTrapTableUsed;
extern unsigned long dyninstTrapTableVersion;
extern trapMapping_t* dyninstTrapTable;
extern unsigned long dyninstTrapTableIsSorted;
extern void
DYNINSTBaseInit();
extern double DYNINSTstaticHeap_512K_lowmemHeap_1[];
extern double DYNINSTstaticHeap_16M_anyHeap_1[];
extern unsigned long sizeOfLowMemHeap1;
extern unsigned long sizeOfAnyHeap1;
/************************************************************************
* void DYNINSTbreakPoint(void)
*
* stop oneself.
************************************************************************/
void
DYNINSTbreakPoint(void)
{
/* TODO: how do we stop all threads? */
DYNINST_break_point_event = 1;
DebugBreak();
DYNINST_break_point_event = 0;
}
void
DYNINSTsafeBreakPoint()
{
DYNINSTbreakPoint();
}
static dyntid_t initial_thread_tid;
/* this function is automatically called when windows loads this dll
if we are launching a mutatee to instrument, dyninst will place
the correct values in libdyninstAPI_RT_DLL_localPid and
libdyninstAPI_RT_DLL_localCause and they will be passed to
DYNINSTinit to correctly initialize the dll. this keeps us
from having to instrument two steps from the mutator (load and then
the execution of DYNINSTinit()
*/
BOOL WINAPI
DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
static int DllMainCalledOnce = 0;
// fprintf(stderr,"RTLIB: In DllMain staticmode=%d %s[%d]\n", DYNINSTstaticMode,
// __FILE__,__LINE__);
if(DllMainCalledOnce) return 1;
DllMainCalledOnce++;
DYNINSTinit();
#if defined(cap_mutatee_traps)
if(DYNINSTstaticMode)
{
DYNINSTinitializeTrapHandler();
}
#endif
return 1;
}
char gLoadLibraryErrorString[ERROR_STRING_LENGTH];
int
DYNINSTloadLibrary(char* libname)
{
HMODULE res;
gLoadLibraryErrorString[0] = '\0';
res = LoadLibrary(libname);
if(res == NULL)
{
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), gLoadLibraryErrorString,
ERROR_STRING_LENGTH, NULL);
return 0;
}
return 1;
}
/************************************************************************
* void DYNINSTasyncConnect()
*
* Connect to mutator's async handler thread. <pid> is pid of mutator
************************************************************************/
// CRITICAL_SECTION comms_mutex;
int async_socket = -1;
int connect_port = 0;
int
DYNINSTasyncConnect(int mutatorpid)
{
int sock_fd;
struct sockaddr_in sadr;
struct in_addr* inadr;
struct addrinfo* result = NULL;
WORD wsversion = MAKEWORD(2, 0);
WSADATA wsadata;
rtBPatch_asyncEventRecord ev;
if(async_socket != -1)
{
/*fprintf(stderr, "%s[%d]: already connected\n", __FILE__, __LINE__);*/
return 0;
}
RTprintf("%s[%d]: inside DYNINSTasyncConnect\n", __FILE__, __LINE__);
if(0 == connect_port)
{
fprintf(stderr, "%s[%d]: DYNINSTasyncConnect, no port\n", __FILE__, __LINE__);
}
WSAStartup(wsversion, &wsadata);
RTprintf("%s[%d]: DYNINSTasyncConnect before gethostbyname\n", __FILE__, __LINE__);
getaddrinfo("localhost", NULL, NULL, &result);
inadr = (struct in_addr*) result->ai_addr;
RTprintf("%s[%d]: inside DYNINSTasyncConnect before memset\n", __FILE__, __LINE__);
memset((void*) &sadr, 0, sizeof(sadr));
sadr.sin_family = PF_INET;
sadr.sin_port = htons((u_short) connect_port);
sadr.sin_addr = *inadr;
RTprintf("%s[%d]: DYNINSTasyncConnect before socket\n", __FILE__, __LINE__);
sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if(sock_fd == INVALID_SOCKET)
{
fprintf(stderr, "DYNINST: socket failed: %d\n", WSAGetLastError());
}
RTprintf("%s[%d]: DYNINSTasyncConnect before connect\n", __FILE__, __LINE__);
if(connect(sock_fd, (struct sockaddr*) &sadr, sizeof(sadr)) == SOCKET_ERROR)
{
fprintf(stderr, "DYNINSTasyncConnect: connect failed: %d\n", WSAGetLastError());
}
/* maybe need to do fcntl to set nonblocking writes on this fd */
async_socket = sock_fd;
RTprintf("%s[%d]: DYNINSTasyncConnect before write\n", __FILE__, __LINE__);
/* after connecting, we need to send along our pid */
ev.type = rtBPatch_newConnectionEvent;
ev.pid = _getpid();
if(!DYNINSTwriteEvent((void*) &ev, sizeof(rtBPatch_asyncEventRecord)))
{
fprintf(stderr, "%s[%d]: DYNINSTwriteEventFailed\n", __FILE__, __LINE__);
}
/* initialize comms mutex */
// InitializeCriticalSection(&comms_mutex);
// fprintf(stderr, "%s[%d]: DYNINSTasyncConnect appears to have succeeded\n",
// __FILE__, __LINE__);
RTprintf("%s[%d]: leaving DYNINSTasyncConnect\n", __FILE__, __LINE__);
freeaddrinfo(result);
return 1; /*true*/
}
int
DYNINSTasyncDisconnect()
{
WSACleanup();
return _close(async_socket);
}
void
printSysError(unsigned errNo)
{
char buf[1000];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errNo,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 1000, NULL);
fprintf(stderr, "*** System error [%d]: %s\n", errNo, buf);
fflush(stderr);
}
int
DYNINSTwriteEvent(void* ev, size_t sz)
{
DYNINSTasyncConnect(DYNINST_mutatorPid);
if(send((SOCKET) async_socket, ev, sz, 0) != sz)
{
printSysError(WSAGetLastError());
printf("DYNINSTwriteTrace: send error %d, %d %d\n", WSAGetLastError(), sz,
async_socket);
if(async_socket == -1) return 1;
return 0;
}
return 1;
}
int
dyn_pid_self()
{
return _getpid();
}
int
dyn_lwp_self()
{
#ifdef _WIN64
return GetCurrentThreadId();
#else
/* return GetCurrentThreadId(); */
/* getCurrentThreadId() is conflicting with SD-Dyninst instrumentation.
* So I'm doing the massively unportable thing here and hard-coding the assembly
* FOR GREAT JUSTICE!
*/
/* This will do stack frame setup, but that seems harmless in this context... */
__asm {
mov EAX,FS:[0x18]
mov EAX,DS:[EAX+0x24]
}
#endif
}
dyntid_t
dyn_pthread_self()
{
return (dyntid_t) dyn_lwp_self();
}
int
DYNINSTthreadInfo(BPatch_newThreadEventRecord* ev)
{
return 1;
}
/*
We reserve index 0 for the initial thread. This value varies by
platform but is always constant for that platform. Wrap that
platform-ness here.
*/
int
DYNINST_am_initial_thread(dyntid_t tid)
{
return (tid == initial_thread_tid);
}
// Check that the address is backed by a file,
// get the binary's load address,
// get the PE header, assuming there is one,
// see if the last section has been tagged with "DYNINST_REWRITE"
// get trap-table header from last binary section's end - label - size
// sets allocBase to the binary's load address
static struct trap_mapping_header*
getStaticTrapMap(unsigned long addr, unsigned long* allocBase)
{
struct trap_mapping_header* header = NULL;
char fileName[ERROR_STRING_LENGTH];
DWORD actualNameLen = 0;
MEMORY_BASIC_INFORMATION memInfo;
int numSections = 0;
PIMAGE_NT_HEADERS peHdr = NULL;
IMAGE_SECTION_HEADER curSecn;
int sidx = 0;
char* str = NULL;
// check that the address is backed by a file
actualNameLen = GetMappedFileName(GetCurrentProcess(), (LPVOID) addr, fileName,
ERROR_STRING_LENGTH);
if(!actualNameLen)
{
fileName[0] = '\0';
goto done; // no file mapped at trap address
}
fileName[ERROR_STRING_LENGTH - 1] = '\0';
// get the binary's load address, size
if(!VirtualQuery((LPCVOID) addr, &memInfo, sizeof(memInfo)) ||
MEM_COMMIT != memInfo.State)
{
fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__, __LINE__);
goto done; // shouldn't be possible given previous query, but hey
}
*allocBase = (unsigned long) memInfo.AllocationBase;
rtdebug_printf("RTLIB: getStaticTrapMap addr=%lx meminfo.BaseAddress=%lx "
"meminfo.AllocationBase = %lx, memInfo.RegionSize = %lx, "
"%s[%d]\n",
addr, memInfo.BaseAddress, memInfo.AllocationBase, memInfo.RegionSize,
__FILE__, __LINE__);
// get the PE header, assuming there is one
peHdr = ImageNtHeader(memInfo.AllocationBase);
if(!peHdr)
{
fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__, __LINE__);
goto done; // no pe header
}
// see if the last section has been tagged with "DYNINST_REWRITE"
numSections = peHdr->FileHeader.NumberOfSections;
curSecn = *(PIMAGE_SECTION_HEADER)(((unsigned char*) peHdr) + sizeof(DWORD) +
sizeof(IMAGE_FILE_HEADER) +
peHdr->FileHeader.SizeOfOptionalHeader +
sizeof(IMAGE_SECTION_HEADER) * (numSections - 1));
// fprintf(stderr, "RTLIB: PE section header address = %lx\n", curSecn);
// fprintf(stderr, "curSecn.chars = %lx %s[%d]\n",curSecn.Characteristics,
// __FILE__,__LINE__);
if((sizeof(void*) + 16) > curSecn.SizeOfRawData)
{
fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__, __LINE__);
goto done; // last section is uninitialized, doesn't have trap table
}
// fprintf(stderr, "RTLIB %s[%d]\n", __FILE__,__LINE__);
// fprintf(stderr, "RTLIB mi.ab =%lx cs.va =%lx cs.srd=%lx %s[%d]\n",
// memInfo.AllocationBase, curSecn.VirtualAddress, curSecn.SizeOfRawData,
// __FILE__,__LINE__);
str = (char*) ((long) memInfo.AllocationBase + curSecn.VirtualAddress +
curSecn.SizeOfRawData - 16);
if(0 != strncmp("DYNINST_REWRITE", str, 15))
{
fprintf(stderr,
"ERROR IN RTLIB: getStaticTrapMap found bad string [%s] at %p (%s[%d])\n",
str, str, __FILE__, __LINE__);
goto done; // doesn't have DYNINST_REWRITE label
}
// get trap-table header
header = (struct trap_mapping_header*) ((unsigned long) memInfo.AllocationBase +
*((unsigned long*) (str - sizeof(void*))));
done:
if(header)
{
rtdebug_printf("RTLIB: found trap map header at %lx: [%lx %lx]\n",
(unsigned long) header, header->low_entry, header->high_entry);
}
else
{
rtdebug_printf("ERROR: didn't find trap table\n");
}
return header;
}
// Find the target IP and substitute. Leave everything else untouched.
LONG
dyn_trapHandler(PEXCEPTION_POINTERS e)
{
void* trap_to = 0;
void* trap_addr = (void*) ((unsigned char*) e->ExceptionRecord->ExceptionAddress);
unsigned long zero = 0;
unsigned long one = 1;
unsigned long loadAddr = 0;
struct trap_mapping_header* hdr = NULL;
trapMapping_t* mapping = NULL;
rtdebug_printf("RTLIB: In dyn_trapHandler for exception type 0x%lx at 0x%lx\n",
e->ExceptionRecord->ExceptionCode, trap_addr);
assert(DYNINSTstaticMode && "detach on the fly not implemented on Windows");
if(EXCEPTION_BREAKPOINT != e->ExceptionRecord->ExceptionCode)
{
fprintf(stderr,
"RTLIB: dyn_trapHandler exiting early, exception "
"type = 0x%lx triggered at %p is not breakpoint %s[%d]\n",
e->ExceptionRecord->ExceptionCode, trap_addr, __FILE__, __LINE__);
return EXCEPTION_CONTINUE_SEARCH;
}
hdr = getStaticTrapMap((unsigned long) trap_addr, &loadAddr);
assert(hdr);
mapping = &(hdr->traps[0]);
rtdebug_printf("RTLIB: calling dyninstTrapTranslate(\n\t0x%lx, \n\t"
"0x%lx, \n\t0x%lx, \n\t0x%lx, \n\t0x%lx)\n",
(unsigned long) trap_addr - loadAddr + 1, hdr->num_entries, zero,
mapping, one);
trap_to = dyninstTrapTranslate((void*) ((unsigned long) trap_addr - loadAddr + 1),
(unsigned long*) &hdr->num_entries, &zero,
(volatile trapMapping_t**) &mapping, &one);
#ifdef _WIN64
rtdebug_printf("RTLIB: changing Rip from trap at 0x%lx to 0x%lx\n",
e->ContextRecord->Rip, (long) trap_to + loadAddr);
e->ContextRecord->Rip = (long) trap_to + loadAddr;
#else
rtdebug_printf("RTLIB: changing Eip from trap at 0x%lx to 0x%lx\n",
e->ContextRecord->Eip, (long) trap_to + loadAddr);
e->ContextRecord->Eip = (long) trap_to + loadAddr;
#endif
return EXCEPTION_CONTINUE_EXECUTION;
}
PVOID fake_AVEH_handle;
/* registers the trap handler by calling AddVectoredExceptionHandler
*/
int
DYNINSTinitializeTrapHandler()
{
fake_AVEH_handle = AddVectoredExceptionHandler(
RT_TRUE, (PVECTORED_EXCEPTION_HANDLER) dyn_trapHandler);
rtdebug_printf("RTLIB: added vectored trap handler\n");
return fake_AVEH_handle != 0;
}
PVOID
dyn_AddVectoredExceptionHandler(ULONG isFirst, PVECTORED_EXCEPTION_HANDLER handler)
{
PVOID handlerHandle;
if(isFirst)
{
RemoveVectoredExceptionHandler(fake_AVEH_handle);
handlerHandle = AddVectoredExceptionHandler(isFirst, handler);
fake_AVEH_handle = AddVectoredExceptionHandler(
isFirst, (PVECTORED_EXCEPTION_HANDLER) dyn_trapHandler);
}
else
{
handlerHandle = AddVectoredExceptionHandler(isFirst, handler);
}
return handlerHandle;
}
extern int fakeTickCount;
extern FILE* stOut;
DWORD __stdcall DYNINST_FakeTickCount()
{
DWORD tmp = 0x12345678;
if(0 == fakeTickCount)
{
fakeTickCount = tmp;
}
else
{
fakeTickCount = fakeTickCount + 2;
// fakeTickCount = fakeTickCount + (tmp - fakeTickCount)/1000 + 1;
}
fprintf(stOut, "0x%lx = DYNINST_FakeTickCount()\n", fakeTickCount);
return (DWORD) fakeTickCount;
}
BOOL __stdcall DYNINST_FakeBlockInput(BOOL blockit)
{
BOOL ret = RT_TRUE;
fprintf(stOut, "0x%lx = DYNINST_FakeBlockInput(%d)\n", ret, blockit);
return ret;
}
DWORD __stdcall DYNINST_FakeSuspendThread(HANDLE hThread)
{
DWORD suspendCnt = 0;
fprintf(stOut, "%d = DYNINST_FakeSuspendThread(%p)\n", suspendCnt, hThread);
return suspendCnt;
}
BOOL __stdcall DYNINST_FakeCheckRemoteDebuggerPresent(HANDLE hProcess,
PBOOL bpDebuggerPresent)
{
BOOL ret = RT_FALSE;
fprintf(stOut, "%d = DYNINST_FakeCheckRemoteDebuggerPresent(%p,%p)\n", ret, hProcess,
bpDebuggerPresent);
(*bpDebuggerPresent) = ret;
return ret;
}
VOID __stdcall DYNINST_FakeGetSystemTime(LPSYSTEMTIME lpSystemTime)
{
lpSystemTime->wYear = 2009;
lpSystemTime->wMonth = 5;
lpSystemTime->wDayOfWeek = 0;
lpSystemTime->wDay = 3;
lpSystemTime->wHour = 10;
lpSystemTime->wMinute = 1;
lpSystemTime->wSecond = 33;
lpSystemTime->wMilliseconds = 855;
fprintf(stOut, "called DYNINST_FakeGetSystemTime()\n");
fflush(stOut);
}
void
mark_heaps_exec()
{
int OK;
DWORD old_permissions;
OK = VirtualProtect(DYNINSTstaticHeap_16M_anyHeap_1, sizeOfAnyHeap1,
PAGE_EXECUTE_READWRITE, &old_permissions);
if(!OK)
{
fprintf(stderr, "ERROR: 16M/any heap not usable in RTlib: %d\n", GetLastError());
}
OK = VirtualProtect(DYNINSTstaticHeap_512K_lowmemHeap_1, sizeOfLowMemHeap1,
PAGE_EXECUTE_READWRITE, &old_permissions);
if(!OK)
{
fprintf(stderr, "ERROR: 512k/lowmem heap not usable in RTlib: %d\n",
GetLastError());
}
}