Вглубь синтетических джунглей файловой системы sysfs в Linux



8 коммент.
Файловая система /sys в Linux отличается от /proc тем, что предоставляет детализированную информацию о работе ядра пользователю (например, параметры устройств и загруженных модулей). Информация строго организована и обычно форматируются простом ASCII тексте, что делает её очень доступной для пользователей и приложений. Так что можно занять шаловливые ручонки чем-нибудь полезным, вроде дёргания разных крутилок в /sys и подсматриванием в системные переменные. Далее - немного подробностей о синтетических джунглях файловой системы /sys.


Зачем нужна /sys, когда есть /proc? 

Основной лейтмотив создания /sys было навести некоторый порядок в том бардаке, который являет из себя /proc и выделить информацию о структурах ядра в отдельную директорию.

Sysfs это
файловая система, находящаяся в памяти (in-memory), основана первоначально на Ramfs, которая в свою очередь была написана во время перехода на ядро 2.4.0. Как говорит один из авторов [1], ``это было упражнение в элегантности, имевшее целью показать, насколько легко написать простую файловую систему, если использовать новый на тот момент слой VFS''. Из-за простоты и использования VFS, это дало здоровую основу для создания других in-memory файловых систем.

При этом sysfs может быть смонтирована, как и любая другая файловая система из пространства пользователя. Большинство дистрибутивов делают это автоматически при старте системы, добавляя соотвутствующую строчку в /etc/fstab.


Что внутри /sys?
Sysfs является каналом распространения информации между ядром и пространством пользователя. Например, есть возможность смены планировщика ввода/вывода или изменения параметров Udev программы. В каталоге /sys находится несколько подкаталогов, представляющих ряд основных подсистем, которые зарегистрированы в Sysfs:
/sys/
|-- block
|-- bus
|-- class
|-- devices
|-- firmware
|-- module
‘-- power


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

Зайдя туда, мы обнаруживаем кучу блочных устройств, среди которых можно найти рабочий винчестер, подключённые флешки и внешние жёсткие диски. Вот что автор этих строк нашёл про свой жёсткий диск, на котором установлен евонный Дебиан:

notebeast:/sys/block/hda# ls -l
итого 0
-r--r--r-- 1 root root 4096 2012-03-03 22:05 capability
-r--r--r-- 1 root root 4096 2012-03-03 22:05 dev
lrwxrwxrwx 1 root root 0 2012-03-03 22:05 device -> ../../devices/pci0000:00/0000:00:1f.1/ide0/0.0
drwxr-xr-x 3 root root 0 2012-03-03 22:05 hda1
drwxr-xr-x 3 root root 0 2012-03-03 22:05 hda2
drwxr-xr-x 2 root root 0 2012-03-03 18:40 holders
drwxr-xr-x 3 root root 0 2012-03-03 22:05 queue
-r--r--r-- 1 root root 4096 2012-03-03 22:05 range
-r--r--r-- 1 root root 4096 2012-03-03 22:05 removable
-r--r--r-- 1 root root 4096 2012-03-03 22:05 size
drwxr-xr-x 2 root root 0 2012-03-03 18:40 slaves
-r--r--r-- 1 root root 4096 2012-03-03 22:05 stat
lrwxrwxrwx 1 root root 0 2012-03-03 22:05 subsystem -> ../../block
--w------- 1 root root 4096 2012-03-03 22:05 uevent
Отсюда мы узнаём, например, что диск /dev/hda разбит на две партиции, hda1 и hda2, размеры которых хранятся в size, что можно достучаться до планировщика I/O в queue   и собрать немножко статистики по работе жёсткого диска в stat. Заглянем туда в поисках приключений и чего-нибудь неизведанного.


Статистика ввода-вывода

Интерфейс /sys/block/sdX/stat даёт некоторые статистические данные о производительности ввода-вывода ядра. Эти данные пользователь или администратор может использовать для оптимизации производительности, если знает, что они значат.

Например, если дать команду:

# cat /sys/block/sda/stat
Мы увидим что-то типа:

186908 41568 6033917 2408504 91198 509600 4882200 9406764 0 1161304 11848624

Эти сакрально-литургические знаки означают следующее:

Поле 1 -- полное число запросов на чтение, выполненных успешно.


Поле 2 -- число объединённых запросов на чтение. Запросы на чтение и запись, примыкающие друг к другу, могут быть объединены для повышения эффективности. Таким образом, два 4K считывания может стать одним 8K считыванием перед тем, как в конечном итоге быть переданы диску. Поэтому запрос будет считаться одним, и это поле позволяет вам узнать, как часто это было сделано.

Поле 3 -- число считанных секторов, чтение которых прошло успешно. 

Поле 4 -- миллисекунд, потраченных на чтение. 

Поле 5 -- число запросов на запись, выполенных успешно.

Поле 6 -- число объединённых запросов на запись. Запросы на чтение и запись, примыкающие друг к другу, могут быть объединены для повышения эффективности. Таким образом, два 4K считывания может стать одним 8K считыванием перед тем, как в конечном итоге быть переданы диску. Поэтому запрос будет считаться одним, и это поле позволяет вам узнать, как часто это было сделано.

Поле 7 -- число секторов, записанных успешно.

Поле 8 -- миллисекунды, потраченные на запись.

Поле 9 -- число запросов ввода-вывода, активных в данный момент. Единственное поле, которое должно стремиться к нулю.

 Поле 10 -- миллисекунд, потраченных на выполнение запросов ввода-вывода. 

Поле 11 -- взвешенное количество миллисекунд, потраченных на ввод-вывод. Может использоваться как простая мера производительности ввода-вывода.




Смена планировщика ввода-вывода на лету

Как нам намекает документация, планировщик ввода-вывода может быть изменён в любое время на лету, хотя может быть небольшая задержка из-за того, что все запросы предыдущего планировщика должны быть обработаны прежде, чем запустится новый. Чтобы узнать, какой планировщик стоит сейчас, даём команду:
cat /sys/block/sdX/queue/scheduler
Заменяя sdX на интересующее нас устройство. Текущий планировщик отмечен в квадратных скобках:
noop anticipatory deadline [cfq]
То есть сейчас стоит cfq - Completely Fair Queuing, полностью честный планировщик. Планировщики для разных дисков могут быть:
  • noop часто наилучший выбор для файловых систем в памяти (например ramdisk) и других устройств без механических частей (флешек), где попытки оптимизировать ввод-вывод приводят лишь к напрасной трате ресурсов.
  • as (anticipatory) по воплощённым в нём идеях схож с deadline, но более навороченный и пытается оптимизировать ввод-вывод с упреждением. Удалён из ядер начиная с 2.6.33.
  • deadline лёгкий планировщик, который пытается установить жёсткий предел на задержки ввода-вывода.
  • cfq поддерживает честное распределение ввода-вывода между процессами, используя концепцию очередей (queue) для каждого процесса. CFQ разедляет синхронные и асинхронные операции ввода-вывода, отдавая предпочтение синхронным операциям. Грубо говоря, CFQ не допускает ситуации, когда один процесс начнёт создавать много операций ввода-вывода, другие процессы могут ``голодать''. Имеет несколько параметров настройки.
