My Feed Title My Feed Description 2020-12-18T17:18:50+03:00 AlexBR https://putey.net/otladka Ошибки при разработке схемы. Дистанционный выключатель с таймером. https://putey.net/post/oshibki-pri-razrabotke-skhemy-nakazator 2020-12-18T17:18:50+03:00 2020-12-18T17:18:50+03:00

Что этот девайс, из себя представлят - это устройство, которое выклчает питание по таймеру и дает возможностьуправлять розеткой с расстояния. Можно сказать, что уже есть умные розетки, котороми можно управлять даже с телефона, но я не ищу легких путей. Нужно все испытать.

Задумка алгоритма

Устройство должно состоять из двух частей: 1-передатчик и 2-приемник. Данные по радиоканалу должны передаваться зашифрованными и если были записанными, то не могли быть многократно воспроизведены.

Передатчик

Состоит из двух тактовых кнопок и одного выклюателя, питается от 3-х батареек АА. Имеет один семисегментный индикатор, который показывает какую команду нужно передать. 1ая кнопка переключает последовательно доступные команды, 2ая кнопка осуществляет передачу. Расшифровка значения показания индикатора:

Символ Команда
включить питание на приемнике немедленно
сбросить таймер в 0 у текущего режима
включить питание и установить таймер на 10 минут(отключить питание по достижении значения)
включить питание и установить таймер на 20 минут(отключить питание по достижении значения)
включить питание и установить таймер на 30 минут(отключить питание по достижении значения)
включить питание и установить таймер на 40 минут(отключить питание по достижении значения)
включить питание и установить таймер на 50 минут(отключить питание по достижении значения)
включить питание и установить таймер на 60 минут(отключить питание по достижении значения)
включить питание и установить таймер на 70 минут(отключить питание по достижении значения)
включить питание и установить таймер на 80 минут(отключить питание по достижении значения)
включить питание и установить таймер на 90 минут(отключить питание по достижении значения)
отключить питание немедленно

При нажатии на творую кнопку, команда шифруется и отправляется на приемник.

Приемник

Устройство, принимающее команду, расшифровывающее ее. Выполняет команду и немедленно ее выполняет, тюе разрывает сеть 220 Вольт или наоборот коммутирует, или включает таймер и разрывает питание по таймеру. Приемник запитывается от сети 220 Вольт.

Алгоритм передатчика

Для передачи данных по воздуху используются FS1000A и XY-MK-5V, набор 433 МГц про который упоминается в предыдущей статье. А так же используется аналогичная библиотека ManchesterRF.c, но с изменениями для ATMega8, интервалы длинного и коротких периодов.

Как распознается принятая информация на основе короткого и длинного периода описывалось здесь

Вот код передатчика: исходный код

За один сеанс передаи передается 12 байт. Стурктура массива следующая:

  • 0-й байт - открытый ключ A(Alise) по алгоритму Диффи-Хелмана.
  • 1-й байт - индекс, с котрого в массиве наинаются полезные данные(их 4 байт)
  • ...
  • N-й полезный байт - секртеный идентификатор устройства
  • N+1й полезный байт - команда
  • N+2й полезный байт - младший байт счетчика сессии
  • N+3й полезный байт - старший байт счетчика сессии
  • ...

Публичный ключ от Боба (B) забит прямо в код передатчика, т.к. передающее устройство работает только в одну сторону

void sendMode(uint8_t command){
    ClearMessage(message, MESSAGE_LEN);
    SipherArray(message, MESSAGE_LEN, command);
    ManchesterRF_transmitArray(MESSAGE_LEN, message);
    if (!sesIdent) {
        ClearMessage(message, MESSAGE_LEN);
        SipherArray(message, MESSAGE_LEN, RESET_SESSION);
        ManchesterRF_transmitArray(MESSAGE_LEN, message);
    }
}

Если идентификатор сессии равен 0, то приемнику посылается команда RESET_SESSION, что заставлеят приемник сброситься, подать питание. При включении передатчика посылается команда RESET_SESSION, поэтому, если приемник не реагирует, то можно просто включить и выключить передатчик.

Схема передатчика получилась весьма простая и в проекте находится в папке KiCad.

С передатчиком все достаточно просто получилось.

Алгоритм приемника

