Come posso stampare un CFStringRef in un'azione DTrace?
Domanda
Ho una sonda DTrace che rileva le chiamate a una funzione e uno degli argomenti della funzione è un CFStringRef
. Questa è una struttura privata che contiene un puntatore a una stringa unicode. Ma CFStringRef
non è esso stesso un char *
, quindi i normali metodi DTrace come copyinstr ()
restituiscono semplicemente ? Cp?
, che non è esattamente utile.
Quindi, come posso stampare la stringa nell'azione DTrace?
Soluzione
Per quanto ne so, non esiste un supporto integrato per questo tipo di cose. Di solito una libreria pubblica un probe che decodifica la stringa per te (come menziona Brad). Quindi poiché nel tuo caso non puoi modificare la libreria, dovrai usare il provider pid
e agganciarti a una funzione utente e decodificarla tu stesso.
La soluzione (che è molto simile all'approccio che useresti in C ++ per scaricare un std :: string
) è scaricare il puntatore che è memorizzato con un offset di 2 parole dalla base Puntatore CFStringRef
. Si noti che poiché un CFString
può memorizzare stringhe internamente in una varietà di formati e rappresentazioni, questo è soggetto a modifiche.
Data la banale applicazione di test:
#include <CoreFoundation/CoreFoundation.h>
int mungeString(CFStringRef someString)
{
const char* str = CFStringGetCStringPtr(someString, kCFStringEncodingMacRoman);
if (str)
return strlen(str);
else
return 0;
}
int main(int argc, char* argv[])
{
CFStringRef data = CFSTR("My test data");
printf("%u\n", mungeString(data));
return 0;
}
Il seguente script dtrace
stamperà il valore di stringa del primo argomento, supponendo che sia un CFStringRef
:
#!/usr/sbin/dtrace -s
/*
Dumps a CFStringRef parameter to a function,
assuming MacRoman or ASCII encoding.
The C-style string is found at an offset of
2 words past the CFStringRef pointer.
This appears to work in 10.6 in 32- and 64-bit
binaries, but is an implementation detail that
is subject to change.
Written by Gavin Baker <gavinb.antonym.org>
*/
#pragma D option quiet
/* Uncomment for LP32 */
/* typedef long ptr_t; */
/* Uncomment for LP64 */
typedef long long ptr_t;
pid$target::mungeString:entry
{
printf("Called mungeString:\n");
printf("arg0 = 0x%p\n",arg0);
this->str = *(ptr_t*)copyin(arg0+2*sizeof(ptr_t), sizeof(ptr_t));
printf("string addr = %p\n", this->str);
printf("string val = %s\n", copyinstr(this->str));
}
E l'output sarà simile a:
$ sudo dtrace -s dump.d -c ./build/Debug/dtcftest
12
Called mungeString:
arg0 = 0x2030
string addr = 1fef
string val = My test data
Rimuovi semplicemente il commento dal typedef
corretto a seconda che tu stia eseguendo un binario a 32 o 64 bit. Ho provato questo su entrambe le architetture su 10.6 e funziona benissimo.
Altri suggerimenti
Credo che non sia possibile farlo direttamente, ma è possibile creare un probe statico personalizzato che alimenta CFString / NSString come carattere *, che è possibile utilizzare con copyinstr (). Descrivo come farlo in un articolo qui .