2009-09-11 5 views
8

У меня есть DTrace-зонд, который ловит вызовы функции, а один из аргументов функции - CFStringRef. Это частная структура, которая содержит указатель на строку юникода. Но CFStringRef сам по себе не является char*, поэтому обычные методы DTrace, такие как copyinstr(), просто возвращают ?cp?, что не совсем полезно.Как напечатать CFStringRef в действии DTrace?

Итак, как я могу распечатать строку в действии DTrace?

ответ

12

Насколько я знаю, нет встроенной поддержки такого рода вещей. Обычно библиотека будет публиковать пробник, который декодирует строку для вас (как упоминает Брэд). Так как в вашем случае вы не можете изменить библиотеку, вам нужно будет использовать провайдера pid и подключиться к пользовательской функции и самостоятельно декодировать ее.

Решение (которое очень похоже на подход, который вы использовали бы на C++ для дампа std::string), заключается в том, чтобы выгрузить указатель, который хранится со смещением на два слова от указателя базы CFStringRef. Обратите внимание: поскольку CFString может хранить строки внутри разных форматов и представлений, это может быть изменено.

Учитывая тривиальное тестовое приложение:

#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; 
} 

Следующая dtrace скрипт будет печатать значение строки первого аргумента, при условии, что это 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)); 

} 

И выход будет что-то например:

$ sudo dtrace -s dump.d -c ./build/Debug/dtcftest 
12 
Called mungeString: 
arg0 = 0x2030 
string addr = 1fef 
string val = My test data 

Просто unco mment right typedef в зависимости от того, работаете ли вы с 32-битным или 64-битным двоичным кодом. Я тестировал это на обеих архитектурах на 10.6, и он отлично работает.

+0

Используя эту программу и этот файл зонда, я просто получаю большой список: dtrace: ошибка на включенном зонде ID 1 (ID 93815: pid11402: sc: mungeString: entry): недействительный адрес (0x7c8) в действии # 5 на DIF смещение 12 Вывод из линии, которая печатает строку, я видеть, что весь строковый addrs является немного необычной: Вызывается mungeString: arg0 = 0x100001068 строки адр = 7c8 добавления второго, другой постоянной строки и mungeString'ing его, я получаю тот же string addr для обеих строк. – TALlama

+0

Хорошо, я могу сказать по адресам памяти, что вы должны использовать 10.6 и создавать 64-битное приложение. Я написал тестовое приложение (в спешке!) На 10,5, поскольку в то время у меня был доступ. Я должен был бы использовать sizeof (intptr_t) для смещения в сценарии DTrace, чтобы быть нейтральным с духом (а не с жестким кодом 8, который теперь будет 16 в 64-битном приложении). Я посмотрю на машину 10.6. – gavinb

+0

@TALlama Попробуйте обновленный сценарий выше. Я тестировал его как в 32-битных, так и в 64-битных двоичных файлах, и он отлично работает. – gavinb

1

Я считаю, что вы не можете сделать это напрямую, но вы можете создать настраиваемый статический зонд, который подает в CFString/NSString как char *, который вы можете использовать с copyinstr(). Я описываю, как это сделать в статье here.

+0

К сожалению, я пытаюсь использовать это, чтобы исследовать некоторый скомпилированный код, который у меня нет, поэтому изменить источник невозможно. – TALlama