А вот с приемником получились проблемы... Которые нужно учитывать...

]]>
Трюки при разработке и проектировании схем с микроконтроллерами AVR https://putey.net/post/tryuki-pri-razrabotke-i-proektirovanii-skhem-s-mikrokontrollerami-avr 2020-12-18T17:18:38+03:00 2020-12-18T17:18:38+03:00 Обзор двух способов:

  1. как развести дорожки печатной платы с помощью KiCAD 5+FreeRoute
  2. как эмулировать входной сигнал при отладке в симуляторе Atmel Studio

Видеошпаргалка, как сделать автоматическую трассировку в KiCad 5 + FreeRoute

Видеоинструкция о том как применять stimuli файл в среде Atmel Studio

Для задачи на видео потребовалось отладить, как контроллер обработает входящий последовательный сигнал с приемника и как он выделит данные. С помощью логического анализатора было получено поведение изменения сигнала на входе и сконвертировано в stim файл, понятный для симулятора Atmel Studio. И потом шаг за шагом отслеживается выделение данных из полученного сигнала.

]]>
memleak - отладчик утечек памяти https://putey.net/post/memleak-otladchik-utechek-pamyati 2019-03-28T01:40:32+03:00 2019-03-28T01:40:32+03:00 memleax отлаживает и находит утечки памяти без перезагрузки сервиса или процесса и без перекомпилляции.

Установка:

wget http://download.opensuse.org/repositories/home:/bayrepo/CentOS_7/home:bayrepo.repo -O /etc/yum.repos.d/home:bayrepo.repo
yum install memleax -y

Детали описания: http://docs.putey.net/ru/memleax

Автор утилиты: https://github.com/WuBingzheng/memleax

]]>
Использование gdb для отладки быстро завершающихся процессов https://putey.net/post/ispolzovanie-gdb-dlya-bystro-zavershayushikhsya-processov 2018-03-29T03:26:26+03:00 2018-03-29T03:26:26+03:00 Пусть необходимо отладить процесс, запускаемый из другого процесса и быстро завершающийся.

Пример: нужно отладить расширение PHP, PHP настроен как cgi, т.е процесс запускается при появлении запроса и быстро завершается.

В отладке поможет systemtap.

Первое, необходимо написать такой небольшой probe(php.stp):

#! /usr/bin/env stap

probe process("/opt/myphp/usr/lib64/php/modules/mymodule.so").function("check_func") {
    printf("Send SIGSTOP\n")
    raise(%{ SIGSTOP %})
}

probe begin {
    printf("Waiting for even or Ctrl+C\n")
}

Где /opt/myphp/usr/lib64/php/modules/mymodule.so - это путь к расширению, и check_func - это функция, которую нужно отладить. Проверить видимость для systemtap это функции можно командой: stap -L 'process("/opt/myphp/usr/lib64/php/modules/mymodule.so").function("check_func")' или в общем виде stap -L 'process("/opt/myphp/usr/lib64/php/modules/mymodule.so").function("*")' | grep check_func.

Все необходимые debug пакеты должны быть установлены.

Теперь запускаем stap: stap -g php.stp. Обязательно в режиме guru - -g. И вызываем скрипт посредством браузера, curl, wget, lynx и т.д.

Далее ищем php процесс в статусе T:

[~]# ps aux | grep php
root      3006  0.0  0.0 254628  3284 pts/8    S+   19:11   0:00 curl -v test.test/eval.php
user0   3008  0.1  0.3 230480 14236 ?        T    19:11   0:00 /opt/myphp/usr/bin/php-cgi

Присоединяемся к нему с помощью gdb gdb /opt/myphp/usr/bin/php-cgi --pid=3008

И выполняем такие команды:

gdb>b check_func
gdb>signal SIGCONT
gdb>n

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

Все, можно отлаживать.

]]>
SystemTap - часть 5. Наброски и черновики https://putey.net/post/systemtap-chastj-5-nabroski-i-chernoviki 2017-03-16T02:18:00+03:00 2017-03-16T02:18:00+03:00 В этой статье не планирую ставить никакого задания. Просто буду собирать полезные сценарии из интернета и возможно - описывать свои. А так же вставлю ссылки на полезные статьи по исследованию и описанию работы некоторых функций glibc, для дальнейшей возможности обследования их через systemtap.

Сценарий 1

Интересный скрипт, позволяющий остановить выполнение программы в нужном месте и запустить gdb

#!/bin/stap -g

global gdbRunning = 0;