Выбор планировщика зависит от задач и оборудования (любопытные бенчмарки для SSD). Более того, у каждого планировщика, как правило, есть настраиваемые параметры. Некоторые соображения можно почерпнуть из поста по ссылке.

Сменить планировщик можно на лету:
# echo "deadline" > /sys/block/sda/queue/scheduler
После этого планировщик для данного диска будет изменён. 
 


И другие каталоги...
 Содержимое других каталогов будет интереснее разработчикам, а не пользователям, и может сильно меняться от версии ядра Linux.

/sys/bus
Это структура шин данных в системе, которая показывает, какая шина куда подключена (например, контроллер USB может быть подключен к шине PCI), и какие устройства в каждой шине потенциально может поддерживать (наряду с соответствующими драйверами), и какие устройства существуют. Здесь есть символической ссылки, которые указывают на директории устройства в глобальном дереве устройств. Каждый тип шины данных представлен двумя подкаталогами: устройств и драйверов.
   
/sys/class
Хранит все классы устройств, зарегистрированные ядром. Используется для описания функционального типа устройств. Большинство подкаталогов содержат символические ссылки на каталоги device и driver. Например, физическое устройство типа мышь может ссылаться на объект ядра "мышь", на устройство input event и input debug. Классы могут включать в себя диски, разделы, последовательные порты, и т.д.  

/sys/devices
Содержит глобальную иерархию устройств: каждое физическое устройство, которые было обнаружено и зарегистрировано ядром.

Например, автор этих строк нашёл:
/sys/devices/virtual/thermal/thermal_zone0/temp  
показания температуры на процессоре в ноутбуке. Исключений два - platform devices и system devices.

Platform devices это периферия (подключаемые устройства), присущие конкретной платформе (порты ввода-вывода, legacy-устройства типа последовательного контроллера или контроллера дискет [floppy controller]).

System devices это устройства, интергрированные в платформу, например аппаратные регистры для доступа к конфигурированию, которые не имеют возможностей обмениваться данными. Обычно для них нет драйверов (процессор, таймеры и другое).
   
/sys/firmware
Cодержит интерфейсы для просмотра и манипулирования firmware-специфичными объектами и их параметрами. Как правило, это платформо-зависимый код, который выполняется в системе при включении, например BIOS.  

/sys/module
Cодержит подкаталоги для каждого загруженного модуля ядра. Имя каталога отражает имя модуля. Ядро имеет глобальное пространство имён для всех модулей. Подкаталоги содержат параметры, специфичные для каждого загруженного модуля. Эта информация используется для отладки и простым смертным не будет интересна.  

/sys/power
Это скорее заделка на будущее. Может содержать название состояния, которое позволит процессу переходить в режим пониженного энергопотребления.
В зависимости от версии ядра, в /sys могут появляться и другие каталоги.


Ссылки
Есть любопытный документец [1] The sysfs Filesystem, OLS'05 на 14 страниц, написанная тем водянистым и пустозвонным стилем, коий так не переваривает автор этих строк. Документация к ядру тоже не особенно жаждет подробно рассказать о том, что означают все эти переменные и отгораживается вот этим:

TODO: Finish this section.
Понятно, что это самое туду не входит в приоритетный список дел. Но кое-что выудить всё-таки можно. Надеюсь, что этот пост несколько приподымет завесу тайны с файловой системы /sys.
Читать далее

Обзор редакторов для работы в ЛаТеХ: LaTeX Editors and Integrated LaTeX Environments



24 коммент.

Частый вопрос начинающих латехников: ну вот установили мы LaTeX, а как теперь со всем этим работать? Вопрос задают сравнительно часто, и подумалось мне, что неплохо бы всё это оформить в виде одного поста со скриншотами и сравнениями. Описание сред для работы с LaTeX идёт в порядке убывания возможностей программ.

Читать далее

Xournal - рукописные заметки и пометки в PDF файлах



9 коммент.

Наличие у вас графического планшета или ноутбука с экраном, чувствительным к нажатию, открывает широкие возможности для творчества: можно рисовать картины (почти как на бумаге), создавать чертежи в CAD-программах (планшет сильно облегчит работу) или делать рукописные заметки.

Читать далее

Продвинутые таблицы в ЛаТеХе: advanced tables in LaTeX



30 коммент.

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

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

Объединение строк и столбцов в таблицах LaTeX

Создание навороченных таблиц часто требует объединять столбцы и строки, особенно при группировке сходных данных. Для этого можно использовать команды \multicolumn и \multirow, а так же некоторые другие трюки, о которых ниже.

Напомню, что \multicolumn{2}{|c|}{Результаты измерений} означает, что мы объединяем 2 (два) столбца в таблице, получившаяся ячейка будет центрирована и нарисованы вертикальные линии.

Таблицы с объединением столбцов в LaTeX

Для того, чтобы несколько столбцов объединить в одну, можно воспользоваться командами \cline, \raisebox и \multicolumn одновременно. Здесь \multicolumn служит для объединения двух колонок в одну, \cline прочерчивает линию в строках, а \raisebox поднимает текст к середине объединённой строки.
Вот код таблицы:

\begin{table}[H]
\caption{\label{tab:bolts} Нестандартные болты для левой резьбы.}
\begin{center}
\begin{tabular}{|c|c|c|}
\hline
& \multicolumn{2}{c|}{Диаметр} \\
\cline{2-3}
\raisebox{1.5ex}[0cm][0cm]{Нестандартные болты}
& Норма & Разброс \\
\hline
Размеры & 10 мм & 1 мм \\
\hline
\end{tabular}
\end{center}
\end{table}

В документе это будет выглядеть так (обратите внимание на первую колонку):


