aboutsummaryrefslogtreecommitdiff
path: root/src/syd-trace-freebsd.c
blob: 9072b58c200ef4c17fcb45db75d3656026263f94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* vim: set sw=4 sts=4 et foldmethod=syntax : */

/*
 * Copyright (c) 2010 Ali Polatel <alip@exherbo.org>
 *
 * This file is part of the sydbox sandbox tool. sydbox is free software;
 * you can redistribute it and/or modify it under the terms of the GNU General
 * Public License version 2, as published by the Free Software Foundation.
 *
 * sydbox is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "syd-trace-freebsd.h"

#include <errno.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/wait.h>

#include <glib.h>

#include "syd-log.h"

/**
 * Common functions are defined here for convenience.
 */

unsigned int trace_event(int status)
{
    int sig;

    if (WIFSTOPPED(status)) {
        sig = WSTOPSIG(status);
        if (SIGSTOP == sig)
            return E_STOP;
        else if (SIGTRAP == sig)
            return E_TRAP;
        else
            return E_GENUINE;
    }
    else if (WIFEXITED(status))
        return E_EXIT;
    else if (WIFSIGNALED(status))
        return E_EXIT_SIGNAL;

    return E_UNKNOWN;
}

int trace_me(void)
{
    int save_errno;

    if (G_UNLIKELY(0 > ptrace(PT_TRACE_ME, 0, NULL, 0))) {
        save_errno = errno;
        g_info("failed to set tracing: %s", g_strerror(errno));
        errno = save_errno;
        return -1;
    }
    return 0;
}

int trace_cont(pid_t pid)
{
    int save_errno;

    if (G_UNLIKELY(0 > ptrace(PT_CONTINUE, pid, (caddr_t)1, 0))) {
        save_errno = errno;
        g_info("failed to continue child %i: %s", pid, g_strerror(errno));
        errno = save_errno;
        return -1;
    }
    return 0;
}

int trace_kill(pid_t pid)
{
    int save_errno;

    if (G_UNLIKELY(0 > ptrace(PT_KILL, pid, NULL, 0) && ESRCH != errno)) {
        save_errno = errno;
        g_info("failed to kill child %i: %s", pid, g_strerror(errno));
        errno = save_errno;
        return -1;
    }
    return 0;
}

int trace_syscall(pid_t pid, int data, int call)
{
    int save_errno;

    switch (call) {
        case -1:
            call = PT_SYSCALL;
            break;
        case 0:
            call = PT_TO_SCX;
            break;
        case 1:
            call = PT_TO_SCE;
            break;
        default:
            g_assert_not_reached();
    }

    if (G_UNLIKELY(0 > ptrace(call, pid, (caddr_t)1, data))) {
        save_errno = errno;
        g_info("failed to resume child %i: %s", pid, g_strerror(errno));
        errno = save_errno;
        return -1;
    }

    return 0;
}