probe process(@1).mark(@2)
{
    raise(%{ SIGSTOP %});

    gdbCmd = sprintf("cgdb -- -q -ex 'thread find %d' %s %d", tid(), @1, pid());

    if (gdbRunning == 0)
    {
        gdbRunning = 1;
        printf("STOP PID %d TID %d [%s]\n", pid(), tid(), gdbCmd);
        system(gdbCmd);
    }
    else
    {
        printf("STOP PID %d TID %d\n", pid(), tid());
    }
}

в качестве первого параметра задается имя программы или библиотеки или PID, в качестве второго параметра имя функции, место файла. Из нового в синтаксисе использования systemtap, это использование команды raise Взято отсюда: http://stackoverflow.com/questions/20492308/can-a-process-be-stopped-via-a-systemtap-probe-so-gdb-can-be-attached

Статья о malloc

Статья детальная, но на английском: https://developers.redhat.com/blog/2014/10/02/understanding-malloc-behavior-using-systemtap-userspace-probes/ полное название: Understanding malloc behavior using Systemtap userspace probes

Сценарий 2

Исследование захватов Mutex в User Space

#! /usr/bin/env stap

# This script tries to identify contended user-space locks by hooking
# into the futex system call.

global FUTEX_WAIT = 0 /*, FUTEX_WAKE = 1 */
global FUTEX_PRIVATE_FLAG = 128 /* linux 2.6.22+ */
global FUTEX_CLOCK_REALTIME = 256 /* linux 2.6.29+ */

global lock_waits # long-lived stats on (tid,lock) blockage elapsed time
global process_names # long-lived pid-to-execname mapping

probe syscall.futex.return {  
  if (($op & ~(FUTEX_PRIVATE_FLAG|FUTEX_CLOCK_REALTIME)) != FUTEX_WAIT) next
  process_names[pid()] = execname()
  elapsed = gettimeofday_us() - @entry(gettimeofday_us())
  lock_waits[pid(), $uaddr] <<< elapsed
}

probe end {
  foreach ([pid+, lock] in lock_waits) 
    printf ("%s[%d] lock %p contended %d times, %d avg us\n",
            process_names[pid], pid, lock, @count(lock_waits[pid,lock]),
            @avg(lock_waits[pid,lock]))
}

Взято отсюда https://sourceware.org/systemtap/SystemTap_Beginners_Guide/futexcontentionsect.html

Как распечатать содержимое передаваемое в функции не только в виде указатилей, но и провести разименовывание типов

Ранее уже опиминались опрделения для pretty printing

$$vars
Expands to a character string that is equivalent to  sprintf("parm1=%x ... parmN=%x var1=%x ... varN=%x",
          parm1, ..., parmN, var1, ..., varN) for each variable in scope at the probe point. Some values may be printed as “=?” if their run-time location cannot be found.
$$locals
Expands to a subset of $$vars containing only the local variables.
$$parms
Expands to a subset of $$vars containing only the function parameters.
$$return
Is available in return probes only. It expands to a string that is equivalent to  sprintf("return=%x",  $return) if the probed function has a return value, or else an empty string.

если вызвать stap -e 'probe kernel.function("vfs_read") {printf("%s\n", $$parms); exit(); }' то получим file=0xffff8800b40d4c80 buf=0x7fff634403e0 count=0x2004 pos=0xffff8800af96df48, что не дает прдеставления, а что же содерат указатели. Если в конце pretty print определения добавить $$, то можно получить и содержимое указателей: stap -e 'probe kernel.function("vfs_read") {printf("%s\n", $$parms$$); exit(); }' получаем

file={.f_u={.fu_list={.next=0xffff8801336ca0e8, .prev=0xffff88012ded0840}, .fu_rcuhead={.next=0xffff8801336ca0e8, .func=0xffff88012ded0840}}, .f_path={.mnt=0xffff880132fc97c0, .dentry=0xffff88001a889cc0}, .f_op=0xffffffffa06f64c0, .f_lock={.raw_lock={.slock=196611}}, .f_count={.counter=2}, .f_flags=34818, .f_mode=31, .f_pos=0, .f_owner={.lock={.raw_lock={.lock=16777216}}, .pid=0x0, .pid_type=0, .uid=0, .euid=0, .signum=0}, .f_cred=0xffff880130129a80, .f_ra={.start=0, .size=0, .async_size=0, .ra_pages=32, .

Так уже лучше.

Взято отсюда: https://sourceware.org/systemtap/SystemTap_Beginners_Guide/targetvariables.html

]]>
SystemTap - часть 4. Упрощенная версия ltrace своими руками https://putey.net/post/systemtap-chastj-4-uproshennaya-versiya-ltrace-svoimi-rukami 2017-03-11T02:16:00+03:00 2017-03-11T02:16:00+03:00 Попробую написать утилитку, которая бы отслеживала путь выполнения программы, не так подробно как ltrace, но все же существенно более быстро.

А так же попробую воспользоваться функциями.

1 Напишу функцию, которая аналогична indent, но с собственным алгоритмом формирования смещения:

function local_depth() {
    ind = ""
    for (i=depth[tid()];i>=0;i--){
        ind = sprintf("%s|", ind)
    }
    ind = ind . ">"
    return ind
}

Результат выполения функции - это строка отступа для текущего потока с учетом глубины вложенности. Т.е сведения о глубине хранятся в массиве depth с ключем tid(), т.е идентификатором текущего потока. Результат примерно выглядит так |||> или |||||||>

2 Непосредственно сами функции формирования информации о текущем местонахождении:

function out_info(func_name, vars_list, fid) {
    dbg = get_debug_info()
    if (dbg != "") {
        dbg = " >>>".dbg
    }
    printf("%s(%10d) uid(%5d):%s%s[%d](%s) %s%s\n", func_name, tid(), uid(), local_depth(), ppfunc(), fid, execname(), vars_list, dbg)
}

function out_info_return(func_name, vars_list, fid) {
    printf("%s(%10d) uid(%5d):|%s%s[%d](%s) ret +----> %s\n", func_name, tid(), uid(), local_depth(), ppfunc(), fid, execname(), vars_list)
}

Функции используют механизмы форматирования printf. И выводит стандартный, ранее рассматриваемый набор функций: tid, uid, ppfunc. Как раз здесь вызывается функция создания отступа, рассмотренна ранее local_depth.

Входные параметры функций:

  1. имя которое будет выведено вначале и при анализе может понадобится для фильтрации,
  2. список переменных локальных
  3. идентификатор, присвоенный функции программы(не проба), при входе в нее.

Идентификатор - это число одинаковое для входа функции и выхода из нее. Т.к. вход и выход могут быть не сразу друг за другом, по идентификатору можно будет определить когда был произведен вход. Даже если функция вызывалась рекурсивно.

3 Функция погружения и выхода из подпрограммы:

function work_depth_push(){
    #fn = sprintf("%s", ppfunc())
    foreach (val in skip){
        if(is_current_function(skip[val])==0) return 0
    }
    s_tid = tid()
    if (!@defined( depth[s_tid])) {
        depth[s_tid] = 0
    }
    cnt = counter++
    names[s_tid, depth[s_tid]++] = cnt
    return cnt
}

function work_depth_pop(){
    foreach (val in skip){
        if(is_current_function(skip[val])==0) return 0
    }
    s_tid = tid()
    if (!@defined( depth[s_tid])) {
        depth[s_tid] = 0
    }
    cnt = 0
    if (depth[s_tid] > 0 ) {
        cnt = names[s_tid, depth[s_tid]-1]
        delete names[s_tid, --depth[s_tid]]
    }
    return cnt
}

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

В начале этих двух функций вызывается is_current_function, которая проверяет, является ли текущее место тем которое нужно игнорировать. Список игнорирования - это skip.

Сведения о погруженных функциях и идентификаторе сохранются в массив names[tid, number].

4 Сами probes, которые говорят куда наша программка должна встроиться:

probe process("*").function("*").call {
    fid = work_depth_push()
    if (fid==0) next
    vrs = sprintf("%s", $$vars)
    ap_name = sprintf("%7s", execname())
    out_info(ap_name, vrs, fid)
}

probe process("*").function("*").return {
    fid = work_depth_pop()
    if (fid==0) next
    vrs = sprintf("%s", $$return)
    ap_name = sprintf("%7s", execname())
    out_info_return(ap_name, vrs, fid)
}

Мы прикрепляемся ко всем процессам, ко всем вызовам функций, а так же к результату возвращаемому функциями - это методы .call и .reurn. В самих в начале для проверки и подготовки данных вызываются work_depth_push и work_depth_pop. Если идентификатор не...

]]>
SystemTap - часть 3. Напишем свой probe https://putey.net/post/systemtap-chastj-3-napishem-svoj-probe 2017-03-05T02:12:00+03:00 2017-03-05T02:12:00+03:00