Для этой таблицы использован трюк с \multicolumn для объединения двух ячеек в одну, \cline{2-3} для прочерчивания горизонтальной линии в таблице от второй колонки до третьей, и \raisebox для вставки надписи Нестандартные болты.


Таблицы с объединением строк в LaTeX

Если нужна таблица, в которой несколько строк объединены, можно использовать пакет multirow, добавив \usepackage{multirow} в преамбулу документа. Это позволит создать строки, простирающиеся на несколько колонок командой:
\multirow{объединить Х строк}{ширина}{содержимое}
Предыдущий пример можно переиначить вот так:

\begin{table}[H]
\caption{\label{tab:bolts} Нестандартные болты для левой резьбы.}
\begin{center}
\begin{tabular}{|c|c|c|}
\hline
\multirow{3}{*}{Размеры нестандартных болтов} & \multicolumn{2}{c|}{Диаметр} \\
\cline{2-3}
            & Норма & Разброс \\
\cline{2-3}
            & 10 мм & 1 мм \\
\hline
\end{tabular}
\end{center}
\end{table}

В документе такая таблица будет выглядеть так:



Объединение строк и столбцов вместе плюс использование hhline

Пример с texexchange, который мне нравится, иллюстрирует применение описанных выше команд:

\begin{table}[ph]
  \centering
  \begin{tabular}{c|c|c|c|c}
    \hline
    \multirow{2}{*}{Raaa (k)} & \multicolumn{4}{c}{C ()} \\
    \hhline{~----}
    & 3.3 & 2.5 & 1 & 0.5 \\
    \hline
    \multirow{2}{*}{Raaa (k)} & \multicolumn{2}{c|}{\multirow{2}{*}{this}} & 0.5 & 0.6\\
    \hhline{~~~--}            & \multicolumn{2}{c|}{}                      & 0.7 & 1.2 \\
    \hline
  \end{tabular}
  \caption{R, C ripple size}
  \label{T:peak}
\end{table}

В документе выглядит так:


Здесь нужно отметить применение команды \hhline из одноимённого пакета hhline, которая рисует линии в таблицах, подобно обычной \hline. Особенность \hhline в том, что можно прочерчивать невидимые линии (~) и обычные (-) вот так:
\hhline{~----}
В данном случае будет нарисовано пять линий в таблице, первая будет пустая. В общем это аналог \cline{2-5}, только более удобный.

Надеюсь, что с такими таблицами вы будете встречаться так же редко, как и с такими экзотическими болтами.


Раскраска ячеек таблиц в LaTeX

Кто сказал, что таблицы в LaTeX унылы и безжизненны? Хотя часто раскраска таблицы не одобряется, иногда, особенно в презентациях, выделение ячеек таблицы цветом помогает быстрее понять материал.
Для раскраски ячеек нам понадобятся пакеты
\usepackage{color,colortbl}
и в преамбуле определяем цвета, которые нам нужны:
\definecolor{darkishgreen}{RGB}{39,203,22}
\definecolor{LightCyan}{rgb}{0.88,1,1}
\definecolor{Gray}{gray}{0.9}
\definecolor{lightRed}{RGB}{230,170,150}
\definecolor{modRed}{RGB}{230,82,90}
\definecolor{strongRed}{RGB}{230,6,6}
Теперь нужно сделать отдельный тип цветных колонок для таблицы. Для этого в документе, уже после \begin{document}, создаём новые команды в виде:
\newcolumntype{g}{>{\columncolor{Gray}}c}
и
\newcolumntype{d}{>{\columncolor{darkishgreen}}c}
Это позволит нам раскрашивать колонки. Для раскраски строк воспользуемся командой \rowcolor{цвет} из пакета colortbl. Можно раскрасить отдельно ячейку с помощью команды \cellcolor{Gray} которую помещаем в раскрашиваемую ячейку.

А теперь всё вместе:

\newcolumntype{g}{>{\columncolor{Gray}}c}
\newcolumntype{d}{>{\columncolor{darkishgreen}}c}

\begin{tabular}{|c||c||g||d|d|d|}
    \hline
 Signal & \cellcolor{Gray} Device    & \multicolumn{4}{|c|}{Computation time, s}\\
\cline{3-6}
Strength    & \cellcolor{Gray}  size     &Dantzig-   &Branch and & Active    &Projected\\ 
        &       &Wolfe      &Bound      &Set        &Gradients\\ 
\rowcolor{lightRed}
\hline
Weak        & 7x7   &400        &230        &200        &58\\ \cline{3-6}
\rowcolor{lightRed}
(0\% constr.)    & 10x10 &1000       &840        &500        &135 \\ \cline{3-6}

\hline
\rowcolor{modRed}
Moderate    & 7x7   &640        &380        &270        &54\\ \cline{3-6}
\rowcolor{modRed}
(5\% constr.)    & 10x10 &3120       &1200       &700        &110 \\ \cline{3-6}

\hline
\rowcolor{strongRed}
Strong      & 7x7   &1400       &290        &350        &55\\  \cline{3-6}
\rowcolor{strongRed}
(20\% constr.)   & 10x10 &15320      &810        &960        &120 \\  \cline{3-6}
\hline \hline
    \end{tabular}

В документе такая таблица выглядит вот так:


Здесь ещё можно отметить использование || в качестве двойного разделителя колонок.




Изменение размеров строк и столбцов в ЛаТеХ таблице

Переменная \arraystretch отвечает за расстояние между строками а переменная \tabcolsep соответственно за расстояние между столбцами. В примере ниже мы сделаем столбцы и строки пошире:

\renewcommand{\arraystretch}{1.8} %% increase table row spacing
\renewcommand{\tabcolsep}{1cm}   %% increase table column spacing
\begin{center}
\begin{tabular}{|c|c|c|}
\hline
Расширение краёв: & \textbf{1,0-1,4} & размер ФРТ \\
\hline
Аподизация: & \textbf{0,25-0,30} & размер ФРТ \\ 
\hline
Сглаживания краёв: & \textbf{0,25-0,50}& размер ФРТ \\
\hline
\end{tabular}
\end{center}

В документе это будет выглядеть так:



Изменение высоты одной строки в таблице

Иногда требуется сделать одну из строк в таблице побольше, не задевая все остальные. Здесь поможет трюк с командой rule: команда вставит невидимую горизонтальную линию заданной ширины и толщины:
\rule[высота подъёма линейки]{ширина}{толщина}
Это не единственный манёвр, который позволяет увеличить расстояние между строками: можно в конце строки, после \\ вставить [1cm], увеличив размер строки соответственно.

