Столкнулся с необходимостью пересобрать старый streams-модуль ядра. Оказывается, теперь в Solaris недостаточно просто скомпилировать и собрать драйвер из исходников как это было раньше:
# 32 bit module
$ cc -O -D_KERNEL -c tlm.c
$ ld -r -o tlm tlm.o
# 64 bit module
$ cc -D_KERNEL -xarch=v9 -xcode=abs32 -xregs=no%appl -O -c -o tlm64.o tlm.c
$ ld -r -o sparcv9/tlm tlm64.o
В Solaris10 и OpenSolaris включены утилиты, которым для своей работы небходима дополнительная символическая информация в загружаемом файле, называемая СTF. К таким утилитам относятся, к примеру, dtrace, mdb, scat.
СTF - (Compact C Type Format) - формат храниения и описания структур и параметров вызова языка С. Очень похож на stubs/DWARF за исключением того, что в СTF нет необходимости хранить информацию о строках кода. СTF, подобно DWARF размещается в ELF- файле, однако записывается туда не компилятором, а при помощи специальных утилит ctfconvert, ctfmerge, ctfdump и хранится в специальной секции этого файла .SUNW_ctf:
$ elfdump -c /usr/kernel/fs/pcfs
Section Header[1]: sh_name: .text
.... skiped ....
Section Header[15]: sh_name: .SUNW_ctf
sh_addr: 0 sh_flags: 0
sh_size: 0x6e36 sh_type: [ SHT_PROGBITS ]
sh_offset: 0x120a4 sh_entsize: 0
sh_link: 0 sh_info: 0
sh_addralign: 0x4
сtfconvert - преобразует DWARF информацию в объектном файле (скомпилированном c обязательно опцией -g -включение отладочной информации) и записывает ее в секцию .SUNW_ctf вместо секций отладочной информации (секции .debug_* и .rel.debug_*). Объем объектного файла при этом становиться существенно меньше (~ в 2 раза).
За опциями пришлось лезть в исходники:
-l label - метка (обычно Alfa, Betta, Generic, Generic patch, номер патча), которая попадет в секцию меток, в преобразованном файле
-L variable - значение метки будет взято из переменной окружения variable
-o outfile - выходной файл (по умолчанию тот-же, что и исходный)
-s use .dynsym not .symtab используется в динамически линкуемых объектах
-i - игнорировать файлы скопилированные из языков, отличных от C
-g - сохранить информацию о stabs/DWARF в полученном файле. Можно установить еще и переменную окружения STRIPSTABS_KEEP_STABS
-v verbose
ctfmerge - собирает воедино информацию из нескольких объектных файлов, обрабатывает на уникальность и записыват в файл результата. Забавно, что внутри у простой утилиты оказался достаточно сложный алгоритм с многопоточной моделью и пространными коментариями, как она работает. Особенно порадовала фраза в конце описания: "The person who changes the merging thread code in this file without updating this comment will not live to see the stock hit five" - имеется в виду тот период жизни SUN Mirosystems, когда акции котировались ниже $5 за штуку =)
Опции, как и в прошлый раз из исходников. Сходные -L -l -s -o -g -v пропущены.
-d uniqfile - в качестве базового в проверке на уникальность использовать символы в uniqfile.
-D uniqlabel - использовать uniqlablel в uniqfile для проверки на уникальность CTF символов.
-f - использовать алгоритм нечеткого совпадения CTF символов.
-t - требовать наличия CTF информации во всех исходных файлах
-w файл - аддитивное слияние информации из указанного файла. Новая информация не перетирает старую, а дописывается в конец. Необходимо для реализации нового патча общего модуля, используемого другими модулями. Позволяет сохранить старое пространство меток, которые существуют и в других модулях тоже.
сtfdump - просмотр данных ctf. Куча опций - каждая выводит свою часть информации.
Описанные утилиты входят в состав пакета SUNWonbld.
теперь как же это работает?
$ cc -D_KERNEL -xarch=v9 -xcode=abs32 -xregs=no%appl -O -c -o tlm64.o tlm.c
$ ctfconvert -i -l "Generic patch" tlm64.o
$ ld -r -o sparcv9/tlm tlm64.o
$ ctfmerge -l "Generic patch" -d /kernel/genunix -o sparcv9/tlm tlm64.o
bash-3.00# modload /tmp/tlm
bash-3.00# /usr/ccs/bin/nm /dev/ksyms|grep tlm
[13388] |4273763332| 662|FUNC |LOCL |0 |ABS |kb8042_ioctlmsg
[18711] |3571966488| 16|OBJT |LOCL |0 |ABS |tlminfo
[37606] |4194799756| 22|FUNC |GLOB |0 |ABS |tlm_printmblk
[37605] |3571966484| 4|OBJT |GLOB |0 |ABS |tlm_table
bash-3.00# mdb -k
Loading modules: [ skiped ]
> ::print -ta struct Moddata
{
0 unsigned char [256] wrs
100 unsigned char [256] rds
}
> ::sizeof struct Moddata
sizeof (struct Moddata) = 0x200
>
Без этой чудо-процедуры было бы так
> ::print -ta struct Moddata
mdb: failed to look up type struct Moddata: No type information available for that name
>
Вывод: Для того, чтобы можно было просто просматривать структуры данных на работающем ядре используем утилиты CTF.