Skip to content

Commit

Permalink
tmp
Browse files Browse the repository at this point in the history
  • Loading branch information
xoofx committed Dec 1, 2024
1 parent bb61081 commit 250aa29
Show file tree
Hide file tree
Showing 3 changed files with 394 additions and 0 deletions.
377 changes: 377 additions & 0 deletions src/Ultra.Sampler/Sampler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,377 @@
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Ultra.Sampler;

public class Sampler
{
public unsafe static void Sample()
{
var result = Native.task_for_pid(Native.mach_task_self(), Process.GetCurrentProcess().Id, out int task);
if (result != 0)
{
Console.WriteLine($"task_for_pid failed with error code {result}");
return;
}

uint* taskList;

result = Native.task_threads(task, &taskList, out uint taskCount);
if (result != 0)
{
Console.WriteLine($"task_threads failed with error code {result}");
return;
}

result = Native.pthread_threadid_np(0, out var currentThreadId);
Console.WriteLine($"Current Thread ID: {currentThreadId}");

byte* nameBuffer = stackalloc byte[256];

for (var i = 0; i < taskCount; i++)
{
var threadPort = taskList[i];
int threadInfoCount = Native.THREAD_IDENTIFIER_INFO_COUNT;
result = Native.thread_info(threadPort, Native.THREAD_IDENTIFIER_INFO, out var threadInfo, ref threadInfoCount);
if (result != 0)
{
Console.WriteLine($"thread_info failed with error code {result}");
return;
}

var thread_t = Native.pthread_from_mach_thread_np(threadPort);

if (thread_t != 0)
{
result = Native.pthread_getname_np(thread_t, nameBuffer, 256);
if (result != 0)
{
Console.WriteLine($"pthread_getname_np failed with error code {result}");
return;
}
Console.WriteLine($"Thread ID: {threadInfo.thread_id} Name: {Marshal.PtrToStringAnsi((IntPtr)nameBuffer)}");
}
else
{
Console.WriteLine($"Thread ID: {threadInfo.thread_id}");
}

if (threadInfo.thread_id == currentThreadId) continue;

result = Native.thread_suspend(taskList[i]);
if (result != 0)
{
Console.WriteLine($"thread_suspend failed with error code {result}");
return;
}

arm_thread_state64_t armThreadState = new arm_thread_state64_t();
int armThreadStateCount = Native.ARM_THREAD_STATE64_COUNT;

result = Native.thread_get_state(threadPort, Native.ARM_THREAD_STATE64, (nint)(void*)&armThreadState, ref armThreadStateCount);
if (result != 0)
{
Console.WriteLine($"thread_get_state failed with error code {result}");
return;
}

//Console.WriteLine($"sp: 0x{armThreadState.__sp:X8}, fp: 0x{armThreadState.__fp:X8}, lr: 0x{armThreadState.__lr:X8}");
WalkCallStack(armThreadState.__sp, armThreadState.__fp, armThreadState.__lr);


result = Native.thread_resume(threadPort);
if (result != 0)
{
Console.WriteLine($"thread_resume failed with error code {result}");
return;
}
}
}

private static unsafe void WalkCallStack(ulong sp, ulong fp, ulong lr)
{
while (fp != 0)
{
// TODO: log lr
sp = fp + 16;
lr = *(ulong*)(fp + 8);
fp = *(ulong*)fp;
}
}
}

internal static class Native
{
internal const int EPERM = 1;

internal const int KERN_INVALID_ADDRESS = 1;

internal const int PROT_READ = 0x01;

internal const int PT_ATTACH = 10; // TODO: deprecated
internal const int PT_DETACH = 11;

internal const int TASK_DYLD_INFO = 17;
internal const int THREAD_IDENTIFIER_INFO = 4;
internal const int x86_THREAD_STATE64 = 4;
internal const int ARM_THREAD_STATE64 = 6;
internal const int VM_REGION_BASIC_INFO_64 = 9;

internal static readonly unsafe int TASK_DYLD_INFO_COUNT = sizeof(task_dyld_info) / sizeof(uint);

internal static readonly unsafe int
THREAD_IDENTIFIER_INFO_COUNT = sizeof(thread_identifier_info) / sizeof(uint);

internal static readonly unsafe int x86_THREAD_STATE64_COUNT = sizeof(x86_thread_state64_t) / sizeof(uint);
internal static readonly unsafe int ARM_THREAD_STATE64_COUNT = sizeof(arm_thread_state64_t) / sizeof(uint);

internal static readonly unsafe int VM_REGION_BASIC_INFO_COUNT_64 =
sizeof(vm_region_basic_info_64) / sizeof(int);

private const string LibSystem = "libSystem.dylib";

[DllImport(LibSystem, SetLastError = true)]
internal static extern int kill(int pid, int sig);

[DllImport(LibSystem)]
public static extern int pthread_threadid_np(nint thread, out ulong threadId);

[DllImport(LibSystem)]
public static extern unsafe int pthread_getname_np(nint thread, byte* name, nint len);

[DllImport(LibSystem)]
public static extern int thread_suspend(uint target_act);

[DllImport(LibSystem)]
public static extern int thread_resume(uint target_act);

[DllImport(LibSystem)]
public static extern nint pthread_from_mach_thread_np(uint target_act);

[DllImport(LibSystem)]
internal static extern int mach_task_self();

[DllImport(LibSystem, SetLastError = true)]
internal static extern int ptrace(int request, int pid, IntPtr addr = default, int data = default);

[DllImport(LibSystem)]
internal static extern int task_for_pid(int parent, int pid, out int task);

[DllImport(LibSystem)]
internal static extern int task_info(int target_task, uint flavor, out /*int*/task_dyld_info task_info,
ref /*uint*/int task_info_count);

[DllImport(LibSystem)]
internal static extern unsafe int task_threads(int target_task, uint** act_list, out uint act_list_count);

[DllImport(LibSystem)]
internal static extern int thread_info(uint target_act, uint flavor,
out /*int*/thread_identifier_info thread_info, ref /*uint*/int thread_info_count);

[DllImport(LibSystem)]
internal static extern int thread_get_state(uint target_act, int flavor, /*uint**/nint old_state, ref /*uint*/int old_state_count);

[DllImport(LibSystem)]
internal static extern unsafe int vm_read_overwrite(int target_task, /*UIntPtr*/ulong address, /*UIntPtr*/
long size, /*UIntPtr*/void* data, out /*UIntPtr*/long data_size);

[DllImport(LibSystem)]
internal static extern int mach_vm_region(int target_task, ref /*UIntPtr*/ulong address,
out /*UIntPtr*/ulong size, int flavor, out /*int*/vm_region_basic_info_64 info, ref /*uint*/int info_count,
out int object_name);

[DllImport(LibSystem)]
internal static extern int mach_vm_deallocate(int target_task, /*UIntPtr*/ulong address, /*UIntPtr*/ulong size);

[DllImport(LibSystem)]
internal static extern int mach_port_deallocate( /*uint*/ int task, uint name);

[DllImport(LibSystem)]
internal static extern int waitpid(int pid, IntPtr status, int options);

internal readonly struct dyld_all_image_infos
{
internal readonly uint version;
internal readonly uint infoArrayCount;
internal readonly ulong infoArray;

// We don't need the rest of this struct so we do not define the rest of the fields.
}

internal readonly struct dyld_image_info
{
internal readonly ulong imageLoadAddress;
internal readonly ulong imageFilePath;
internal readonly ulong imageFileModDate;
}

internal readonly struct task_dyld_info
{
internal readonly ulong all_image_info_addr;
internal readonly ulong all_image_info_size;
internal readonly int all_image_info_format;
}

internal readonly struct thread_identifier_info
{
internal readonly ulong thread_id;
internal readonly ulong thread_handle;
internal readonly ulong dispatch_qaddr;
}

internal readonly struct vm_region_basic_info_64
{
internal readonly int protection;
internal readonly int max_protection;
internal readonly uint inheritance;
internal readonly uint shared;
internal readonly uint reserved;
internal readonly ulong offset;
internal readonly int behavior;
internal readonly ushort user_wired_count;
}
}

[StructLayout(LayoutKind.Explicit)]
internal struct thread_state_t
{
[FieldOffset(0)] public x86_thread_state64_t x64;

[FieldOffset(0)] public arm_thread_state64_t arm;
}


