Блог пользователя masterx


FreeBSD. kgdb KLD debugging

Как и прочая FreeBSD-шная литра, FreeBSD Developers' Handbook, морально устарела и пользоваться ей, по крайней мере для debugging the KLD modules большого смысла нет. Копи-пэйст моего дебагинга:

FreeBSD. cvsup для машины за "фаерволом"

cvsup host: cvsup.de.freebsd.org
машина за "фаерволом": A
машина НЕ за фаерволом: B

A # ssh -L5999:cvsup.de.freebsd.org:5999 B
B #

Затем, на машине А, в нужный supfile прописываем:
*default host=localhost

и запускаем cvsup

FreeBSD: одна из причин: kldload: can't load ...: File exists

На данный момент работаю с веткой -CURRENT. Обновил через perforce весь src/, Зашел в src/sys/modules/em. Сделал: make clean; make. Далее при попытке загрузить модуль:

sudo kldload ./if_em.ko

в терминал вылетело сообшение: "kldload: can't load if_em.ko: File exists". Одной из причин данного сообшения может являться тот факт, что модуль, который мы пытаемся подгрузить, статически слинкован с ядром. Проверить этот вариант можно следующим образом:

 cd /boot/kernel/
 readelf -s kernel.symbols| grep FILE | grep if_em

Поиски if_em в ядре не увенчались успехом. Погуглил и нашел подсказку здесь:
http://www.mail-archive.com/freebsd-hackers@freebsd.org/msg70080.html:

% grep __FreeBSD_version /usr/src/sys/param.h
...
#define __FreeBSD_version 900013        /* Master, propagated to newvers */
% sysctl kern.osreldate
kern.osreldate: 900014

FreeBSD: проблемы с msmtp

msmtp из порта собирается без поддержки TLS, в следствие чего, использование smtp на google затрудненно. Исправляем:

# cd /usr/ports/mail/msmtp
# make -DWITH_OPENSSL install clean

~/.msmtprc:

account gmail
host smtp.gmail.com
from 
auth on
tls on
tls_trust_file /usr/local/share/certs/ca-root-nss.crt
user 
password passwd
port 587
 
account default : gmail

Подкасты с Эха Москвы.

В университете редиска-сисадмин отказывается инсталлировать на рабочий комп полезные программы, с помощью которых, в свободное от работы время можно комфортно прослушивать подкасты любимой радиостанции. Время от времени стряпались небольшие скриптики для выуживания mp3-шных треков с новыми передачами Эха Москвы, и наконец накопившийся материал удачно собрался в один большой скрипт.

Вот некоторые колеса:

Русская Рулетка

# [ $[ $RANDOM % 6 ] == 0 ] && rm -rf /* || echo "Жив"
Играть в Русскую Рулетку надо имея права администратора (root), желательно на сервере, имеющем свыше 3000 посещений в день.

Украдено отсюда: http://lurkmore.ru/Rm_-rf

Vim. Перемещения курсора в Си-программах. Прыжок к телу функции.

Пару месяцев назад запостил в типсы исправленный vim-скрипт Cfname.vim, облегчающий редактирование программ на C. Оригинал можно найти на http://www.vim.org/scripts/. Автор не пожелал выложить новый скрипт с моими исправлениями, поэтому использовать "тамошний" скрипт не рекомендую, так как он во многих случаях не делает того, что должен. Лучше пользоваться моим.
Самой интересной фичей скрипта является возможность определения функции, в теле которой расположен курсор, и печать заголовка ( имя_функции (... ) { ) по нажатию определенных клавиш.

FreeBSD. Callouts. Переодически вызывающиеся в ядре функции.

Понадобилось написать функцию, которая один (первый) раз вызывается из системного вызова, и далее продолжает вызываться в ядре через заданные промежутки времени N раз несмотря на возвращение процесса из системного вызова в user space. Реализуется данный механизм через callout (9).
Порядок действий прост:
1. обявляем структуру struct callout my_callout
2. callout_init(struct callout &my_callout, 1);
3. Пишем функцию, которая должна вызываться: func (void *arg)
4. Внутри функции делаем следующее: callout_reset(&my_callout, secs*hz, func, arg);
Сие привяжет my_callout к func, реинициализирует таймер, и через secs секунд повторно будет вызвана func.

Исходник:

#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>

FreeBSD. Remapping kernel memory buffer to space of user process

Задача: В системном вызове создать в пространстве ядра буфер. Сделать дополнительное отображение буфера в пространство процесса, сделавшего системный вызов. Другими словами, привязать к буферу два набора виртуальных адресов: кернельные, для доступа к буферу из системного вызова, и другие виртуальные адреса для процесса.

Ни в какой литературе даже примерного решения данной проблемы не нашел. Поэтому, как всегда, методом проб и ошибок, просматривая чужие исходники с решением похожих задач, пришел к такому варианту решения:

  • Получаем указатель на структуру vmspace, описывающую виртуальное адресное пространство процесса: struct vmspace *vms = procp->p_vmspace;
  • Создаем буфер размером в страницу: MALLOC(addr, vm_offset_t, PAGE_SIZE, M_DEVBUF...
  • Находим vm_object, соответствующий выделенному буферу: vm_map_lookup(&kmem_map, addr, VM_PROT_ALL,

FreeBSD. Копирование данных между ядром и процессом пользователя.

copy (9)
copy, copyin, copyout, copystr, copyinstr -- kernel copy functions

В принципе, copystr копирует данные между ядром и процессом, в контексте которого ядро выполняется. Спрашивалось, для чего нужны copyinstr, copyout, copyin ???
copystr - работает только с резидентными страницами. Если страница не подгружена, то возникает kernel panic.
Функциям *in, *out присутствие страниц в памяти необязательно.

FreeBSD. Работа с адресным пространством процесса из системного вызова.

С целью ускорить передачу данных между ядром и процессом пользователя применяется системный вызов mmap. В качестве параметра файлового дескриптора указывается путь к символьному устройству и если драйвер устройства поддерживает вызов mmap, то в пространстве ядра выделяется (malloc) участок памяти, который отображается в адресное пространство процесса, вызвавшего mmap.

Debian Lenny. По следам инсталляции.

Несколько раз пришлось переинсталлировать Debian Lenny. Каждый раз не без глюков. Скидываю историю команд, на случай если не дай бог ещё раз придется.

SSH Port Forwarding

Пришлось столкнуться с очередной проблемкой, которую с третей попытки не решил. Опять таки было лень вдумчиво читать ман.
Итак, переброска портов с локальной машины на удалённую и наоборот. Писать вобщем-то нечего, так как до меня уже все написали. Поэтомму только ссылки
Доступ к компьютеру за файерволом - Remote port forwarding
Переброс портов удаленного сервера на локальную машину - Local port forwarding
И еще тут с картинками.
…
A теперь коротко и ясно:
1. Local port forwarding

ssh -L 1111:localhost:2222 username@remotehost

все пакеты приходящие на порт 1111 локалной машины (localhost) отправляются на порт 2222 удаленной машины (remotehost).

2.Remote port forwarding
 

Debian. Маунтирование UFS2 партиции.

Так как с первых трех попыток не вышло из-за того, что поленился читать длиннющий ман, и дабы не пришлось читать его в следующий раз в поисках нужных опций, оставляю заметку здесь.

mount -t ufs -o ufstype=ufs2 -o ro  /dev/hda3 /mnt/bsd/

Без -ro маунтироваться отказывается, говорит, что:

% dmesg | grep ufs
[17202.002530] ufs was compiled with read-only support, can't be mounted as read-write

вот ведь как...

FreeBSD Модули. DECLARE_MODULE, MODULE_METADATA и SYSINIT.

Теперь несколько детальнее о модулях ядра. Ранее было описанно несколько способов, как имплантировать свой код в адресное пространство ядра ОС. Но для того, что бы этот код имел доступ к данным, определенным в ядре и предоставлял доступ к своим данным со стороны ядра и других модулей, нужно, как мне показалось, следовать определенным правилам. Итак, никуда не уйти от макроса DECLARE_MODULE.

FreeBSD. Общие данные для различных модулей

Приспичило ради интереса решить такую задачку: Написать два модуля ядра использующих общий пул данных. В моих предыдущих постах способ решения подобной задачи в userspace разобран и вопросов не оставляет. Но при попытке сделать нечто подобное в модулях ядра, происходят нежелательные эффекты. Похоже, что модуль при загрузке в ядро не экспортирует символы, которые в нем определены. То есть все определенные в модуле глобальные переменные видны функциям модуля, но не далее: другой загруженный модуль не увидит ни функций ни переменных, которые в первом модуле глобально определены.

FreeBSD Модули и ELF-Секции

Пост на стадии сурового редактирования. Мааса неточностей пока

В предыдущем посте подробно написал как создавать собственные ELF-секции, сославшись на то, что в ядре FreeBSD данная техника используется довольно часто.
Теперь на конкретном примере рассмотрим внутренности модуля ядра FreeBSD и убедимся, что техника размещения данных в собственных ELF-секциях играет в этом безобразии не последнюю роль.

С и ELF-Секции

Подробное описание ELF можно легко найти через поиск в google, а если лень искать, то вот например.

В чем суть ? ELF - формат исполняемых и объектных(.o) файлов, а также динамических библиотек(.so). Что находится в файлах всех перечисленных типов? Программы: код функций и данные, с которыми функции работают. Зачем нужен какой-то там формат? Во первых, что бы ОС знала как загрузить файл, и по какому адресу затем передать управление. Также куча програмного обеспечения создается не одним программистом и не в одном файле и, по этому, было бы неплохо иметь возможность соединять различные бинарники на стадии линковки или динамически при загрузке. Но для этого, внутренности исполняемого файла должны представлять собой не винегрет из кода и данных, а именть стандартную структуру, что бы загрузчик и линковщик могли эти файлы загружать и безошибочно связывать друг с другом.

И так, детали об ELF в соответствущей документации. А в кратце:

FreeBSD начало

Потратив (от части убив) не мало времени на изучение некоторых компонент ядра ОС FreeBSD, пришел к банальному выводу: "начинать нужно с начала".
FreeBSD Architecture Handbook - документация, состояние которой уже несколько лет не uptodate, по началу была для меня довольно посредственным помошником. Причины: Чрезмерная краткость при объяснении тех моментов, которые являются ключевыми в ядре ОС; например Kobj и Sysinit. Далее, читатель очень часто отсылается к макросам, без какого-либо указания на то, во что в конечном итоге данные макросы разворачиваются и откуда у них растут ноги. И главное, отсутствие ответов на вопросы: зачем? почему? и почему именно так, а не иначе?. Итоги и выводы: 1. Начинать мне с неё не стоило. 2. Лучшая документация - исходник.

C и массивы

По своей детской наивности предполагал, что массивы в Си суть указатели. А нет. Имя массива, таки да, будет подменяться на адрес первого элемента, но указателем, в правильном смысле этого слова, не является.

Примерчик (pointer.c):

char a[10];
char b[10];
 
int
main()
{
	a=b;	
	return(0);
}

Компилируем:

% cc -o pointer pointer.c
pointer.c: In function 'main':
pointer.c:7: error: incompatible types in assignment

Так как имя массива является константным указателем, тоесть константой, присваивать ему (ей) ничего нельзя.

Неплохое объяснение:

http://c-faq.com/aryptr/aryptr2.html


Другое дело так:

#include <stdlib.h>
 
char *a;
char *b;
 
int
main()
{
	a=malloc(10);
	b=malloc(10);
 
	a=b;	
	return(0);
}