Как изменить возвращаемое значение функции

В этой программе есть функция, которая в настоящее время возвращает 1. Я бы предпочел, чтобы она возвращала 0.

Из этого я делаю вывод: мы можем добавить смещение к программному счетчику, uregs[R_PC]+arg0, чтобы найти адрес возвращаемого значения.

Я выделил 32-битный «0» и пытаюсь записать 2 его байта по адресу, где находится возвращаемое значение (наша функция ожидает возврата BOOL16, поэтому нам нужно только 2 байта 0):

sudo dtrace -p "$(getpid)" -w -n '
int *zero;
BEGIN { zero=alloca(4); *zero=0; }
pid$target::TextOutA:return {
    copyout(zero, uregs[R_PC]+arg0, 2);
}'

Конечно, я получаю:

dtrace: ошибка при включенном идентификаторе зонда 2 (ID 320426: pid60498:gdi32.dll.so:TextOutA:return): неверный адрес (0x41f21c) в действии №1 при смещении DIF 60

uregs[R_PC] предположительно является адресом пользовательского пространства. Вероятно, copyout() нужен адрес ядра.

Как преобразовать адрес пользовательского пространства uregs[R_PC] в пространство ядра? Я знаю, что с помощью copyin() мы можем считывать данные, хранящиеся по адресу пользовательского пространства, в пространство ядра. Но это не дает нам адрес ядра этой памяти.

В качестве альтернативы: есть ли другой способ изменить возвращаемое значение с помощью DTrace?


person Birchlabs    schedule 25.07.2017    source источник
comment
Я не понимаю, как arg0 + u_regs[R_PC]; получает адрес возвращаемого значения. Это два адреса. Добавлять их смысла нет. Как узнать адрес возвращаемого значения? Это вполне может быть передано через реестр. Фактическое возвращаемое значение находится в arg1. См. docs.oracle.com/cd/E19253. -01/817-6223/chp-pid/index.html   -  person Andrew Henle    schedule 30.07.2017
comment
Насколько я понимаю из документации, u_regs[R_PC] — это счетчик программ, а arg0 — это смещение от счетчика программ. таким образом, u_regs[R_PC] будет абсолютным адресом, а arg0 будет относительным смещением, которое вы можете добавить к этому абсолютному адресу, чтобы получить другой абсолютный адрес.   -  person Birchlabs    schedule 31.07.2017
comment
что касается arg1: конечно, это содержит значение, но я намеревался изменить значение до того, как функция вернет его. единственный инструмент, который у нас есть для изменения данных в DTrace (copyout()), требует, чтобы мы знали адрес данных.   -  person Birchlabs    schedule 31.07.2017


Ответы (1)


DTrace не подходит для этого. Вместо этого вы должны использовать отладчик, такой как dbx, mdb или gdb.

А пока я попытаюсь прояснить некоторые концепции, которые вы упомянули.

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

Во-вторых, в общем случае реализация функции возвращает значение, сохраняя его в определенном регистре; например %rax на амд64. Таким образом, переопределение возвращаемого значения потребует переопределения значения регистра. Это невозможно, потому что доступ DTrace к пользовательским земельным регистрам возможен только для чтения.

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

person Robert Harris    schedule 26.07.2017
comment
блестяще! спасибо за подробное объяснение. связанный ответ тоже полезен. Итак, arg0 указывает на инструкцию (т.е. на одну из инструкций возврата в этой функции), а не на данные — так что даже если бы у меня был ее адрес в пространстве ядра, это не то, что я искал. да, это, вероятно, работа для другого инструмента. - person Birchlabs; 27.07.2017