Задача для проба: написать пробы которые бы отслеживали посланный от процесса к процессу сигнал в CentOS 7, вывод обеспечит в двух строках: 1 - кто послал кому послал и какой сигнал, 2 - кто принял. И вывод бактрейса хендлера принявшего сигнал.

Первым делом я посетил вот этот перечень готовых функций: https://sourceware.org/systemtap/tapsets/signal.stp.html

Он содержит все необходимы для реализации программы функции: signal.send+ и signal.handle+

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

Ибо инструкция гласит, что:

тип элементов массива в SystemTap определяется типом первого записанного в массив элемента.

Вот проб для сохранения сведений при посылке сигнала. В проб добавлены дополнительные проверки:

probe signal.send {
    #флажок того, что pid процесса, посылающего сигнал не находится в списке исключений
    found_excluded_pid = 0
    #перебираем массив с pid исключениями, если находим, то взводим флажок = 1
    foreach(cnt in filter_epid){
        if (pid()==filter_epid[cnt]){
            found_excluded_pid = 1
            break
        }
    }
    #если флажок не 1, то pid не исключен
    if (found_excluded_pid == 0) {
    # проверим, а не задан ли единственный pid для отслеживания, полезен при режиме -x или когда известен pid
        if (filter_pid == 0 || ((filter_pid != 0) && (pid() == filter_pid))){
    #и проверим, а случайно не задан ли фильтр для номера сигнала, может нам нужно следить только за одним сигналом
            if (filter_sig == 0 || ((filter_sig != 0) && (sig == filter_sig))){
    #проверки пройдены, начинаем сохранять, используем для сохранения глобальный счетчик, он будет ключем массива,
    # так как возможно мы не успеем обработать массив, когда в него от этого же процесса попадет другой сигнал и данные перезатруться
                sc = signal_counter++
                si_cn[sig_pid, sig, sc]=sc
    # каждый параметр уходит в свой массив, неудобно, но проще метода пока не нашел
                si_sn[sc] = sig_name #имя сигнала
                si_sp[sc] = sig_pid #pid кому сигнал посылается
                si_pp[sc] = pid() #pid посылателя сигнала
                si_pn[sc] = pid_name #имя процесса кому сигнал посылается
                si_en[sc] = execname() #имя процесса посылателя
                si_ppf[sc] = ppfunc() 
                si_ppf2[sc] = sprint_ubacktrace()
                si_gc[sc] = gettimeofday_ns()
            }
        }
    }
}

Все идентификаторы функции описаны по адресу. Т.к это не target переменные, то знак $ перед ними не ставится. Т.е так и пишется sig_name, sig_pid и т.д

Теперь опишем принимающий проб, вот он должен и выводить данные накопленные в массиве и добавлять свои:

