Как легко отобразить перечисления C++ на строки

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

  1. Загрузите код для внедрения . Большинство ответов, опубликованных здесь, используют то, что я считаю лучшим подходом - вызов dlopen() в подчиненном процессе для связи в общей библиотеке, содержащей введенный код. В статье, которую вы связали с автором, вместо этого загрузили перемещаемый объектный файл и связали его вручную с подчиненным. Это, откровенно говоря, безумие - перемещаемые объекты не являются «готовыми к работе» и включают перемещения даже для внутренних ссылок. А ручная компоновка утомительна и подвержена ошибкам - гораздо проще позволить реальной работе динамического компоновщика во время выполнения. Это, в первую очередь, означает вовлечение в процесс libdl, но для этого есть много вариантов.
  2. Создать объезд . Большинство ответов, опубликованных здесь до сих пор, включали в себя поиск записи PLT для интересующей функции, использование которой для нахождения соответствующей записи GOT, а затем изменение записи GOT для указания на введенную функцию. Это хорошо до некоторой степени, но некоторые функции компоновщика, например, использование dlsym, могут обойти GOT и обеспечить прямой доступ к интересующей функции. Единственный способ быть уверенным в перехвате всех вызовов определенной функции - это переписать начальные инструкции кода этой функции в памяти, чтобы создать «обходной» путь, перенаправляющий выполнение на вашу внедренную функцию.
  3. Создать батут (необязательно). Часто при выполнении такого рода инъекций вы захотите вызвать исходную функцию, вызов которой вы перехватываете. Способ сделать это с помощью обхода функции заключается в создании небольшого кода «батут», который включает перезаписанные инструкции исходной функции, а затем переход к оставшейся части оригинала. Это может быть сложно, потому что любые относящиеся к IP инструкции в скопированном наборе необходимо изменить, чтобы учесть их новые адреса.
  4. Автоматизировать все это . Эти шаги могут быть утомительными, даже если вы делаете некоторые из простых решений, опубликованных в других ответах. Лучший способ убедиться, что шаги выполняются правильно каждый раз с переменными параметрами (внедрение различных функций и т. Д.), - это автоматизировать их выполнение. Начиная с серии 7.0, в gdb появилась возможность писать новые команды на Python. Эта поддержка может быть использована для реализации решения «под ключ» для внедрения и обхода кода в / в подчиненном процессе.

Вот пример. У меня есть такие же исполняемые файлы a и b, как и раньше, и inject2.so, созданный из следующего кода:

#include 
#include 

int (*rand__)(void) = NULL;

int
rand(void)
{
    int result = rand__();
    printf("rand invoked! result = %d\n", result);
    return result % 47;
}

Затем я могу поместить свою команду Python detour в detour.py и иметь следующий сеанс gdb:

(gdb) source detour.py
(gdb) exec-file a
(gdb) set follow-fork-mode child
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/llasram/ws/detour/a 
a: 1933263113
a: 831502921
[New process 8500]
b: 918844931
process 8500 is executing new program: /home/llasram/ws/detour/b
[Switching to process 8500]

Catchpoint 1 (exec'd /home/llasram/ws/detour/b), 0x00007ffff7ddfaf0 in _start ()
   from /lib64/ld-linux-x86-64.so.2
(gdb) break main
Breakpoint 2 at 0x4005d0: file b.c, line 7.
(gdb) cont
Continuing.

Breakpoint 2, main (argc=1, argv=0x7fffffffdd68) at b.c:7
7       {
(gdb) detour libc.so.6:rand inject2.so:rand inject2.so:rand__
(gdb) cont
Continuing.
rand invoked! result = 392103444
b: 22

Program exited normally.

В дочернем процессе я создаю обходной путь от функции rand() в libc.so.6 к функции rand() в inject2.so и сохраняю указатель на батут для оригинала rand() в переменной rand__ из inject2.so. И, как и ожидалось, введенный код вызывает оригинал, отображает полный результат и возвращает этот результат по модулю 47.

Из-за длины, я просто ссылаюсь на pastie, содержащий код моей команды detour . Это довольно поверхностная реализация (особенно с точки зрения создания батута), но она должна хорошо работать в большом проценте случаев. Я протестировал его с gdb 7.2 (последняя выпущенная версия) в Linux с 32-битными и 64-битными исполняемыми файлами. Я не проверял это на OS X, но любые различия должны быть относительно незначительными.

113
задан Roddy 16 October 2008 в 12:11
поделиться

2 ответа

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

// WeekEnd enumeration
enum WeekEnd
{
    Sunday = 1,
    Saturday = 7
};

// String support for WeekEnd
Begin_Enum_String( WeekEnd )
{
    Enum_String( Sunday );
    Enum_String( Saturday );
}
End_Enum_String;

// Convert from WeekEnd to string
const std::string &str = EnumString<WeekEnd>::From( Saturday );
// str should now be "Saturday"

// Convert from string to WeekEnd
WeekEnd w;
EnumString<WeekEnd>::To( w, "Sunday" );
// w should now be Sunday

Если да, то можете прочитать эту статью:
http: // www.gamedev.net/reference/snippets/features/cppstringizing/[1286 visible

0
ответ дан 24 November 2019 в 02:44
поделиться

Мне несколько раз требовалась эта функциональность для отладки/анализа кода от других. Для этого я написал скрипт Perl, который генерирует класс с несколькими перегруженными toString методов. Каждый метод toString принимает Enum в качестве аргумента и возвращает const char*.

Конечно, скрипт не анализирует C++ для самих обименов, а использует ctags для генерации таблицы символов.

Скрипт Perl находится здесь: http://heinitz-it.de/download/enum2string/enum2string.pl.html

2
ответ дан 24 November 2019 в 02:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: