Как узнать, вернул ли системный вызов ошибку?

Я пытаюсь воспроизвести поведение strace в C, используя ptrace.

Я хотел бы проверить, вернул ли системный вызов ошибку (и какую ошибку1), но не знаю, как это сделать?

Вот пример вывода strace, который я пытаюсь воспроизвести:

execve("./exit", ["./exit"], 0x7ffff059f250 /* 62 vars */) = 0
read(42, NULL, 0)                       = -1 EBADF (Bad file descriptor)
exit(0)                                 = ?
+++ exited with 0 +++

Я пытался сравнить возвращаемое значение системного вызова2 с -1, но они не равны.

Я вижу в реализации системного вызова GLIBC (sysdeps/unix/sysv/linux/syscall.c), что используется макрос INTERNAL_SYSCALL_ERROR_P, который, похоже, является макросом для внутреннего использования GLIBC. Я нашел две реализации этого макроса:

  • Первый, в sysdeps/unix/sysv/linux/sysdep.h:
#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned long int)(val) > -4096UL)
  • Второй, в sysdeps/unix/sysv/linux/x86_64/x32/times.c:
#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned long long int)(val) >= -4095LL)

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

1Чтобы восстановить код ошибки, инвертирование возвращаемого значения системного вызова (-rax), похоже, работает.

2С помощью ptrace(PTRACE_GETREGS, ...) мы можем получить дочерние регистры и сохранить их в struct user_regs_struct (определенном в sys/user.h). Получив доступ к члену rax этой структуры, мы получаем возвращаемое значение системного вызова.

При ошибке системного вызова (под x86) IIRC устанавливает флаг переноса.

Craig Estey 17.03.2024 01:44

Что означает «Я пытался сравнить возвращаемое значение системного вызова с -1»? Вы не можете сравнивать возвращаемое значение syscall ни с чем, пока оно каким-то образом не станет вам видимым. Вы имеете в виду, что пытались отследить программу, и в этой программе у вас был код для сравнения возвращаемого значения вызова с -1? Вы имеете в виду, что посмотрели вывод strace и искали в нем «-1»? Что-то другое?

Eric Postpischil 17.03.2024 01:55

@EricPostpischil Возвращаемое значение системного вызова хранится в регистре rax. То есть я сравнил это с -1. Фактически, у меня есть программа, которая отслеживает другую с помощью ptrace. Я не уверен, что понял ваш вопрос, правильно ли я на него ответил?

Clement-Z4RM 17.03.2024 13:02

Итак, реальная проблема заключается в том, что у вас есть программа, которая пытается использовать ptrace, и эта программа ведет себя не так, как вы ожидаете. Для этого вам необходимо предоставить минимально воспроизводимый пример программы, о которой идет речь. Я вижу, что вы уже ввели ответ, и он подтверждает это: вы, очевидно, получали правильное значение, возвращаемое в члене rax структуры, но не интерпретировали его должным образом. Предоставление минимально воспроизводимого примера позволило бы другим людям воспроизвести и диагностировать проблему.

Eric Postpischil 17.03.2024 15:49
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
118
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Думаю, я нашел решение.

syscall, похоже, не устанавливает флаг переноса.
В противном случае, как мы видим в этом руководстве по системным вызовам, если rax отрицательное значение (ниже 0), это указывает на ошибку.
Поскольку rax в struct user_regs_struct не имеет знака, нам просто нужно привести его к знаку, и мы сможем узнать, вернулся ли системный вызов и произошла ли ошибка, а также какая ошибка (-rax, чтобы получить код ошибки).

int main(int argc, const char *argv[])
{
    struct user_regs_struct regs;

    // strace logic ...
    if ((long long)regs.rax < 0)
        printf(" = -1 %s (%s)\n", strerrorname_np((int)-regs.rax), strerror((int)-regs.rax));
    else
        printf(" = %llu\n", regs.rax);
    // ...
}

Другие вопросы по теме