Предупреждение: я не рекомендую делать это.Послушайте комментарии, в которых вам предлагается найти другой способ решения вашей проблемы
Я также хотел бы еще раз повторить предупреждение Хеннинга Махолмса о том, что оно будет чрезвычайно специфичным для архитектуры и непереносимым.Это будет адское обслуживание, и вам придется вручную обрабатывать множество различных инструкций, если только это не одна конкретная последовательность команд, которую вы ищете (как в приведенном ниже примере).
С учетом сказанного, если вы все еще хотите это сделать, это можно сделать следующим образом:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#define __USE_GNU
#include <signal.h>
void action(int sig, siginfo_t* siginfo, void* context)
{
sig=sig; siginfo=siginfo;// ignore warning
// get execution context
mcontext_t* mcontext = &((ucontext_t*)context)->uc_mcontext;
// find out what instruction faulted
#if defined(__x86_64)
uint8_t* code = (uint8_t*)mcontext->gregs[REG_RIP];
if (code[0] == 0x88 && code[1] == 0x10) { // mov %dl,(%rax)
mcontext->gregs[REG_RIP] += 2; // skip it!
return;
}
#elif defined(__i386)
uint8_t* code = (uint8_t*)mcontext->gregs[REG_EIP];
if (code[0] == 0x88 && code[1] == 0x10) { // mov %dl,(%eax)
mcontext->gregs[REG_EIP] += 2; // skip it!
return;
}
#else
#error "Unsupported system"
#endif
// unknown/unhandled instruction failed...
// only for debugging, shouldn't print stuff in a signal handler
int i = 0;
for (i = 0; i < 16; i++) {
fprintf(stderr, "%2.2X ", code[i]);
}
fprintf(stderr, "\n");
exit(1);
}
int main(void)
{
// install SIGSEGV handler
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_sigaction = action;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGSEGV, &act, NULL) < 0) {
perror("sigaction");
return 1;
}
// cause fault
int i;
for (i = 0; i < 10; i++) {
((unsigned char*)0)[i] = i;
}
return EXIT_SUCCESS;
}
Здесь я обработал только одну конкретную последовательность инструкцийдля 32- и 64-разрядных x86, хотя поддерживать дополнительные архитектуры и инструкции должно быть тривиально (если утомительно).
Обновление: вы (сейчас) упоминаете, что находитесь на компьютере ARM.На самом деле это должно облегчить задачу, поскольку инструкции всегда 32-битные (за исключением режима большого пальца), если я не ошибаюсь.У меня нет машины ARM, чтобы протестировать этот, поэтому вам придется копаться в sys/ucontext.h
, чтобы проверить, правильно ли я назвал имена.Конечно, вы также должны проверять ошибочную инструкцию аналогичным образом.Мое лучшее предположение относительно того, как это происходит для ARM, заключается в следующем (расположенном рядом с другими #if defined(...)
утверждениями:
#elif defined(__arm) // or use what your GCC defines, also check for 32-bit arm mode or whatever...
uint8_t* code = (uint8_t*)mcontext->arm_pc;
if (*(uint32_t*)code == /*some instruction*/) {
mcontext->arm_pc += 4; // skip it!
return;
}