[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct arm_thread_state64_t
{
public unsafe fixed ulong __x[29];
public ulong __fp;
public ulong __lr;
public ulong __sp;
public ulong __pc;
public uint __cpsr;
public uint __pad; // or __opaque_flags when ptrauth is enabled

/*public unsafe bool CopyContext(Span<byte> context)
{
if (context.Length < Arm64Context.Size)
return false;
ref Arm64Context contextRef = ref Unsafe.As<byte, Arm64Context>(ref MemoryMarshal.GetReference(context));
contextRef.ContextFlags = Arm64Context.ContextControl | Arm64Context.ContextInteger;
contextRef.Cpsr = __cpsr;
contextRef.X0 = __x[0];
contextRef.X1 = __x[1];
contextRef.X2 = __x[2];
contextRef.X3 = __x[3];
contextRef.X4 = __x[4];
contextRef.X5 = __x[5];
contextRef.X6 = __x[6];
contextRef.X7 = __x[7];
contextRef.X8 = __x[8];
contextRef.X9 = __x[9];
contextRef.X10 = __x[10];
contextRef.X11 = __x[11];
contextRef.X12 = __x[12];
contextRef.X13 = __x[13];
contextRef.X14 = __x[14];
contextRef.X15 = __x[15];
contextRef.X16 = __x[16];
contextRef.X17 = __x[17];
contextRef.X18 = __x[18];
contextRef.X19 = __x[19];
contextRef.X20 = __x[20];
contextRef.X21 = __x[21];
contextRef.X22 = __x[22];
contextRef.X23 = __x[23];
contextRef.X24 = __x[24];
contextRef.X25 = __x[25];
contextRef.X26 = __x[26];
contextRef.X27 = __x[27];
contextRef.X28 = __x[28];
// no ptrauth
contextRef.Fp = __fp;
contextRef.Lr = __lr;
contextRef.Sp = __sp;
contextRef.Pc = __pc;
return true;
}*/
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal readonly struct x86_thread_state64_t
{
public readonly ulong __rax;
public readonly ulong __rbx;
public readonly ulong __rcx;
public readonly ulong __rdx;
public readonly ulong __rdi;
public readonly ulong __rsi;
public readonly ulong __rbp;
public readonly ulong __rsp;
public readonly ulong __r8;
public readonly ulong __r9;
public readonly ulong __r10;
public readonly ulong __r11;
public readonly ulong __r12;
public readonly ulong __r13;
public readonly ulong __r14;
public readonly ulong __r15;
public readonly ulong __rip;
public readonly ulong __rflags;
public readonly ulong __cs;
public readonly ulong __fs;
public readonly ulong __gs;

/*public bool CopyContext(Span<byte> context)
{
if (context.Length < AMD64Context.Size)
return false;
ref AMD64Context contextRef = ref Unsafe.As<byte, AMD64Context>(ref MemoryMarshal.GetReference(context));
contextRef.ContextFlags =
AMD64Context.ContextControl | AMD64Context.ContextInteger | AMD64Context.ContextSegments;
contextRef.Rax = __rax;
contextRef.Rbx = __rbx;
contextRef.Rcx = __rcx;
contextRef.Rdx = __rdx;
contextRef.Rdi = __rdi;
contextRef.Rsi = __rsi;
contextRef.Rbp = __rbp;
contextRef.Rsp = __rsp;
contextRef.R8 = __r8;
contextRef.R9 = __r9;
contextRef.R10 = __r10;
contextRef.R11 = __r11;
contextRef.R12 = __r12;
contextRef.R13 = __r13;
contextRef.R14 = __r14;
contextRef.R15 = __r15;
contextRef.Rip = __rip;
contextRef.EFlags = (int) __rflags;
contextRef.Cs = (ushort) __cs;
contextRef.Ss = 0;
contextRef.Ds = 0;
contextRef.Es = 0;
contextRef.Fs = (ushort) __fs;
contextRef.Gs = (ushort) __gs;
return true;
}
*/
}

internal struct MemoryRegion //: IRegion
{
public ulong BeginAddress { get; set; }
public ulong EndAddress { get; set; }

public int Permission { get; set; }

public bool IsReadable => (Permission & Native.PROT_READ) != 0;
}
11 changes: 11 additions & 0 deletions src/Ultra.Sampler/Ultra.Sampler.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPackable>false</IsPackable>
</PropertyGroup>

</Project>
Loading

0 comments on commit 250aa29

Please sign in to comment.