В данном примере мы расширим первую строку в таблице с помощью \rule{0cm}{2cm} и вторую с помощью [1cm] следующим образом:

\begin{center}
\begin{tabular}{|c|c|c|}
\hline
\rule{0cm}{2cm}
Расширение краёв: & \textbf{1,0-1,4} & размер ФРТ \\
\hline
Аподизация: & \textbf{0,25-0,30} & размер ФРТ \\  [1cm]
\hline
Сглаживания краёв: & \textbf{0,25-0,50}& размер ФРТ \\
\hline
\end{tabular}
\end{center}
 
Так выглядит таблица в документе:


Ещё немного о трюках с таблицами можно почерпнуть там.




Книжные таблицы в LaTeX: booktabs

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

Если вам хочется набирать таблицы "как у больших дядь в книжках", можно воспользоваться пакетом booktabs. Подключив в преамбуле документа \usepackage{booktabs} мы сразу же имеем возможность набирать красивые таблицы.
"Большие дяди" стараются сделать таблицы проще, с комфортным для глаз расстояниями между строками, и почти никогда не используют вертикальные разделители.
Вот код для такой таблицы:

\begin{tabular}{llr}
\toprule     %%% верхняя линейка
\multicolumn{2}{c}{Постобработка} \
\cmidrule(r){1-2}
Вид & Описание & Время выполнения, сек. \
\midrule %%% тонкий разделитель 
Расширение краёв        & холодный старт & 12 \
                    & горячий старт &    8 \
Аподизация          & симметричная  & 90 \
Сглаживания краёв   & по Гауссу  & 33 \
\bottomrule %%% верхняя линейка
\end{tabular}
 
Вот как выглядит такая таблица:




Когда столбцов в таблице слишком много...

Чтобы проще было задавать число колонок таблицы, особенно если их много, можно использовать конструкцию вида \begin{tabular}{l*{X}{l}}, где X это число колонок.

Вот пример такой таблицы с 10 колонками:

\begin{tabular}{l*{10}{l}}
\hline
Расширение краёв:   &  1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
\hline
Аподизация:             & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
\hline
Сглаживания краёв:  & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9  \\
\hline
\end{tabular}

А вот как она выглядит в готовом документе:


Стоит отметить пакет siunitx, который предоставляет возможность  выравнивания по десятичной точке или запятой. Также можно посмотреть на пакет array, предоставляющий расширенные версии окружений tabular и array (например, вертикально центрированные колонки и возможность определять новые типы колонок).


Ссылки

Эти трюки позволят создать весьма навороченные таблицы без необходимости перечитывать томик квантовой физики.

Конечно, есть ещё много пакетов по работе с таблицами, например ltxtable - это longtable и tabularx, который стоит использовать для создания больших и сложных таблиц с разделением по страницам, с кучей текста в ячейках. Многостраничные таблицы так же может создавать пакет supertab.

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

Стоит ещё отметить хороший туториал по таблицам, который включает \multirow и \multicol. Поборники русского стиля оформления таблиц могут заинтересоваться постом по ссылке.
Читать далее

Новый 2013 год и подведение итогов 2012



6 коммент.
Очередной понедельничный пост, на сей раз новогодний. Решил подвести немного итогов года, оглянуться назад и почить на лаврах :-)

Как оно было?

Год выдался весьма плодотворным: было много конференций, узнал много нового, обновил парк ноутбуков и реализовал хрустальную мечту юности (Lenovo X201 Tablet).

В смысле постов - их было столько же, сколько и в предыдущем году. Стало больше гостевых постов, и это радостно: гостевые посты вносят свежую струю в блог, и так я узнаю много нового и интересного (и надеюсь, не только я).

Запущен в тестовом режиме Лунодром "Дебианити". Это совсем мелкие заметки на манжетах, ссылки и прочие наброски, не подходящие под формат записок. Итог моих экспериментов со scriptogr.am и markdown, а так же временное решение проблемы хранения мелких набросков под рукой (ещё один блог заводить не хочется, здесь публиковать рано или ни к чему, а пригодиться могут).

Теперь итоги. Посты были разные, и интересно взглянуть на то, что понравилось из написанного мне, и что - читателям.

Топ5 постов, которые нравятся мне

Есть посты, которые пишутся в формате "чтобы не забылось" - и это почти всё про LaTeX и Gnuplot, которыми я пользуюсь постоянно. Но есть и нечто особенное, что стоит много часов и дней усилий по сбору материала и выпиливанию подробностей. Итак, мой Топ-5 постов за этот год, которые мне нравятся.

Странное рождение и долгая жизнь UNIX

Пост года, во всяком случае для меня, и самый большой перевод с английского на русский. На перевод и утрясание копирайтов с IEEE ушло почти четыре дня, но результат того стоил. Хотя переводчик с меня не очень хороший, смысл, думаю, передать удалось. Пост важен с исторической точки зрения, дабы помнить, с чего всё начиналось.
Статистика: +31 Plus one, 27 Comments, 5977 Views.

Markdown - гаечный ключ для забивания треугольных болтов

После того, как я нашёл применение Markdown в качестве простого и быстрого генератора вложенных списков для LaTeX, он стал частью моего workflow. Но этому предшествовала переписка с iv_vl, которая, надо сказать, направила меня по ложному следу. Пост был написан после того, как я перепробовал массу опенсорсных сноповязалок и прочих велосипедов с квадратными колёсами :-)
Статистика: +24 Plus one, 33 Comments, 2699 Views.

Краткий обзор современных окружений рабочего стола

Несколько неожиданный для меня экспромт Vlsu, ставший отличным постом. Прекрасные иллюстрации, структура и описания, хотя самый первый вариант был вызывающе неполиткорректным :-) Тем не менее, пост более чем стоил усилий, на него потраченных - один из лучших постов этого года, и абсолютный лидер по количеству просмотров. Браво, Vlsu, снимаю шляпу.
Статистика: +25 Plus one, 72 Comments, 13020 Views.

Pomodoro: тайм-менеджмент, который работает

Pomodoro я использую уже больше года, и для меня это было большим прорывом в плане учёта и анализа собственной продуктивности. Позволяет делать больше без стахановских рывков и прочего ненужного героизма. Пост, один из самых подробных за этот год, писался долго и был сильно улучшен усилиями комментаторов.
Статистика: +28 Plus one, 26 Comments, 3991 Views.

Настольный Змей Горыныч

Один из наиболее информативных постов для меня лично - узнал много нового про multihead, хотя это стоило некоторых денег (купленные переходники, хотя и используются время от времени, но tripple-head на ноутбуке не вышел). Пост нравится своей структурированностью, которая стоила немалых усилий. Кроме того, один из немногих постов, почти полностью написанный в Markdown.
Статистика: +22 Plus one, 18 Comments, 2169 Views.



Топ5 постов, которые понравились читателям

Здесь я ориентировался по числу PlusOne и просмотрам. В комментариях можно отвести душу и привести свои списки, но здесь балом правит бездушная статистика.

Вскрытие 9В батарейки: в поисках батареек АААА

Написанный за час и почти не стоивший усилий, пост неожиданно понравился народу на Хабре и собрал больше всех ПлюсАдынов за этот год (почти полсотни). Все деньги, потраченные на его написание, с лихвой отбились кассовыми сборами с рекламы :-)
Статистика: +46 Plus one, 18 Comments, 5041 Views.

Странное рождение и долгая жизнь UNIX

Здесь наши симпатии совпадают - второй пост по плюсадинам. Кривизну перевода сильно выправил тов. Minoru, за что ему большое спасибо.
Статистика: +31 Plus one, 27 Comments, 5977 Views.

Краткий обзор современных окружений рабочего стола

Самый комментируемый и самый посещаемый пост года от Vlsu. Уже растащен на скриншоты, понаставлена куча ссылок и есть по крайней мере два репоста. Как говорится, признание к художнику приходит не тогда, когда его работы в первый раз выставят, а тогда, когда их в первый раз украдут :-)
Статистика: +25 Plus one, 72 Comments, 13020 Views.

Возможности настройки GRUB2 в Linux

Второй пост по числу просмотров в этом году, и не мой, а написанный Yamamaya. Очень подробный и насыщенный деталями, хотя это и было главным объектом критики ведущего. Тем не менее, пост информативный и второй по количеству просмотров за год.
Статистика: +24 Plus one, 29 Comments, 10591 Views.

Как редактировать в Vim без порчи и бибиканья

Снова гостевой пост, на этот раз от Pento, о текстовом редакторе, который пищит и всё портит. Несмотря на краткость и лаконичность, набрал почти 9000 просмотров и часто появляется в поисковых запросах о Vim.
Статистика: +6 Plus one, 38 Comments, 8480 Views.

И ещё немного статистики

Отбирать что-то лучшее всегда непросто, поэтому я приведу Топ5 самых посещаемых, самых комментируемых и собравших больше всех +1 постов, опубликованных в этом году. Ваше слово, товарищ Статистика!

Самые плюсадинистые


Название постаPlus oneCommentsViews
Вскрытие 9В батарейки: в поисках батареек АААА46185041
Странное рождение и долгая жизнь UNIX31275977
Pomodoro: тайм-менеджмент, который работает28263991
Краткий обзор современных окружений рабочего стола257213020
Возможности настройки GRUB2 в Linux242910591
Markdown - гаечный ключ для забивания24332699

 

Самые комментируемые

Название постаPlus oneCommentsViews
Краткий обзор современных окружений рабочего стола257213020
Вычислительный танк заряженный свободой: ThinkPad  15675854
Как редактировать в Vim без порчи и бибиканья6388480
Назад в мезозой к программным динозаврам 19372001
Markdown - гаечный ключ для забивания24332699
Консольный Mplayer: мощь без границ21333371

Самые просматриваемые


Название постаPlus oneCommentsViews
Краткий обзор современных окружений рабочего стола257213020
Возможности настройки GRUB2 в Linux242910591
Как редактировать в Vim без порчи и бибиканья6388480
Навигационные программы для Android6318227
Странное рождение и долгая жизнь UNIX31275977



Глядя в даль...

В следующем году будет... а, впрочем, кто его знает, что там будет. Много черновиков и идей, мало времени, много интересного. Приоткрывая пухлую папку черновиков, можно видеть наброски про латех, гнуплот, программирование на C и Матлаб, не очень много про железо, немного про ядро, пара забойных обзоров и ещё кое-что про Андроид. Ну и что там гостевые авторы понапишут. Кстати, ваши посты тоже тут могут засветиться - гостевые посты принимаются в любое время.


Открывая шампанское...

С новым годом Линукса на Десктопе! Чтоб никогда ничего не падало, чтоб фич было много, а багов - мало. Чтоб была свобода, Столлман, равенство и братство :-)

Ну и уж этот-то год точно станет Годом Линукса на Десктопе :-)
Читать далее

Декомпиляторы, или Что делать, если нужно восстановить исходники из бинарников?



19 коммент.
Проблема восстановления исходного кода из скомпилированных бинарников возникает сравнительно часто и протекает остро, с воем и рыданиями. Здесь нам, до некоторой степени, помогут замечательные программы-декомпиляторы, и в этом посте автор собрал свои скромные попытки выдрать исходники (или хотя бы намёки на них) из скомпилированных из С-шного кода бинарников.


Задача для декомпилятора бинарников, собранных из С кода:
Классический случай: один деятель на факультете написал на правильном ANSI C (и используя библиотеки BLAS и LAPACK) нужные и хорошие алгоритмы, и скомпилировал их в виде MEX-файлов для использования (это С-шный код, который можно вызывать из МАТЛАБ).

Но потом он повздорил с народом, разозлился и свалил в частную контору, унеся все исходники с собой. Документации нет. Копий исходников нет. Есть обрывки личной переписки и намёки в сопровождающих файлах на тип алгоритма. Вариант физического воздействия на автора тупыми тяжёлыми предметами не рассматривается.

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


Кратко: суть и сложность проблемы
Декомпилятор (Decompiler) пытается перевести скомпилированный бинарный файл обратно в некое подобие исходного кода. Качество выхлопа зависит от особенностей языка исходника:
  • Для C# или Java есть много декомпиляторов - байткод на java содержит  много информации. Это помогает восстанавливать декомпилятору исходник до состояния, пригодного к повторной компиляции.
  • Совершенно другая история с двоичными файлами, в которых, как правило, отладочной информации нет. Тем не менее, динамически связанные библиотеки функций, как правило, вызываются по имени. Часто, типы параметров библиотечных функций известны, и это может помочь до известных пределов. 
Декомпиляторы пытаются восстановить информацию, которая частично утрачена при компиляции в бинарный файл - в этом и заключается основная сложность.

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

