среда, 26 февраля 2014 г.

SIGILL при переходе на следующую строчку после breakpoint в GDB на Android

В случае если вам хочется обойтись без Eclipse/Android Studio и прочих IDE для отладки вашего приложения для Андройда, то можно воспользоваться обычным GDB из NDK. Если вы просто подключаетесь к gdbserver'у из этого обычного GDB, то может возникнуть следующая ошибка: 

(gdb) b f_close 
Breakpoint 1 at 0x5c309018: file api/test.c, line 359.
(gdb) c
Continuing.
[New Thread 24337]
[Switching to Thread 24337]

Breakpoint 1, f_close () at api/test.c:359
359     int err = 0;
(gdb) n

Program received signal SIGILL, Illegal instruction.


Если после этого продолжить выполнение, то программа упадёт по сигналу SIGILL или SIGSEGV. В NDK есть специальный скрипт - ndk-gdb, который запускает gdbserver и делает ещё кучу других вещей. В том числе он исправляет эту проблему.

Решение


Загрузите с вашего Андройд-устройства следующие файлы:

* /system/lib/libc.so
* /system/bin/app_process
* /system/bin/linker
И поместите их в папку с вашими бинарниками на хосте (например ./obj/local/armeabi/). После этого воспользуйтесь следующими командами для подключения к gdbserver'у:


file obj/local/armeabi/app_process
target remote :5039
set solib-search-path obj/local/armeabi/

Убедитесь что бинарники подгрузились с помощью команд info sharedlibrary и info file.

Теперь можно пошагово выполнять приложение без проблем!

четверг, 31 января 2013 г.

Android glxinfo

Под катом находятся исходники простой утилиты, выводящей информацию об OpenGL в Android 4.

Обратите внимание что код расчитан на компиляцию системой сборки Android (вам понадобятся исходники платформы чтобы собрать). Я не пробовал собирать с помощью NDK.

Например она выводит следуюущую информацию, если запущена на PandaBoard Rev.B ES:
EGL version 1.4
EGL_VERSION = 1.4 Android META-EGL
EGL_VENDOR = Android
EGL_EXTENSIONS = EGL_KHR_image EGL_KHR_image_base EGL_KHR_image_base 
EGL_KHR_gl_texture_2D_image EGL_KHR_gl_texture_cubemap_image EGL_KHR_gl_renderbuffer_image 
EGL_KHR_fence_sync EGL_ANDROID_image_native_buffer EGL_ANDROID_image_native_buffer
EGL_CLIENT_APIS = OpenGL ES
На эмуляторе Android 4.0:
EGL version 1.4
EGL_VERSION = 1.4 Android META-EGL
EGL_VENDOR = Android
EGL_EXTENSIONS = EGL_KHR_image EGL_KHR_image_base EGL_KHR_image_pixmap 
EGL_KHR_gl_texture_2D_image EGL_KHR_gl_texture_cubemap_image EGL_KHR_gl_renderbuffer_image 
EGL_KHR_fence_sync EGL_ANDROID_image_native_buffer EGL_ANDROID_swap_rectangle 
EGL_NV_system_time
EGL_CLIENT_APIS = OpenGL ES

вторник, 1 января 2013 г.

Пример перехвата сетевого траффика с помощью Raw Sockets

Иногда бывает необходимость в получении сырых данных поступающих на сетевой интерфейс. Один из вариантов решения задачи — создать сетевой драйвер использующий интерфейсы netfilter. Хотя этот вариант будет иметь наибольшую производительность, существует более простой путь с точки зрения реализации. Для этого не надо писать никаких драйверов, достаточно просто открыть Raw Socket (сырой сокет) в программе рижима пользователя.

Ниже приведён пример программы, печатающей на экран весь входящий трафик:


#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <linux/if_ether.h> // ETH_P_ALL
#include <linux/if_packet.h> // sockaddr_ll

