Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I initialize a pointer to a specific C struct? #56

Open
antman1p opened this issue Jan 26, 2021 · 3 comments
Open

How do I initialize a pointer to a specific C struct? #56

antman1p opened this issue Jan 26, 2021 · 3 comments

Comments

@antman1p
Copy link

antman1p commented Jan 26, 2021

I asked this question in stackoverflow as well:

I have a JXA function that binds the libproc.dylib function proc_pidinfo and then I attempt to call the function like so:

ObjC.bindFunction('proc_pidinfo', ['int',['int', 'int', 'Int64', 'void *', 'int']]);
 var infoSize = $.proc_pidinfo(pids[0], PROC_PIDTBSDINFO, 0, pidInfo, INFO_SIZE );

However, the pidinfo argument needs to be a pointer to the procinfo.h struct proc_bsdinfo. I tried a few things like initializing a variable as a reference (var pidInfo = Ref();) with no type value, as well as several other type values (including "struct") as an argument, but nothing has worked:

How do I initialize the proc_bsdinfo struct?

@Tatsh
Copy link

Tatsh commented May 31, 2021

I don't think there is a (nice) way. Can you use a Swift script instead?

This is not working but it's close, and can't be run in sandboxed Swift app. Fix SomeTypeHere to be the struct, initialise pidInfo to the correct type, etc.

#!/usr/bin/env swift
import Darwin

let handle = dlopen("/usr/lib/libc.dylib", RTLD_NOW)
let proc_pidinfoSym = dlsym(handle, "proc_pidinfo")

typealias proc_pidinfoFunc = @convention(c) (_ x: CInt, _ y: CInt, _ z: CInt, _ q: UnsafeMutablePointer<SomeTypeHere>, _ r: CInt) -> CInt
let proc_pidinfo = unsafeBitCast(proc_pidinfoSym, to: proc_pidinfoFunc.self)

let pids = ...
var pidInfo: CInt = 0
let infoSize = proc_pidinfo(Int32(pids[0]), PROC_PIDTBSDINFO, 0, &pidInfo, 32)
print(infoSize)

@Tatsh
Copy link

Tatsh commented Nov 22, 2021

This can be done with $.malloc.

#!/usr/bin/env osascript -l JavaScript
ObjC.import('Cocoa')
ObjC.import('stdlib')

let pids = [145]
ObjC.bindFunction('malloc', ['void*', ['int']])
let pidInfo = $.malloc(2000)
ObjC.bindFunction('proc_pidinfo', ['int',['int', 'int', 'Int64', 'void *', 'int']]);
$.proc_pidinfo(pids[0], 3, 0, pidInfo, 2000 );

let arr = []
for (let i = 0; i < 2000; i++) {
    arr.push(String.fromCharCode(pidInfo[i]))
}
console.log(arr)

The issue is that the fields are not going to be defined at all.

Example output with pids = [145] where 145 is the PID of loginwindow.

0,`,@,,,,,,,,,,�,,,,,,,,õ,,,,,,,,,,,,,,,,,,,,,,,,,,,,l,o,g,i,n,w,i,n,d,o,w,,,,,,l,o,g,i,n,w,i,n,d,o,w,,,,,,,,,,,,,,
,,,,,,,,d,,,,�,,,,,,,,ÿ,ÿ,ÿ,ÿ,,,,,,,,,�,n,
�,a,,,,,L,�,,,,,,,à,¼,~,,,`,,,,½,~,,,`,,, ,½,~,,,`,,,@,½,~,,,`,,,`,½,~,,
,`,,,�,½,~,,,`,,, ,½,~,,,`,,,À,½,~,,,`,,,à,½,~,,,`,,
,,¾,~,,,`,,, ,¾,~,,,`,,,@,¾,~,,,`,,,`,¾,~,,,`,,,�,¾,~,,,`,,,À,¾,~,,,`,,,à,¾,~,,,`,,,,¿
,~,,,`,,, ,¿,~,,,`,,,@,¿,~,,,`,,,�,¿,~,,,`,,, ,¿,~,,,`,,,À,¿,~,,,`,,,à,¿,~,,,`,,, ,º,},,,`,,,,
À,~,,,`,,, ,À,~,,,`,,,@,À,~,,,`,,,`,À,~,,,`,,, ,À,~,,,`,,,à
,À,~,,,`,,,,Á,~,,,`,,, ,Á,~,,,`,,,@,Á,~,,,`,,,`,Á,~,,,`,,,�,Á,~,,,`,,, ,Á,~
,,,`,,,À,Á,~,,,`,,,à,Á,~,,,`,,,,Â,~,,,`,,, ,Â,~,,,`,,,`,Â,~,,,`,,, ,Â,~,,,`,,,À,Â,~,,,`,,,à,Â,~,,,`,,,,Ã,~,,,`,,, ,Ã,~,

@stephancasas
Copy link

I realize this thread is a little old, but you may have better luck deciphering the output if you clear the allocated memory prior to passing it through the target function.

Here's an example implementing the deprecated GetProcessForPID function:

function run(argv) {
  ObjC.bindFunction('malloc', ['void*', ['int']]); // bind malloc
  ObjC.bindFunction('memset', ['void *', ['void *', 'int', 'int']]); // bind memset to clear allocated memory

  const PID = 516; // query for PID 516 (Brave Browser on my system at the time of this demo)
  const bytes = 8; // allocate 8 bytes -- for ProcessSerialNumber struct with two UInt32 fields

  let psn = $.malloc(bytes); // allocate the memory
  $.memset(psn, 0, bytes); // clear the memory

  ObjC.bindFunction('GetProcessForPID', ['int', ['int', 'void *']]); // override bind GetProcessForPID to ignore JXA type safety
  $.GetProcessForPID(PID, psn); // call the function

  // assemble the output for review
  let arr = [];
  for (let i = 0; i < bytes; i++) {
    arr.push(psn[i]);
  }

  return JSON.stringify(arr);
}

In my own test, I got back:

[0,0,0,0,15,240,0,0]

This can be read as two UInt32 values — highLongOfPSN and lowLongOfPSN — belonging to the struct ProcessSerialNumber. Having already run the function from XCode using the native ObjC compiler, I know the decimal values for these fields to be 0 and 61455. If I convert the latter to a its UInt32 (little endian) equivalent, we get the bytes 15, 240, 0, 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants