Skip to content
Commits on Source (14)
# This file uses the freedesktop ci-templates to build Weston and run our
# This file uses the freedesktop ci-templates to build Wayland and run our
# tests in CI.
#
#
# ci-templates uses a multi-stage build process. First, the base container
# image is built which contains the core distribution, the toolchain, and
# all our build dependencies. This container is aggressively cached; if a
......@@ -41,24 +41,19 @@
# API changes. If you need new features from ci-templates you must bump
# this to the current SHA you require from the ci-templates repo, however
# be aware that you may need to account for API changes when doing so.
.templates_sha: &template_sha 290b79e0e78eab67a83766f4e9691be554fc4afd # see https://docs.gitlab.com/ee/ci/yaml/#includefile
.templates_sha: &template_sha 567700e483aabed992d0a4fea84994a0472deff6 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
include:
# Debian container builder template
- project: 'freedesktop/ci-templates'
ref: *template_sha
file: '/templates/debian.yml'
# ci-fairy template
- project: 'freedesktop/ci-templates'
ref: *template_sha
file: '/templates/ci-fairy.yml'
file:
- '/templates/debian.yml'
- '/templates/freebsd.yml'
- '/templates/ci-fairy.yml'
variables:
FDO_UPSTREAM_REPO: wayland/wayland
FDO_REPO_SUFFIX: "$BUILD_OS/$BUILD_ARCH"
# bump this tag every time you change something which requires rebuilding the
# base image
FDO_DISTRIBUTION_TAG: "2021-08-03.0"
# Define the build stages. These are used for UI grouping as well as
......@@ -80,6 +75,9 @@ stages:
FDO_DISTRIBUTION_VERSION: buster
FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build'
FDO_DISTRIBUTION_EXEC: 'pip3 install meson==0.52.1'
# bump this tag every time you change something which requires rebuilding the
# base image
FDO_DISTRIBUTION_TAG: "2021-08-03.0"
.debian-x86_64:
extends:
......@@ -229,7 +227,39 @@ armv7-debian-container_prep:
paths:
- build-*/meson-logs
- prefix-*
reports:
junit: build-*/meson-logs/testlog.junit.xml
# Full build and test.
.do-build-qemu:
extends:
- .ci-rules
stage: "Build and test"
script:
# Start the VM and copy our workspace to the VM
- /app/vmctl start
- scp -r $PWD "vm:"
# The `set +e is needed to ensure that we always copy the meson logs back to
# the workspace to see details about the failed tests.
- |
set +e
/app/vmctl exec "pkg info; cd $CI_PROJECT_NAME ; meson $BUILDDIR --prefix=$PREFIX $MESON_BUILD_TYPE $MESON_ARGS && ninja -C $BUILDDIR -j${FDO_CI_CONCURRENT:-4}"
/app/vmctl exec "meson test --print-errorlogs -C $BUILDDIR --num-processes ${FDO_CI_CONCURRENT:-4}" && touch .tests-successful
set -ex
scp -r vm:$BUILDDIR/meson-logs .
/app/vmctl exec "ninja -C $BUILDDIR install"
mkdir -p $PREFIX && scp -r vm:$PREFIX/ $PREFIX/
# Finally, shut down the VM.
- /app/vmctl stop
- test -f .tests-successful || exit 1
artifacts:
name: wayland-$CI_JOB_NAME
when: always
paths:
- meson-logs
- prefix-*
reports:
junit: meson-logs/testlog.junit.xml
# Full build and test.
x86_64-debian-build:
......@@ -264,3 +294,57 @@ armv7-release-debian-build:
- .build-env-debian-armv7
- .do-build
- .build-release
# Base variables used for anything using a FreeBSD environment
.os-freebsd:
variables:
BUILD_OS: freebsd
FDO_DISTRIBUTION_VERSION: "13.0"
FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2'
# bump this tag every time you change something which requires rebuilding the
# base image
FDO_DISTRIBUTION_TAG: "2021-08-05.0"
# Don't build documentation since installing the required tools massively
# increases the VM image (and therefore container) size.
MESON_ARGS: "-Ddocumentation=false"
.freebsd-x86_64:
extends:
- .os-freebsd
variables:
BUILD_ARCH: "x86_64"
x86_64-freebsd-container_prep:
extends:
- .ci-rules
- .freebsd-x86_64
- .fdo.qemu-build@freebsd@x86_64
stage: "Base container"
variables:
GIT_STRATEGY: none
.build-env-freebsd-x86_64:
variables:
# Compiling with ASan+UBSan appears to trigger an infinite loop in the
# compiler shipped with FreeBSD 13.0, so we only use UBSan here.
# Additionally, sanitizers can't be used with b_lundef on FreeBSD.
MESON_BUILD_TYPE: "-Dbuildtype=debug -Db_sanitize=undefined -Db_lundef=false"
extends:
- .fdo.suffixed-image@freebsd
- .freebsd-x86_64
- .build-env
needs:
- job: x86_64-freebsd-container_prep
artifacts: false
# Full build and test.
x86_64-freebsd-build:
extends:
- .build-env-freebsd-x86_64
- .do-build-qemu
x86_64-release-freebsd-build:
extends:
- .build-env-freebsd-x86_64
- .do-build-qemu
- .build-release
......@@ -26,7 +26,7 @@ add_project_arguments(
language: 'c'
)
foreach h: [ 'sys/prctl.h' ]
foreach h: [ 'sys/prctl.h', 'sys/procctl.h', 'sys/ucred.h' ]
config_h.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h))
endforeach
......@@ -36,13 +36,39 @@ have_funcs = [
'posix_fallocate',
'prctl',
'memfd_create',
'mremap',
'strndup',
]
foreach f: have_funcs
config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f))
endforeach
config_h.set10('HAVE_XUCRED_CR_PID', cc.has_member('struct xucred', 'cr_pid', prefix : '#include <sys/ucred.h>'))
have_broken_msg_cmsg_cloexec = false
if host_machine.system() == 'freebsd'
have_broken_msg_cmsg_cloexec = not cc.compiles('''
#include <sys/param.h> /* To get __FreeBSD_version. */
#if __FreeBSD_version < 1300502 || \
(__FreeBSD_version >= 1400000 && __FreeBSD_version < 1400006)
/*
* FreeBSD had a broken implementation of MSG_CMSG_CLOEXEC between 2015 and
* 2021. Check if we are compiling against a version that includes the fix
* (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211).
*/
#error "Broken MSG_CMSG_CLOEXEC"
#endif
''', name : 'MSG_CMSG_CLOEXEC works correctly')
endif
config_h.set10('HAVE_BROKEN_MSG_CMSG_CLOEXEC', have_broken_msg_cmsg_cloexec)
if get_option('libraries')
if host_machine.system() == 'freebsd'
# When building for FreeBSD, epoll(7) is provided by a userspace
# wrapper around kqueue(2).
epoll_dep = dependency('epoll-shim')
else
# Otherwise, assume that epoll(7) is supported natively.
epoll_dep = []
endif
ffi_dep = dependency('libffi')
decls = [
......@@ -52,7 +78,7 @@ if get_option('libraries')
]
foreach d: decls
if not cc.has_header_symbol(d['header'], d['symbol'])
if not cc.has_header_symbol(d['header'], d['symbol'], dependencies: epoll_dep)
error('@0@ is needed to compile Wayland libraries'.format(d['symbol']))
endif
endforeach
......
......@@ -89,7 +89,7 @@ if get_option('libraries')
'connection.c',
'wayland-os.c'
],
dependencies: [ ffi_dep, rt_dep ]
dependencies: [ epoll_dep, ffi_dep, rt_dep ]
)
wayland_private_dep = declare_dependency(
......@@ -163,6 +163,7 @@ if get_option('libraries')
],
version: '0.1.0',
dependencies: [
epoll_dep,
ffi_dep,
wayland_private_dep,
wayland_util_dep,
......@@ -177,7 +178,7 @@ if get_option('libraries')
wayland_server_dep = declare_dependency(
link_with: wayland_server,
include_directories: [ root_inc, include_directories('.') ],
dependencies: [ ffi_dep, mathlib_dep, threads_dep ],
dependencies: [ epoll_dep, ffi_dep, mathlib_dep, threads_dep ],
sources: [
wayland_server_protocol_core_h,
wayland_server_protocol_h
......@@ -206,6 +207,7 @@ if get_option('libraries')
],
version: '0.3.0',
dependencies: [
epoll_dep,
ffi_dep,
wayland_private_dep,
wayland_util_dep,
......
......@@ -25,14 +25,21 @@
#define _GNU_SOURCE
#include "../config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/mman.h>
#include <sys/un.h>
#ifdef HAVE_SYS_UCRED_H
#include <sys/ucred.h>
#endif
#include "../config.h"
#include "wayland-os.h"
static int
......@@ -72,6 +79,46 @@ wl_os_socket_cloexec(int domain, int type, int protocol)
return set_cloexec_or_close(fd);
}
#if defined(__FreeBSD__)
int
wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid)
{
socklen_t len;
struct xucred ucred;
len = sizeof(ucred);
if (getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERCRED, &ucred, &len) < 0 ||
ucred.cr_version != XUCRED_VERSION)
return -1;
*uid = ucred.cr_uid;
*gid = ucred.cr_gid;
#if HAVE_XUCRED_CR_PID
/* Since https://cgit.freebsd.org/src/commit/?id=c5afec6e895a */
*pid = ucred.cr_pid;
#else
*pid = 0;
#endif
return 0;
}
#elif defined(SO_PEERCRED)
int
wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid)
{
socklen_t len;
struct ucred ucred;
len = sizeof(ucred);
if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0)
return -1;
*uid = ucred.uid;
*gid = ucred.gid;
*pid = ucred.pid;
return 0;
}
#else
#error "Don't know how to read ucred on this platform"
#endif
int
wl_os_dupfd_cloexec(int fd, int minfd)
{
......@@ -121,6 +168,15 @@ recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags)
ssize_t
wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
{
#if HAVE_BROKEN_MSG_CMSG_CLOEXEC
/*
* FreeBSD had a broken implementation of MSG_CMSG_CLOEXEC between 2015
* and 2021, so we have to use the non-MSG_CMSG_CLOEXEC fallback
* directly when compiling against a version that does not include the
* fix (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211).
*/
#pragma message("Using fallback directly since MSG_CMSG_CLOEXEC is broken.")
#else
ssize_t len;
len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
......@@ -128,7 +184,7 @@ wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
return len;
if (errno != EINVAL)
return -1;
#endif
return recvmsg_cloexec_fallback(sockfd, msg, flags);
}
......@@ -165,3 +221,31 @@ wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
fd = accept(sockfd, addr, addrlen);
return set_cloexec_or_close(fd);
}
/*
* Fallback function for operating systems that don't implement
* mremap(MREMAP_MAYMOVE).
*/
void *
wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size,
ssize_t new_size, int prot, int flags)
{
void *result;
/*
* We could try mapping a new block immediately after the current one
* with MAP_FIXED, however that is not guaranteed to work and breaks
* on CHERI-enabled architectures since the data pointer will still
* have the bounds of the previous allocation. As this is not a
* performance-critical path, we always map a new region and copy the
* old data to the new region.
*/
result = mmap(NULL, new_size, prot, flags, fd, 0);
if (result != MAP_FAILED) {
/* Copy the data over and unmap the old mapping. */
memcpy(result, old_data, *old_size);
if (munmap(old_data, *old_size) == 0) {
*old_size = 0; /* successfully unmapped old data. */
}
}
return result;
}
......@@ -26,9 +26,15 @@
#ifndef WAYLAND_OS_H
#define WAYLAND_OS_H
#include <sys/types.h>
#include <sys/socket.h>
int
wl_os_socket_cloexec(int domain, int type, int protocol);
int
wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid);
int
wl_os_dupfd_cloexec(int fd, int minfd);
......@@ -41,6 +47,10 @@ wl_os_epoll_create_cloexec(void);
int
wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
void *
wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size,
ssize_t new_size, int prot, int flags);
/*
* The following are for wayland-os.c and the unit tests.
......
......@@ -78,7 +78,9 @@ struct wl_client {
struct wl_list link;
struct wl_map objects;
struct wl_priv_signal destroy_signal;
struct ucred ucred;
pid_t pid;
uid_t uid;
gid_t gid;
int error;
struct wl_priv_signal resource_created_signal;
};
......@@ -314,7 +316,7 @@ wl_resource_post_error(struct wl_resource *resource,
static void
destroy_client_with_error(struct wl_client *client, const char *reason)
{
wl_log("%s (pid %u)\n", reason, client->ucred.pid);
wl_log("%s (pid %u)\n", reason, client->pid);
wl_client_destroy(client);
}
......@@ -513,7 +515,6 @@ WL_EXPORT struct wl_client *
wl_client_create(struct wl_display *display, int fd)
{
struct wl_client *client;
socklen_t len;
client = zalloc(sizeof *client);
if (client == NULL)
......@@ -528,9 +529,8 @@ wl_client_create(struct wl_display *display, int fd)
if (!client->source)
goto err_client;
len = sizeof client->ucred;
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED,
&client->ucred, &len) < 0)
if (wl_os_socket_peercred(fd, &client->uid, &client->gid,
&client->pid) != 0)
goto err_source;
client->connection = wl_connection_create(fd);
......@@ -586,11 +586,11 @@ wl_client_get_credentials(struct wl_client *client,
pid_t *pid, uid_t *uid, gid_t *gid)
{
if (pid)
*pid = client->ucred.pid;
*pid = client->pid;
if (uid)
*uid = client->ucred.uid;
*uid = client->uid;
if (gid)
*gid = client->ucred.gid;
*gid = client->gid;
}
/** Get the file descriptor for the client
......
......@@ -45,6 +45,7 @@
#include <errno.h>
#include <fcntl.h>
#include "wayland-os.h"
#include "wayland-util.h"
#include "wayland-private.h"
#include "wayland-server.h"
......@@ -61,8 +62,12 @@ struct wl_shm_pool {
int internal_refcount;
int external_refcount;
char *data;
int32_t size;
int32_t new_size;
ssize_t size;
ssize_t new_size;
/* The following three fields are needed for mremap() emulation. */
int mmap_fd;
int mmap_flags;
int mmap_prot;
bool sigbus_is_impossible;
};
......@@ -90,6 +95,26 @@ struct wl_shm_sigbus_data {
int fallback_mapping_used;
};
static void *
shm_pool_grow_mapping(struct wl_shm_pool *pool)
{
void *data;
#ifdef MREMAP_MAYMOVE
data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE);
#else
data = wl_os_mremap_maymove(pool->mmap_fd, pool->data, &pool->size,
pool->new_size, pool->mmap_prot,
pool->mmap_flags);
if (pool->size != 0) {
wl_resource_post_error(pool->resource,
WL_SHM_ERROR_INVALID_FD,
"leaked old mapping");
}
#endif
return data;
}
static void
shm_pool_finish_resize(struct wl_shm_pool *pool)
{
......@@ -98,7 +123,7 @@ shm_pool_finish_resize(struct wl_shm_pool *pool)
if (pool->size == pool->new_size)
return;
data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE);
data = shm_pool_grow_mapping(pool);
if (data == MAP_FAILED) {
wl_resource_post_error(pool->resource,
WL_SHM_ERROR_INVALID_FD,
......@@ -127,6 +152,7 @@ shm_pool_unref(struct wl_shm_pool *pool, bool external)
return;
munmap(pool->data, pool->size);
close(pool->mmap_fd);
free(pool);
}
......@@ -274,6 +300,8 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource,
{
struct wl_shm_pool *pool;
int seals;
int prot;
int flags;
if (size <= 0) {
wl_resource_post_error(resource,
......@@ -301,17 +329,19 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource,
pool->external_refcount = 0;
pool->size = size;
pool->new_size = size;
pool->data = mmap(NULL, size,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
prot = PROT_READ | PROT_WRITE;
flags = MAP_SHARED;
pool->data = mmap(NULL, size, prot, flags, fd, 0);
if (pool->data == MAP_FAILED) {
wl_resource_post_error(resource,
WL_SHM_ERROR_INVALID_FD,
wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD,
"failed mmap fd %d: %s", fd,
strerror(errno));
goto err_free;
}
close(fd);
/* We may need to keep the fd, prot and flags to emulate mremap(). */
pool->mmap_fd = fd;
pool->mmap_prot = prot;
pool->mmap_flags = flags;
pool->resource =
wl_resource_create(client, &wl_shm_pool_interface, 1, id);
if (!pool->resource) {
......
......@@ -168,10 +168,22 @@ TEST(event_loop_signal)
signal_callback, &got_it);
assert(source);
wl_event_loop_dispatch(loop, 0);
assert(wl_event_loop_dispatch(loop, 0) == 0);
assert(!got_it);
kill(getpid(), SIGUSR1);
wl_event_loop_dispatch(loop, 0);
assert(kill(getpid(), SIGUSR1) == 0);
/*
* On Linux the signal will be immediately visible in the epoll_wait()
* call. However, on FreeBSD we may need a small delay between kill()
* call and the signal being visible to the kevent() call. This
* sometimes happens when the signal processing and kevent processing
* runs on different CPUs, so becomes more likely when the system is
* under load (e.g. running all tests in parallel).
* See https://github.com/jiixyj/epoll-shim/pull/32
* Passing 1ms as the timeout appears to avoid this race condition in
* all cases tested so far, but to be safe we use 1000ms which should
* be enough time even on a really slow (or emulated) system.
*/
assert(wl_event_loop_dispatch(loop, 1000) == 0);
assert(got_it == 1);
wl_event_source_remove(source);
......@@ -199,8 +211,12 @@ TEST(event_loop_multiple_same_signals)
/* Try it more times */
for (i = 0; i < 5; ++i) {
calls_no = 0;
kill(getpid(), SIGUSR1);
assert(wl_event_loop_dispatch(loop, 0) == 0);
assert(kill(getpid(), SIGUSR1) == 0);
/*
* We need a non-zero timeout here to allow the test to pass
* on non-Linux systems (see comment in event_loop_signal).
*/
assert(wl_event_loop_dispatch(loop, 1000) == 0);
assert(calls_no == 2);
}
......@@ -208,8 +224,12 @@ TEST(event_loop_multiple_same_signals)
/* Try it again with one source */
calls_no = 0;
kill(getpid(), SIGUSR1);
assert(wl_event_loop_dispatch(loop, 0) == 0);
assert(kill(getpid(), SIGUSR1) == 0);
/*
* We need a non-zero timeout here to allow the test to pass
* on non-Linux systems (see comment in event_loop_signal).
*/
assert(wl_event_loop_dispatch(loop, 1000) == 0);
assert(calls_no == 1);
wl_event_source_remove(s2);
......
......@@ -9,6 +9,7 @@ test_runner = static_library(
dependencies: [
cc.find_library('dl', required: false),
dependency('threads'),
epoll_dep,
ffi_dep,
wayland_util_dep,
wayland_private_dep,
......@@ -154,7 +155,7 @@ tests = {
foreach test_name, test_extra_sources: tests
test_sources = [ test_name + '.c' ] + test_extra_sources
test_deps = [test_runner_dep]
test_deps = [test_runner_dep, epoll_dep]
bin = executable(test_name, test_sources, dependencies: test_deps)
test(
test_name,
......
......@@ -23,6 +23,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "../config.h"
#define _GNU_SOURCE
......@@ -100,7 +101,7 @@ socket(int domain, int type, int protocol)
}
__attribute__ ((visibility("default"))) int
fcntl(int fd, int cmd, ...)
(fcntl)(int fd, int cmd, ...)
{
va_list ap;
int arg;
......@@ -341,7 +342,13 @@ do_os_wrappers_recvmsg_cloexec(int n)
struct marshal_data data;
data.nr_fds_begin = count_open_fds();
#if HAVE_BROKEN_MSG_CMSG_CLOEXEC
/* We call the fallback directly on FreeBSD versions with a broken
* MSG_CMSG_CLOEXEC, so we don't call the local recvmsg() wrapper. */
data.wrapped_calls = 0;
#else
data.wrapped_calls = n;
#endif
setup_marshal_data(&data);
data.nr_fds_conn = count_open_fds();
......
......@@ -41,6 +41,27 @@
#include "test-runner.h"
#if defined(__FreeBSD__)
#include <sys/sysctl.h>
/*
* On FreeBSD, get file descriptor information using sysctl() since that does
* not depend on a mounted fdescfs (which provides /dev/fd/N for N > 2).
*/
int
count_open_fds(void)
{
int error;
int nfds;
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_NFDS, 0 };
size_t len;
len = sizeof(nfds);
error = sysctl(mib, 4, &nfds, &len, NULL, 0);
assert(error == 0 && "sysctl KERN_PROC_NFDS failed.");
return nfds;
}
#else
int
count_open_fds(void)
{
......@@ -48,8 +69,12 @@ count_open_fds(void)
struct dirent *ent;
int count = 0;
dir = opendir("/proc/self/fd");
assert(dir && "opening /proc/self/fd failed.");
/*
* Using /dev/fd instead of /proc/self/fd should allow this code to
* work on non-Linux operating systems.
*/
dir = opendir("/dev/fd");
assert(dir && "opening /dev/fd failed.");
errno = 0;
while ((ent = readdir(dir))) {
......@@ -58,12 +83,13 @@ count_open_fds(void)
continue;
count++;
}
assert(errno == 0 && "reading /proc/self/fd failed.");
assert(errno == 0 && "reading /dev/fd failed.");
closedir(dir);
return count;
}
#endif
void
exec_fd_leak_check(int nr_expected_fds)
......
......@@ -22,6 +22,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "../config.h"
#define _GNU_SOURCE
......@@ -36,11 +37,16 @@
#include <dlfcn.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <sys/ptrace.h>
#ifdef HAVE_SYS_PROCCTL_H
#include <sys/procctl.h>
#elif defined(HAVE_SYS_PRCTL_H)
#include <sys/prctl.h>
#ifndef PR_SET_PTRACER
# define PR_SET_PTRACER 0x59616d61
#endif
#endif
#include "test-runner.h"
......@@ -226,6 +232,21 @@ stderr_reset_color(void)
* Returns: 1 if a debugger is confirmed present; 0 if no debugger is
* present or if it can't be determined.
*/
#if defined(HAVE_SYS_PROCCTL_H) && defined(PROC_TRACE_STATUS)
static int
is_debugger_attached(void)
{
int rc;
int status;
rc = procctl(P_PID, getpid(), PROC_TRACE_STATUS, &status);
if (rc == -1) {
perror("procctl");
return 0;
}
/* -1=tracing disabled, 0=no debugger attached, >0=pid of debugger. */
return status > 0;
}
#elif defined(HAVE_SYS_PRCTL_H)
static int
is_debugger_attached(void)
{
......@@ -287,6 +308,7 @@ is_debugger_attached(void)
return rc;
}
#endif
int main(int argc, char *argv[])
{
......