probe signal.handle {
   #пройдемся по массиву хранящему pid и уникальный ключ, ранее описанный глобальный счетчик
   foreach([f_pid, sig_f, sc] in si_cn){
   #если pid совпал, то берем счетчик, здесь хочу сказать, если посылающий процесс успеет напосылать сигналов
   #то подхватится первый попавшийся счетчик для обработчика сигнала
       if ((pid() == f_pid) && (sig_f == sig)){
   #выводим первую строку с бактрейсом, если он необходим
           printf("[%d] Signal %s was send by %s/%d to %s/%d\n", 
                   si_pp[sc], si_sn[sc], si_en[sc], si_pp[sc],
                   execname(), pid())
            if (output_info...
]]>
SystemTap - часть 2 https://putey.net/post/systemtap-chastj-2 2017-03-01T02:08:00+03:00 2017-03-01T02:08:00+03:00 Я сразу приведу список статей на которые опирался, при проведении дальнейших экпериментов:

  1. Using System Tap to test the GNU C Library
  2. Стандартные утилиты для UNIX-программиста

Список макроопределений systemtap:

Название Описание
$$vars Expands to a character string that is equivalent to sprintf("parm1=%x ... parmN=%x var1=%x ... varN=%x", parm1, ..., parmN, var1, ..., varN) for each variable in scope at the probe point. Some values may be printed as “=?” if their run-time location cannot be found.
$$locals Expands to a subset of $$vars containing only the local variables.
$$parms Expands to a subset of $$vars containing only the function parameters.
$$return Is available in return probes only. It expands to a string that is equivalent to sprintf("return=%x", $return) if the probed function has a return value, or else an empty string

Продолжу...

И так мы имеем программу memory, давайте отследим, сколько раз в ней вызывается malloc функция:

  1. Найдем сведения о фнукции malloc, необходимы для systemtap 1.1 Анализируем бинарник утилитой nm
    [probes]# nm ./memory | grep malloc
                 U malloc@@GLIBC_2.2.5

    Это нам говорит, что символ не определен U, значит он из библиотеки. 1.2 Проверим список библиотек утилитой ldd:

    [probes]# ldd ./memory
    linux-vdso.so.1 =>  (0x00007fff1fde4000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f900d6d4000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f900daaf000)

    Функция скорее всего в /lib64/libc.so.6 1.3 проверим это утилитой nm опять, но уже на файл библиотеки:

    [probes]# nm /lib64/libc.so.6 | grep malloc
    ...
    000000000007ff70 T __libc_malloc
    000000000007ff70 T malloc
    000000000007ff70 t __malloc

    Теперь то что нужно, T или t

  2. Значит дочтавляем debuginfo для glibc yum install glibc-debuginfo. И прогоняем вот такую команду:
    [probes]# stap -L 'process("/lib64/libc.so.6").statement("*malloc*")'
    process("/usr/lib64/libc-2.17.so").statement("__libc_malloc@/usr/src/debug/glibc-2.17-c758a686/malloc/malloc.c:2881") $bytes:size_t

    Вот первая попавшаяса функция, та что нам нужна, и информация о параметре - имя и размерность $bytes:size_t. Допишем наш проб, чтоб он выводил, что-нибудь при вызове функции malloc и выдавал, что она возвращает и самое интересное, где именно.

Немного покопавшись с кодом malloc.c, и поэкспериментировав с process("/lib64/libc.so.6").function("__libc_malloc"), я обнаружил, что она вызывается дважды. Поэтому в результирующем пробе, я поставил точку проверки на _int_malloc и на free:

#! /usr/bin/env stap

probe process("./memory").begin {
    printf("Test process started %d\n", pid())
}

probe process("./memory").end {
    printf("Test process ended %d\n", pid())
}

probe process("/lib64/libc.so.6").function("_int_malloc"){
    printf("%s:%s malloc called with param %d\n", pp(), ppfunc(), $bytes)
}

probe process("/lib64/libc.so.6").function("_int_malloc").return{
    printf("malloc returned %p\n", $return)
}

probe process("/lib64/libc.so.6").function("free"){
    printf("free called with param %p\n", $mem)
}

probe begin {
    printf("Waiting for even or Ctrl+C\n")
}

И работа программы:

[probes]# stap malloc.stp -c "./memory"
Waiting for even or Ctrl+C
Test process started 6231
process("/usr/lib64/libc-2.17.so").function("_int_malloc@/usr/src/debug/glibc-2.17-c758a686/malloc/malloc.c:3308"):_int_malloc malloc called with param 1024
malloc returned 0x767010
free called with param 0x767010
Test process ended 6231

А теперь промоделируем ситуация, когда malloc возвращает NULL:

#! /usr/bin/env stap

probe process("./memory").begin {
    printf("Test process started %d\n", pid())
}

probe process("./memory").end {
    printf("Test process ended %d\n", pid())
}

probe process("/lib64/libc.so.6").function("_int_malloc"){
    printf("%s:%s malloc called with param %d\n", pp(), ppfunc(), $bytes)
}

probe process("/lib64/libc.so.6").function("_int_malloc").return{
    $return = 0
}

probe process("/lib64/libc.so.6").function("free"){
    printf("free called with param %p\n", $mem)
}

probe begin {
    printf("Waiting for even or Ctrl+C\n")
}

В пробе probe process("/lib64/libc.so.6").function("_int_malloc").return я перезаписал возвращаемое значение в 0 функцией $return = 0 и...

]]>
Эксперименты с rr https://putey.net/post/eksperimenty-s-rr 2017-02-27T01:08:00+03:00 2017-02-27T01:08:00+03:00 rr - легковесная утилитка для записи и проигрывания выполняющегося процесса. Ооочень полезна при отладке, хотя и имеет ряд ограничений.

С ее помощью весьма неплохо записывался php процесс, с чилдами и родителем. А вот MySQL записаться не смог.

