-4

sqlite3_open takes a pointer to a pointer. Id like to trace the address of the second pointer.

E.g: p1(p2(obj))

https://www.sqlite.org/c3ref/open.html

int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);

What is the syntax to get the address of that pointer in DTrace?

Im using the pid$target::sqlite3_open:return probe to read from the arg1 that was set from the entry probe.

Im currently using:

// Copy pointer bytes from arg1 to kernel, cast to pointer. 
(uintptr_t *)copyin(arg1, sizeof(uintptr_t))

Which results in: invalid kernel access in action.

Im on MacOS with SIP enabled, is this the issue?

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
zino
  • 1,222
  • 2
  • 17
  • 47
  • What do you mean by "trace the address of the second pointer"? – S.S. Anne Sep 08 '19 at 00:14
  • What is `copyin`? What is it declared as? What happens if you remove the cast? – S.S. Anne Sep 08 '19 at 00:37
  • I mean I just want to print the address of the second pointer in hex. The first pointer is provided as `arg1` in the `entry` probe. `copyin` is a DTrace global function for moving data from a user process to the kernel where the DTrace process runs (as I understand it). http://dtrace.org/guide/dtrace-ebook.pdf#page=117 – zino Sep 08 '19 at 12:56
  • No need to include your tags in the question title. I already understand this is a DTrace question. – S.S. Anne Sep 08 '19 at 13:09
  • 2
    Why the down votes? – zino Sep 12 '19 at 19:53
  • @zino Have you figured out it? But the answer is: yes, it is SIP. – lelf Dec 22 '19 at 19:33

2 Answers2

6

I may be misunderstanding your question, but what I suspect is that you've misunderstood how sqlite3_open works.

To call sqlite3_open you should have a code that looks like this:

sqlite3 * pDB = NULL;
/* ... */
int result = sqlite3_open("file:database.db", &pDB);

As you see, there's no "pointer to pointer" variable in my code. Instead, sqlite3_ope takes the address of of a pointer variable I allocated on the stack.

To copy that pointer is as simple as:

 sqlite3 * pDB2 = pDB

The reason for this is simple:

The sqlite3_open function wants to return two variable, which is impossible in C.

Instead of returning two variables, sqlite3_open returns only one variable directly and returns the second variable indirectly.

In order to return the second, it takes a pointer to a variable of the same type it wants to return. Then, by dereferencing the address and filling in the value, it provides you with the second variable's value.

However, the second variable sqlite3_open returns is a pointer. This is why, in order to return a pointer as a second variable, sqlite3_open requires a pointer to a pointer variable.

Reading the address

In the example above, the pDB variable holds the address for the sqlite3 object (the one allocated by sqlite3_open).

The address, as you know, is simply a number representing a location in the memory. To read the pointer value as a number, simply cast the pointer to a uintptr_t. i.e.:

 uintptr_t db_mem_addr_value = (uintptr_t)pDB;

Of course, numbers (and memory addresses) can't be printed as hex strings directly, they need a function that will convert them into hex notation.

Consider that in C you would print the memory address in Hex notation by using printf i.e.,

 fprintf(stderr, "%p\n", (void *)pDB);

Using dtrace would be the same. You might want to convert the pointer address to a number, for example, using the lltostr dtrace function:

 lltostr((uintptr_t)*(void**)arg1, 16)
S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
Myst
  • 18,516
  • 2
  • 45
  • 67
  • The `sqlite3_open` call in my code is working as intended. What I am trying to do is get the hex address of that second pointer in my DTrace script (not my program). – zino Sep 08 '19 at 13:01
  • @zino , I don't know if my edit helped. I hope it did... I wish your question included an example I could fiddle with. – Myst Sep 08 '19 at 23:03
  • This usage is common with *opaque pointers*, where the implementation of a struct is hidden from the end user (like `FILE` in the standard library). Sometimes it can be easier to mentally trace these things if you bundle up that lowest level of pointers with something like `typedef sqlite3* pdb`. – bta Sep 11 '19 at 00:43
0

Not a dtrace pro, but here are some observations.

uintptr_t is defined to be large enough to hold any pointer converted to an integer. Note that this does not imply that sizeof(uintptr_t) == sizeof(void*). It is perfectly valid (and on some platforms, necessary) for uintptr_t to be strictly larger than a pointer. That means your copyin call might be copying more bytes than are actually there. Try using a size of sizeof(sqlite**) instead.

Also, it's possible that some of OSX's internal protection mechanisms are causing you problems. See the answer on this related question for a good explanation.

bta
  • 43,959
  • 6
  • 69
  • 99
  • 1
    Specifically on MacOS (assuming an Apple computer, and not some hackintosh), pointer lengths are all equal to 8 bytes. Function pointer lengths, `void *` pointer lengths, etc' are all equal length (64 bit memory addresses). `uintptr_t` is also 8 bytes longs. – Myst Sep 11 '19 at 12:07
  • `csrutil enable --without dtrace` fixed the `invalid kernel access in action` error I was seeing. – zino Sep 12 '19 at 19:54