Так что ответ на вопрос заголовка поста: "Обхватить голову руками и закричать #$@@@@@!" :-)


Программы для декомпилирования (decompilers) для C/C++
Декомпиляторов для C/C++ немного, и ниже список из наиболее работоспособных. Здесь нет разделения на опенсорс или Linux-only - для такого дела, как вскрытие исходников, можно (и нужно) поступиться своими светлыми идеалами и наступить на горло собственной песне.

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


Boomerang
Boomerang это C decompiler с открытыми исходами:
  • поддерживаемые бинарные форматы:  ELF  PE-COFF Mac-OS
  • платформы: Windows/Linux
  • поддерживаемые архитектуры: IA32 MIPS PPC
  • метод работы: поточный, есть жалкий графический интерфейс, лучше использовать CLI.
Весьма продвинутый набор алгоритмов анализа кода, что не удивительно - один из соавтором защитил на этом докторскую диссертацию [Michael James Van Emmerik, Static Single Assignment for Decompilation, Ph.D. thesis, the University of Queensland, Australia. PDF, mirror PDF].

Качество кода, выдаваемого декомпилятором:
  • Структурирование: очень хорошее
  • Переменные: хорошее
  • Типы данных: очень хорошее
Выдаваемое качество кода сильно варьируется: некоторые функции почти идеально восстановлены, хорошо видна структура кода и есть указание типа переменных. В других случаях функции сильно запутаны и их почти невозможно прочитать.

Программа всё ещё в состоянии бета-версии и для больших проектов не подходит. Скачать можно здесь.


RecStudio
Интерактивный декомпилятор RecStudio для С и (отчасти) С++, закрытая разработка:
  • поддерживаемые бинарные форматыELF  PE-COFF AOUT RAW PS-X
  • платформы: Windows/Linux/MacOS
  • поддерживаемые архитектуры: x86 (ia32) x86_64 Mips PowerPC mc68k
  • метод работы: поточный и интерактивный, есть графический интерфейс.
Использует продвинутый набор алгоритмов анализа (partial Single Static Assignment, SSA), хотя до сих пор (и это после 20 лет!) в стадии разработки. Качество кода, выдаваемого декомпилятором:
  • Структурирование: хорошее
  • Переменные: частично
  • Типы данных: частично или никак
Выдаваемое качетсво кода, как правило, хуже, чем у Boomerang, хотя обновлённый RecStudio более подробен.

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



dcc - DOS to C decompiler
Поточный декомпилятор Dcc, только ANSI C  и для exe-файлов, с открытым исходным кодом под GPL:
  • поддерживаемые бинарные форматыEXE/COM
  • платформы: Windows
  • поддерживаемые архитектуры: x86
  • метод работы: поточный.
Один из первых декомпиляторов вообще, и только под DOS. Сильная сторона - структурирование кода. Качество кода, выдаваемого декомпилятором:
  • Структурирование: хорошее
  • Переменные: частично
  • Типы данных: частично или никак
Разработка Cristina Cifuentes, которая защитила PhD в Queensland University of Technology  на этом деле [можно полистать, если что - C. Cifuentes, Reverse Compilation Techniques].

Скачать можно отсюда (на сайте университета).



Hex Rays - plugin для IDA Pro
На самом деле Hex Rays не является отдельной программой - это плагин-декомпилятор для IDA Pro. Комбинация продвинутых возможностей IDA Pro (это дизассемблер) и Hex Rays в качестве декомпилятора очень впечатляет, как и аэрокосмическая цена.
По причине закрытости продукта (нет даже демо-версии) и нереальной цены в этом разделе про Hex Rays больше ничего написано не будет.




Ходовые испытания в реальных условиях
Для начала попробуем декомпилировать что-нибудь совсем простенькое и написанное на ANSI C и с использованем библиотеки BLAS для векторых и матричных операций. Бинарный файл можно скачать здесь.



1. Простенький C-шный бинарник + BLAS
Собственно, код на C для перемножения матрицы и вектора (используется CBLAS). Исходник:


#include <stdio.h>
#include <cblas.h>

double m[] = {
  3, 1, 3,
  1, 5, 9,
  2, 6, 5
};

double x[] = {
  -1, -1, 1
};

double y[] = {
  0, 0, 0
};

int main(void)
{
  int i, j;

  for (i=0; i<3; ++i) {
    for (j=0; j<3; ++j) printf("%5.1f", m[i*3+j]);
    putchar('\n');
  }

  cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, m, 3, x, 1, 0.0, y, 1);


  for (i=0; i<3; ++i)  printf("%5.1f\n", y[i]);

  return 0;
}

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

Выхлоп Boomerang
У него много ключей и параметров, часть которых не знает даже официальная, скажем так, документация. Тем не менее, для ключа -Td (Use data-flow-based type analysis) мы имеем выхлоп в стиле дзен:

double y;
double m = 3.;

// address: 0x80484e4
int main(int argc, char **argv, char **envp) {
    void *local23;   // r28

    for(;;) {
        proc1();
    }
}

Скажем так, не слишком ободряюще. Ключ  -Tc (Use old constraint-based type analysis) выдаёт больше информации к размышлению:

char y[24];
long long m[9] = { 0x4008000000000000LL, 0x3ff0000000000000LL, 0x4008000000000000LL, 0x3ff0000000000000LL, 0x4014000000000000LL, 0x4022000000000000LL, 0x4000000000000000LL, 0x4018000000000000LL, 0x4014000000000000LL };

// address: 0x80484e4
int main(int argc, char **argv, char **envp) {
    int local10;   // r24
    int local13;   // r28
    int local14;   // r29
    int local15;   // r32
    int local2;   // m[r28 + 72]{60}
    int local3;   // r28{181}
    int local6;   // m[r28 + 72]{119}
    int local7;   // m[r28 + 72]{149}
    int local8;   // m[r28 + 76]{9}
    int local9;   // m[r28 + 76]{49}

    *(int*)(local13 - 4) = local14;
    *(int*)(local13 - 12) = 0;
    local3 = local13 - 84;
    if (*(int*)(local3 + 72) > 2) {
        *(int*)(local3 + 52) = 1;
        *(int*)(local3 + 48) = 0x8049868;
        *(long long*)(local3 + 40) = 0.;
        *(int*)(local3 + 36) = 1;
        *(int*)(local3 + 32) = 0x8049848;
        *(int*)(local3 + 28) = 3;
        *(int*)(local3 + 24) = 0x8049800;
        *(long long*)(local3 + 16) = 1.;
        *(int*)(local3 + 12) = 3;
        *(int*)(local3 + 8) = 3;
        *(int*)(local3 + 4) = 111;
        *(int*)local3 = 101;
        cblas_dgemv();
        local6 = 0;
        for(;;) {
            *(long long*)(local3 + 4) = y[0];
            *(int*)local3 = 0x80486b6;
            proc1();
            local7 = *(int*)(local3 + 72) + 1;
        }
    }
    local8 = 0;
    for(;;) {
        local10 = *(int*)(local3 + 72) + *(int*)(local3 + 72) + *(int*)(local3 + 72);
        local15 = m[local10];
        *(long long*)(local3 + 4) = local15;
        *(int*)local3 = 0x80486b0;
        proc1();
        local9 = *(int*)(local3 + 76) + 1;
    }
} 
 