Не буду перенабирать примеры использования утилиты снова, приведу здесь ссылку на мою статью в Wiki где подробно рассмотрены различные варианты использования утилиты с разбором вывода.

Статья расположена по ссылке: http://docs.putey.net/ru/repolistrr

Список рассмотренных экспериментов с rr:

  • Эксперимент 1 - программа с ошибками
  • Эксперимент 2 - программа с разделяемой памятью
  • Эксперимент 3 - соединение с базой данных
  • Эксперимент 4 - запись в файл
  • Эксперимент 5 - работа с семафорами
  • Эксперимент 1 - программа с ошибками
]]>
SystemTap - часть 1 https://putey.net/post/systemtap-chastj-1 2017-02-26T17:30:00+03:00 2017-02-26T17:30:00+03:00

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

И так, что такое systemtap?

SystemTap — это средство, которое позволяет собирать и анализировать информацию о работающей Linux системе. В отличие от встроенных средств, таких как netstat, ps, top, SystemTap был разработан с целью предоставить больше возможностей для сбора и представления информации.

SystemTap представляет из себя интерфейс командной строки и скриптовый язык программирования.

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

В разработке проекта SystemTap участвуют такие компании как Red Hat, IBM, Oracle Corporation, Hitachi.

Установка на CentOS 7

Воспользовавшись командами из мануала, получаю:

yum install systemtap systemtap-runtime
stap-prep

скажу лишь, то что имел вот такие подключенные репозитории на машине:

repo id repo name
!base/7/x86_64 CentOS-7 - Base
!base-debuginfo/x86_64 CentOS-7 - Debuginfo
!epel/x86_64 Extra Packages for Enterprise Linux 7 - x86_64
!epel-debuginfo/x86_64 Extra Packages for Enterprise Linux 7 - x86_64 - Debug
!home_bayrepo home:bayrepo (CentOS_7)
!extras/7/x86_64 CentOS-7 - Extras
!updates/7/x86_64 CentOS-7 - Updates

Все прошло без особых проблем, все поставилось без дополнительных нареканий.

Инстукция, grep CONFIG_UPROBES /boot/config-$(uname -r) показала: CONFIG_UPROBES=y

Проверка тестовой программки:

[~]# stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}'
Pass 1: parsed user script and 123 library scripts using 227624virt/40728res/3260shr/37660data kb, in 400usr/20sys/732real ms.
Pass 2: analyzed script: 1 probe, 1 function, 4 embeds, 0 globals using 359016virt/173172res/4464shr/169052data kb, in 1830usr/450sys/5222real ms.
Pass 3: using cached /root/.systemtap/cache/ab/stap_ab882d45e2b778be682005a486a8a6be_1675.c
Pass 4: using cached /root/.systemtap/cache/ab/stap_ab882d45e2b778be682005a486a8a6be_1675.ko
Pass 5: starting run.
read performed
Pass 5: run completed in 10usr/50sys/617real ms.

Первая программа

Пример первой программы взят из учебника SystemTap по синтаксису языка. Ниже приведен код программы размещенный в файле first.stp:

1-й вариант:

probe begin {
printf("%d, %s\n", $1, @2)
exit()
}

2-й вариант с точкой с запятой после каждой строки, как в Си:

probe begin {
printf("%d, %s\n", $1, @2);
exit();
}

3-й вариант в одну строку:

probe begin { printf("%d, %s\n", $1, @2); exit(); }

Далее выполняем:

[probes]# stap first.stp "5+5" mystring
10, mystring

Из примера видно, что для обращения к агругментам командной строки необходимо использовать литералы: $1, $2, $3 ... $N для приведения к целому, в нашем случае "5+5" трактуется как int и @1, @2 ... для приведения к строке. В нашем случае это "mystring". Из примера видно, что литералы можно смешивать, т.е $1, @2, $3. Если обратиться к несуществующему аргументу, то возникнет ошибка.

stap преобразует stp код в С и компилирует его. С результатом промежуточным преобразования можно ознакомиться, запустив команду с параметром -k - stap -k first.stp "5+5" mystring

В первую очередь хотелось бы описать userspace probing

Начнем с того, что systemtap позволяет работать как с функциями ядра, так и с userspace. Задокументирую в первую очередь userspace, как более понятную для меня область.

Описание синтаксиса я приводить не буду, при желании его легко выудить из...

]]>