Чтение / proc / pid / mem из ptraced процесса возвращает EOF

Контекст

Я работал в программе для моего последнего задания и обнаружил следующее странное поведение.

Я кодировал трассировщик, чтобы иметь возможность читать / записывать память из дочерних процессов. Мое намерение состоит в том, чтобы прочитать выполняемую в данный момент инструкцию в заданной точке, а затем разобрать ее, чтобы получить некоторую информацию об операндах памяти и т.п.

Для целей тестирования используется простой HelloWorld, написанный на C.

Информация

Код трассировщика, который я написал, хотя и упрощен для того, чтобы быть более понятным, таков:

size_t tracer::readMem(ADDR_t offset, char *buff, size_t len) {
    REQUIRE(_state != TRCS_UNINITIALISED);

    if (_memsdescr < 0 || fcntl(_memsdescr, F_GETFL) < 0) {
        _memsdescr = open(("/proc/" + to_string(_child_pid_t) + "/mem").c_str(), O_LARGEFILE);
        if (_memsdescr < 0) {
            logmanager::getInstance ().emplaceBasicLogger ("tracer")
                    .log ( SLVL_ERROR, "Process\' memory could not be "
                           " opened. \n");
            PANIC;
        } else {
            logmanager::getInstance ().emplaceBasicLogger ("tracer")
                    .logfmt ( SLVL_DEBUG, "Opened process' memory. %lx bytes long\n",
                              lseek(_memsdescr, 0, SEEK_END));
        }
    }

    ASSERT(offset <= lseek(_memsdescr, 0, SEEK_END));

    int ret = pread(_memsdescr, buff, len, offset);
    if (ret < 0) {
        logmanager::getInstance ().emplaceBasicLogger ("tracer")
                .logfmt( SLVL_ERROR, "Error reading from memory descriptor: %s\n", sys_errlist[errno]);
    }
    return ret;

}

Код, управляющий выполнением, следующий , В основном все, что он делает - это читает 15-байтовые куски из / proc / mem. Адрес этих блоков получается путем получения значения RIP (указатель инструкции) после вызова ptrace (PTRACE_SINGLESTEP). Это означает, что вся память, которую я пытаюсь прочитать, должна быть отображена в области памяти процесса.

trc.load (filename);
        trc.launchProgram();
        cout << "   Started with pid " << trc.getChildPid() << endl << endl;

        //memspacy::memory_map::printSystemProcVmap(trc.getChildPid());

        //inj.prop_setTraceSyscalls (true);

        while (trc.prop_getState () != memspacy::TRCS_STOPPED) {

            //if (trc.isSyscall()){
            //  trc.showSyscall();
            //}

            //HERE IS WHERE THE DISASSEMBLY takes place
            if (trc.readMem(trc.peekReg(a_RIP), inst_buff, MAX_ARCH_INST_LEN)
                    && dec.disassemble()) {
                dec.printFormatted();

            }

            trc.singleStep();
        }

Выпуск

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

mov %rsp, %rdi
add %al, (%rax)
push %rdi
push %rsi
push %rsp
mov %edi, %ebx
in %dx, %al 
xor %ecx, -0x3f(%rax)
invalid

Полезные факты

Кажется, что после пары инструкций функция чтения перестает получать все данные. Ошибка не выдается, единственная проблема заключается в том, что чтение памяти возвращает 0 байтов . Это будет означать, что EOF достигается в соответствии с информацией на man-странице read (), но lseek () возвращает размер 0xFFFFFFFFFFFF, поэтому с этой целью проблем быть не должно. Кроме того, все чтения находятся в отображенных областях, так как я использую счетчик программ в качестве смещения.

Я не могу думать ни о чем другом, кроме прав доступа к странице, но у них у всех есть установленные разрешения на чтение, иначе он даже не запустится. Процесс правильно отслеживается , и выполнение выполняется просто отлично, с ожидаемым поведением, даже регистры точно такие же, как в контрольном тесте (тест, используемый для проверки исходного поведения).

Мое текущее предположение состоит в том, что в какой-то момент он достигает конца отображаемой области, что делает дескриптор бесполезным, следовательно, эта «недействительная» инструкция в конце, но даже открытие файла при каждом чтении приводит к результату. не изменить.

Данные

Вот карта памяти и смещение чтения последнего действительного чтения.

00400000-00401000 r-xp 00000000 08:06 7602542                            /home/amontes/workspace/memspacy_build/assets/test/test
00600000-00602000 rw-p 00000000 08:06 7602542                            /home/amontes/workspace/memspacy_build/assets/test/test
**7fe3eb602000-7fe3eb625000 r-xp 00000000 08:11 657171                     /lib/x86_64-linux-gnu/ld-2.19.so**
7fe3eb824000-7fe3eb826000 rw-p 00022000 08:11 657171                     /lib/x86_64-linux-gnu/ld-2.19.so
7fe3eb826000-7fe3eb827000 rw-p 00000000 00:00 0 
7fff57783000-7fff577a4000 rw-p 00000000 00:00 0                          [stack]
7fff577fe000-7fff57800000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

Последнее допустимое смещение 7fe3eb606a7c -> Это показывает недопустимую инструкцию

Первое неверное смещение 7fe3eb606a7d -> Это возвращает EOF


Любая помощь или любая идея будут действительно оценены , Спасибо.

10
задан 9 August 2014 в 09:41
поделиться