Подробностей тут больше, и тут выловлен самый главный ключик - cblas_dgemv();    


Выхлоп RecStudio
Намного более обилен и представляет собой следующий поток сознания:


// Generated by Rec Studio 4 - build Oct 20 2012

_init()
{// addr = 0x08048398
    _unknown_ __ebx;                       // r1
    _unknown_ __ebp;                       // r6
    _unknown_ _t2;                         // _t2

    __esp = __esp - 4;
    L1();
    _pop(__ebx);
    if( *((intOrPtr*)(_t2 + 0x1414)) != 0) {
        __gmon_start__();
    }
    frame_dummy();
    __do_global_ctors_aux();
    _pop(__eax);
    return;
}

L080483A4()
{
    _unknown_ _t2;                         // _t2

    _pop(__ebx);
    if( *((intOrPtr*)(_t2 + 0x1414)) != 0) {
        __gmon_start__();
    }
    frame_dummy();
    __do_global_ctors_aux();
    _pop(__eax);
    _pop(__ebx);
    __esp = __ebp;
    _pop(__ebp);
    return;
}

__gmon_start__()
{// addr = 0x080483D8
    goto __imp____gmon_start__;
}

putchar()
{// addr = 0x080483E8
    goto __imp__putchar;
}

__libc_start_main()
{// addr = 0x080483F8
    goto __imp____libc_start_main;
}

cblas_dgemv()
{// addr = 0x08048408
    goto __imp__cblas_dgemv;
}

printf()
{// addr = 0x08048418
    goto __imp__printf;
}

_start(
    signed int __eax,                      // r0
    _unknown_ __edx                        // r3
)
{// addr = 0x08048430
    _unknown_ __ebx;                       // r1
    signed int _t5;                        // _t5
    _unknown_ _t6;                         // _t6
    _unknown_ _t10;                        // _t10

    __edx = __edx;
    _t4 = __eax;
    _pop(__esi);
    __ecx = __esp;
    __esp = __esp & 240;
    _push(__eax);
    _push(__esp);
    _push(__edx);
    _push(__libc_csu_fini);
    _push(__libc_csu_init);
    _push(__ecx);
    _push(_t10);
    _push(main);
    __libc_start_main();
    asm("hlt ");
    0;
    0;
    _push(0);
    _push(_t6);
    __esp = __esp - 4;
    if(completed.5982 != 0) {
    } else {
        _t4 = dtor_idx.5984;
        _t6 = ( &__DTOR_END__ -  &__DTOR_LIST__ >> 2) - 1;
        if(_t4 >= _t6) {
        } else {
            do {
                _t5 = _t4 + 1;
                dtor_idx.5984 = _t5;
                 *((intOrPtr*)(_t5 * 4 +  &__DTOR_LIST__))();
                _t4 = dtor_idx.5984;
            } while(_t4 < _t6);
        }
        completed.5982 = 1;
    }
    __esp = __esp + 4;
    _pop(__ebx);
    _pop(__ebp);
    return;
}

__do_global_dtors_aux(
    _unknown_ __esi                        // r5
)
{// addr = 0x08048460
    _unknown_ __ebx;                       // r1
    _unknown_ __ebp;                       // r6
    _unknown_ _t4;                         // _t4
    signed int _t5;                        // _t5
    signed int _t6;                        // _t6
    _unknown_ _t10;                        // _t10

    if(completed.5982 == 0) {
        _t5 = dtor_idx.5984;
        _t10 = ( &__DTOR_END__ -  &__DTOR_LIST__ >> 2) - 1;
        if(_t5 >= _t10) {
L4:
            completed.5982 = 1;
            return;
        }
        do {
            _t6 = _t5 + 1;
            dtor_idx.5984 = _t6;
             *((intOrPtr*)(_t6 * 4 +  &__DTOR_LIST__))();
            _t5 = dtor_idx.5984;
        } while(_t5 < _t10);
        goto L4;
    }
    return;
}

frame_dummy()
{// addr = 0x080484C0
    _unknown_ __ebp;                       // r6

    __eax = __JCR_LIST__;
    if(__JCR_LIST__ == 0) {
    } else {
        __eax = 0;
        if(__eax != 0) {
             *__esp =  &__JCR_LIST__;
             *__eax();
            return;
        }
    }
    return;
}

main(
    _unknown_ __fp0                        // r28
)
{// addr = 0x080484E4
    signed int _v8;                        // _cfa_fffffff8
    signed int _v12;                       // _cfa_fffffff4
    intOrPtr _v32;                         // _cfa_ffffffe0
    char* _v36;                            // _cfa_ffffffdc
    intOrPtr _v48;                         // _cfa_ffffffd0
    char* _v52;                            // _cfa_ffffffcc
    intOrPtr _v56;                         // _cfa_ffffffc8
    char* _v60;                            // _cfa_ffffffc4
    intOrPtr _v72;                         // _cfa_ffffffb8
    intOrPtr _v76;                         // _cfa_ffffffb4
    intOrPtr _v80;                         // _cfa_ffffffb0
    _unknown_ __ebp;                       // r6

    __fp0 = __fp0;
    __esp = __esp & 240;
    __esp = __esp - 80;
    _v12 = 0;
    while(_v12 <= 2) {
        _v8 = 0;
        while(_v8 <= 2) {
            __fp0 ?_?  *((long long*)((_v12 + __edx + __edx + _v8) * 8 +  &m));
            asm("fstp qword [esp+0x4]");
             *__esp = 134514352;
            printf();
            _v8 = _v8 + 1;
        }
         *__esp = 10;
        putchar();
        _v12 = _v12 + 1;
    }
    _v32 = 1;
    _v36 =  &y;
    asm("fldz ");
    asm("fstp qword [esp+0x28]");
    _v48 = 1;
    _v52 =  &x;
    _v56 = 3;
    _v60 =  &m;
    asm("fld1 ");
    asm("fstp qword [esp+0x10]");
    _v72 = 3;
    _v76 = 3;
    _v80 = 111;
     *__esp = 101;
    cblas_dgemv();
    _v12 = 0;
    while(_v12 <= 2) {
        __fp0 ?_?  *((long long*)(_v12 * 8 +  &y));
        asm("fstp qword [esp+0x4]");
         *__esp = "%5.1f\n";
        printf();
        _v12 = _v12 + 1;
    }
    return 0;
}