int main(int argc, char **argv)
{
    int s;
    struct sockaddr_in src_addr;
    char packet[50] = {0};
    struct sockaddr_ll    sll = {0};

    if ((s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) < 0) { // (1)
        perror("socket");
        return -1;
    }

    sll.sll_family        = AF_PACKET;
    sll.sll_ifindex        = 3; // Interface index (2)
    sll.sll_protocol    = htons(ETH_P_ALL);

    if( bind(s, (struct sockaddr *) &sll, sizeof(sll)) == -1 ) {
        perror("bind");
    }

    socklen_t *len = (socklen_t *)sizeof(src_addr);
    int fromlen = sizeof(src_addr);

    while(1) {
        if (recvfrom(s, &packet, sizeof(packet), 0,
                    (struct sockaddr *)&src_addr, &fromlen) < 0)
            perror("recvfrom");

        int i = sizeof(struct iphdr); // print the payload

        for(; i < sizeof(packet); i++) {
            printf("%02X ", (unsigned char) packet[i]);
        }

        printf("\n");
    }
    return 0;
}
 

Комментарии:

  1. Чтобы открыть сырой сокет, необходимы права суперпользователя. 
  2. Номер интерфейса можно получить в том числе командой "ip addr sh"
Код тестировался на Ubuntu 12.04 x64

Ссылки:

  1. Код основан на примере из ответа на stackoverflow . Оригинальный код у меня не заработал и я его немного изменил.
  2.  libpcap использует этот-же механизм для перехвата траффика (pcap-linux.c/activate_new()). Эту библиотеку используют такие популярные утилиты как tcpdump и wireshark.

пятница, 7 сентября 2012 г.

Управление демонами в Android

Во время загрузки андройда процесс init запускает целый ряд "демонов", описанных в файле /init.rc. Демоны отличаются от обычных линуксовых процессов только тем, что за ними следит  init -- он может их перезапускать в случае гибели, а так же запускать/останавливать по команде пользователя. Команды выглядят вот так:
# setprop ctl.start $SERVICENAME $ARGS
# setprop ctl.stop $SERVICENAME
# setprop ctl.restart $SERVICENAME
Где $SERVICENAME это имя демона, определённое в файле init.rc. $ARGS это аргументы, которые будут переданы запускаемому процессу.
Например, при запущенном эмуляторе можно сделать так:
adb shell setprop ctl.restart ril-daemon
Это команда перезапустит демон radio interface layer.

Ссылки


среда, 7 декабря 2011 г.

Как получить список изменённых файлов в Linux

Предположим у нас есть папка с исходным набором файлов ${ORIG} и рабочая папка ${ORIG_WITH_CHANGES}, в которую изначально были скопированы файлы из ${ORIG} и произведены некоторые изменения. Задача состоит в том, чтобы получить третью папку ${CHANGES}, которая содержала бы только изменённые файлы с сохранением структуры папок.

Добиться поставленной задачи нам поможет команда rsync:

rsync --progress --exclude out -a -c \
        --compare-dest=${ORIG} ${ORIG_WITH_CHANGES} ${CHANGES} 
cd ${CHANGES} 
find -depth -type d -empty -delete
find . -name .git -print0 | xargs -0 rm -rf

Использованные параметры команды rsync:
--progress: с этим ключём rsync печатает список обработанных файлов во время работы
--exclude out: игнорировать папку out
-a: включает архивный режим. Это сокращение к следующей комбинации ключей: -rlptgoD
-с: игнорировать время изменения и проверять изменился ли файл, сравнивая его побитно с оригиналом.
--compare-dest=${ORIG}: по умолчанию rsync первый раз скопирует все файлы в папку ${CHANGES}. Нам же нужны только изменённые по сравнению с оригиналом. Эта опция включает сравнение с оригиналом

Первая строка  создаёт искомую директорию, но помимо изменённых файлов, она ещё хранит кучу пустых папок. Следующие две команды очищают ${CHANGES} от пустых папок и удаляют все папки с названием ".git".

Эта заметка основана на ответах к моему вопросу на unix.stackexchange.com.

вторник, 6 декабря 2011 г.

Автоматическая пересборка проекта при изменении файлов

Данная задача актуальна в первую очередь вэб-проектам — в данном случае сборка обычно заключается в быстром препроцессинге и копировании файлов, так что хочется чтобы она происходила постоянно при каждом изменении файлов. В Django например подобная функциональность встроена в его вэб-сервер, который следит за изменениями файлов в проекте и перезапускает сам себя, если таковые обнаружит. Если же, как в моём случае, никакого django не используется, а применяется простой GNU Make, приходится прибегать к встроенной возможности ОС Linux — инструменту inotify.

Итак, если вы используете Ubuntu, надо установить пакет inotify-tools — оттуда нам понадобится утилита inotifywait. Получается вот такой Makefile:

.PHONY: watch ❶

all:
    echo "Make all called!"

watch:
    while inotifywait -e modify -r ../ \
        --exclude "(\./build/.*|.*\.swp)" ; \
    do make -C $(CURDIR); done # Call this Makefile again with default target
  1. Отмечаем нашу цель как .PHONY — это значит что она не создаёт никаких файлов и будет выполнена в любом случае (даже если файл watch уже существует)
  2. Конкретно в нашей целе мы бесконечно ждём события modify в папке уровнем выше, за исключением папки "build" (в ней находится этот Makefile) и файлов с расширением .swp (их создаёт редактор Vim  и постоянно обновляет, при каждом введённом символе).
    Если это событие наступает, мы воплняем цель по умолчанию из этого же Makefile (по умолчанию это цель all)
Похожий вопрос на Superuser.com.

вторник, 22 ноября 2011 г.

Отладка приложений в Android с помощью gdbserver

Это руководство может быть полезным тем, кто собрал на своей машине платформу Android, запустил её на устройстве/эмуляторе и хочет отлаживать на ней родные приложения. Необходимость собственноручной компиляции андройда обусловлена тем, что в процессе сборки генерируются отладочные символы для всех исполняемых файлов и библиотек. Они складываются в директорию out/target/product/generic/symbols/*. Подцепив эти символы в GDB можно отлаживать любые системные сервисы/приложения/библиотеки.
adb shell gdbserver :5039 --attach 2055 & ❶

adb forward "tcp:5039" "tcp:5039" ❷
${CROSS_COMPILE}gdb ❸
(gdb) target remote :5039 ❹
(gdb) set solib-search-path out/target/product/generic/symbols/system/lib ❺
(gdb) info sharedlibrary ❻
  1. Запускаем gdbserver на порту 5039. Параметр --attach заставляет его подключиться к запущенному процессу с PID = 2055. Чтобы узнать PID подопытного процесса, пишем "adb shell ps"
  2. Перебрасываем порт 5039 на устройстве на локальный порт компьютера, с которого производятся команды
  3. Запускаем gdb. Переменная CROSS_COMPILE должна указывать на gdb для архитектуры целевого устройства (обычно это ARM). Нужный нам gdb можно найти в папке $DROID/prebuilt/linux-x86/toolchain/arm-eabi*
  4. Теперь выполняем команду GDB -- просим его подключиться к локальному порту 5039 (подключение подхватит ADB и соединит нас с портом 5039 устройства, на котором висит gdbserver)
  5. Указываем папку, где можно взять отладочные символы. В нашем случае они указаны только для динамических библиотек. 
  6. Последняя команда загружает символы. На этом этапе мы готовы к работе. Пишем continue и/или ставим brakepoints!

понедельник, 31 октября 2011 г.

Отладка сервисов в Android

Чтобы Eclipse начал останавливаться в точках останова, надо перед такой точкой вставить следующую строку:
android.os.Debug.waitForDebugger();

Так же в манифесте надо прописать android:debuggable="true"

среда, 26 октября 2011 г.

Ошибка cmake/make в Windows: *** target pattern contains no `%'. Stop.

Во время сборки проекта, используя cmake на Windows можно наткнутся на такую проблему:
 *** target pattern contains no `%'. Stop. 


Ошибка возникает в GNU Make 3.81 установленным через Cygwin. Проблема вызвана некорректной работой make (подробности), причём проблема эта была поправлена ещё в далёком 2008, но до сих пор по-умолчанию cygwin ставит именно неработающую версию.

Решение

  1. Исправленную версию make скачиваем тут: http://www.cmake.org/files/cygwin/make.exe 
  2. Копируем скачанный файл в C:\cygwin\bin. 
  3. Переименовываем или создаём ссылку для файла cygintl-8.dll -> cygintl-3.dll всё в той же директории c:\cygwin\bin