__libc_csu_fini()
{// addr = 0x080485F0
    _unknown_ __ebp;                       // r6

    return;
}

__libc_csu_init(
    intOrPtr _a4,                          // _cfa_4
    intOrPtr _a8,                          // _cfa_8
    intOrPtr _a12                          // _cfa_c
)
{// addr = 0x08048600
    intOrPtr _v36;                         // _cfa_ffffffdc
    intOrPtr _v40;                         // _cfa_ffffffd8
    _unknown_ __ebx;                       // r1
    _unknown_ __edi;                       // r4
    signed int __esi;                      // r5
    _unknown_ __ebp;                       // r6
    _unknown_ _t14;                        // _t14
    _unknown_ _t15;                        // _t15
    signed int _t18;                       // _t18

    __i686.get_pc_thunk.bx();
    _t15 = _t14 + 4529;
    __esp = __esp - 28;
    _init();
    _t18 = _t15 + -248 - _t15 + -248 >> 2;
    if(_t18 == 0) {
    } else {
        __esi = 0;
        do {
            _v36 = _a12;
            _v40 = _a8;
             *__esp = _a4;
             *((intOrPtr*)(_t15 + -248 + __esi * 4))();
            __esi = __esi + 1;
        } while(__esi < _t18);
    }
    __esp = __esp + 28;
    return;
}

__i686.get_pc_thunk.bx()
{// addr = 0x0804865A
    return;
}

__do_global_ctors_aux()
{// addr = 0x08048660
    intOrPtr* __ebx;                       // r1
    _unknown_ __ebp;                       // r6

    __eax = __CTOR_LIST__;
    if(__eax == 255) {
    } else {
        __ebx =  &__CTOR_LIST__;
        asm("o16 nop ");
        do {
            __ebx = __ebx - 4;
             *__eax();
            __eax =  *__ebx;
        } while(__eax != 255);
    }
    return;
}

_fini()
{// addr = 0x0804868C
    _unknown_ __ebx;                       // r1
    _unknown_ __ebp;                       // r6
    _unknown_ _t1;                         // _t1

    __esp = __esp - 4;
    L1();
    _pop(__ebx);
    __do_global_dtors_aux(__esi);
    _pop(__ecx);
    return;
}

L08048698()
{
    _unknown_ _t1;                         // _t1

    _pop(__ebx);
    __do_global_dtors_aux(__esi);
    _pop(__ecx);
    _pop(__ebx);
    __esp = __ebp;
    _pop(__ebp);
    return;
}

L08048698()
{
    _unknown_ _t1;                         // _t1

    _pop(__ebx);
    @rec __do_global_dtors_aux@__do_global_dtors_aux@(__esi);
    _pop(__ecx);
    _pop(__ebx);
    __esp = __ebp;
    _pop(__ebp);
    return;
}

// Statistics:
//      74 Register nodes
//      35 Temporaries nodes
//       5 Casts
//     207 Statements
//       2 Labels
//       1 Gotos
//      17 Blocks
//     469 Nodes
//      10 Assembly nodes
//      27 Unknown Types


Total time: 0 seconds.


Структура программы (вначале) в общем несколько лучше, чем у Boomerang, и куда больше подробностей.



2. Бен, ай нид хелп: MEX-файл, написанный на C  + BLAS, исходников которому нет.
Этот пример в посте приводить не стану, так как он длинный, но желающим попробовать своё декомпиляйшн-кунфу такая возможность предоставится:
Некоторые входные данные: это оптимизационный алгоритм для Quadratic Programming типа Branch-and-Bound (почитать тут и здесь). Алгоритм в целом прост и незатейлив, но самая сложная часть в нём - определить lower/upper bound через решение упрощённой оптимизационной задачи, и делать это быстро. Как такое сделать - хороший вопрос, и именно он меня интересует более всего. 

Короче, важен не столько алгоритм, сколько его составные компоненты (стратегия и подпрограммы для lower bound estimation).

Автор этих строк, поковыряв выхлоп RecStudio, нашёл для себя подсказку на строчке 12319:
qps_mq_sub( .....

и особенно на строчке 12088:
getalp( ....
что позволило автору предположить, что для lower/upper bounds  использутеся Liner Programming.  Не слишком много, но по крайней мере понятно, в какую сторону копать.

Если у кого-то вдруг проявится желание потыкать в оный бинарник палочкой, IDA Pro и ещё чем - не стесняйтесь отписываться в комментариях.
Обновление: теперь можно сравнить выдачи Boomerang, RecStudio, и (спасибо, Григорий!) IDA Pro. В самом деле, выдача IDA Pro куда лучше того, что дают остальные, особенно boomerang. Можно выудить (до некоторой степени) структуру программы и даже сообщения об ошибках.


Ссылки
Интересующийся читатель может попробовать полистать вебстраницы автора RecStudio с полезной информацией, сходить на wiki-ресурс по обратной разработке.

Помимо познавательных диссертаций Michael James Van Emmerik (Boomerang) и Cristina Cifuentes [C. Cifuentes, Reverse Compilation Techniques], есть хорошие книжки по теме:
  • "Compilers - Principles, Techniques and Tools", Aho, Sethi, Ullman, 1986 Addison-Wesley Publishing Co.  ISBN 0-201-10088-6.
  • "Advanced Compiler Design & Implementation", Steven Muchnick, 1997 Morgan Kaufmann Publishers, ISBN 1-55860-320-4.
  • "How debuggers work - Algorithms, Data Structures, and Architecture", Jonathan Rosemberg, 1996 John Wiley and Sons, ISBN 0-471-14966-7.

Дело это интересное, но весьма утомительное, хотя может помочь при раскопках очередного legacy-software и сэкономить вам полжизни.
Читать далее