From 90d05cda980fa4e8fed48389d809e33390bb5ffc Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 13 Mar 2011 11:47:22 +0100 Subject: [PATCH] Support for Linux/S390. --- ChangeLog | 15 +++++++++++++++ NEWS | 7 +++++++ m4/fault.m4 | 12 +++++++++--- src/sigsegv.h.in | 20 ++++++++++++++++++-- tests/sigsegv1.c | 5 +++-- tests/sigsegv2.c | 6 +++++- tests/sigsegv3.c | 5 +++-- 7 files changed, 60 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index f0063b0..eaad8ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2011-03-13 Bruno Haible + + Support for Linux/S390. + * m4/fault.m4 (SV_TRY_FAULT): Define + SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS. On Linux/S390 systems, expect a + page-aligned fault address. + * src/sigsegv.h.in (SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS): New macro. + (sigsegv_register): Mention constraint about address and len arguments. + * tests/sigsegv1.c (handler): On Linux/S390 systems, expect a + page-aligned fault address. + * tests/sigsegv3.c (handler): Likewise. + * tests/sigsegv2.c: Add comment. + * NEWS: Document the change. + Reported by Christoph Egger . + 2011-01-29 Bruno Haible Improve OpenBSD support: Allow faster VMA determination. diff --git a/NEWS b/NEWS index 35ed934..a2eacf4 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,12 @@ New in 2.10: +* Support for Linux/S390. + now defines a macro SIGSEGV_FAULT_ADDRESS_ALIGNMENT. + It is either 1 or pagesize. Its meaning is that + - The fault address passed to a SIGSEGV handler has been rounded down + to a multiple of SIGSEGV_FAULT_ADDRESS_ALIGNMENT. + - The address and length arguments of sigsegv_register function calls + must be multiples of SIGSEGV_FAULT_ADDRESS_ALIGNMENT. * Faster distinction between stack overflow and other fault on OpenBSD. New in 2.9: diff --git a/m4/fault.m4 b/m4/fault.m4 index 2dd89f8..2a2d72b 100644 --- a/m4/fault.m4 +++ b/m4/fault.m4 @@ -1,5 +1,5 @@ -# fault.m4 serial 5 (libsigsegv-2.2) -dnl Copyright (C) 2002-2003 Bruno Haible +# fault.m4 serial 6 (libsigsegv-2.10) +dnl Copyright (C) 2002-2003, 2011 Bruno Haible dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program @@ -43,6 +43,11 @@ $4 static int zero_fd; # define map_flags MAP_FILE | MAP_PRIVATE #endif +#if defined __linux__ && (defined __s390__ || defined __s390x__) +# define SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS (0x1000UL - 1) +#else +# define SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS 0UL +#endif unsigned long page; int handler_called = 0; void sigsegv_handler ($5) @@ -51,7 +56,8 @@ void sigsegv_handler ($5) handler_called++; if (handler_called == 10) exit (4); - if (fault_address != (void*)(page + 0x678)) + if (fault_address + != (void*)((page + 0x678) & ~SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS)) exit (3); if (mprotect ((void *) page, 0x10000, PROT_READ | PROT_WRITE) < 0) exit (2); diff --git a/src/sigsegv.h.in b/src/sigsegv.h.in index a21f6a0..5254641 100644 --- a/src/sigsegv.h.in +++ b/src/sigsegv.h.in @@ -1,5 +1,5 @@ /* Page fault handling library. - Copyright (C) 1998-1999, 2002, 2004-2010 Bruno Haible + Copyright (C) 1998-1999, 2002, 2004-2011 Bruno Haible This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -43,8 +43,22 @@ extern int libsigsegv_version; /* Likewise */ /* -------------------------------------------------------------------------- */ /* + * The mask of bits that are set to zero in a fault address that gets passed + * to a global SIGSEGV handler. + * On some platforms, the precise fault address is not known, only the memory + * page into which the fault address falls. On these platforms, + * SIGSEGV_FAULT_ADDRESS_ALIGNMENT is greater than 1. + */ +#if defined __linux__ && (defined __s390__ || defined __s390x__) +# define SIGSEGV_FAULT_ADDRESS_ALIGNMENT 0x1000UL +#else +# define SIGSEGV_FAULT_ADDRESS_ALIGNMENT 1UL +#endif + +/* * The type of a global SIGSEGV handler. - * The fault address is passed as argument. + * The fault address, with the bits (SIGSEGV_FAULT_ADDRESS_ALIGNMENT - 1) + * cleared, is passed as argument. * The access type (read access or write access) is not passed; your handler * has to know itself how to distinguish these two cases. * The second argument is 0, meaning it could also be a stack overflow, or 1, @@ -176,6 +190,8 @@ extern void sigsegv_init (sigsegv_dispatcher* dispatcher); /* * Adds a local SIGSEGV handler to a sigsegv_dispatcher structure. * It will cover the interval [address..address+len-1]. + * The address and len arguments must be multiples of + * SIGSEGV_FAULT_ADDRESS_ALIGNMENT. * Returns a "ticket" that can be used to remove the handler later. */ extern void* sigsegv_register (sigsegv_dispatcher* dispatcher, diff --git a/tests/sigsegv1.c b/tests/sigsegv1.c index ce00642..e59018b 100644 --- a/tests/sigsegv1.c +++ b/tests/sigsegv1.c @@ -1,5 +1,5 @@ /* Test that the handler is called, with the right fault address. - Copyright (C) 2002-2006, 2008 Bruno Haible + Copyright (C) 2002-2006, 2008, 2011 Bruno Haible This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -37,7 +37,8 @@ handler (void *fault_address, int serious) handler_called++; if (handler_called > 10) abort (); - if (fault_address != (void *)(page + 0x678)) + if (fault_address + != (void *)((page + 0x678) & ~(SIGSEGV_FAULT_ADDRESS_ALIGNMENT - 1))) abort (); if (mprotect ((void *) page, 0x4000, PROT_READ_WRITE) == 0) return 1; diff --git a/tests/sigsegv2.c b/tests/sigsegv2.c index 39961a6..775a56a 100644 --- a/tests/sigsegv2.c +++ b/tests/sigsegv2.c @@ -1,5 +1,5 @@ /* Test the dispatcher. - Copyright (C) 2002-2006, 2008 Bruno Haible + Copyright (C) 2002-2006, 2008, 2011 Bruno Haible This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,6 +32,10 @@ static sigsegv_dispatcher dispatcher; static volatile unsigned int logcount = 0; static volatile unsigned long logdata[10]; +/* Note about SIGSEGV_FAULT_ADDRESS_ALIGNMENT: It does not matter whether + fault_address is rounded off here because all intervals that we pass to + sigsegv_register are page-aligned. */ + static int area_handler (void *fault_address, void *user_arg) { diff --git a/tests/sigsegv3.c b/tests/sigsegv3.c index 1ea0ec4..397e356 100644 --- a/tests/sigsegv3.c +++ b/tests/sigsegv3.c @@ -1,5 +1,5 @@ /* Test that the handler can be exited multiple times. - Copyright (C) 2002-2006, 2008 Bruno Haible + Copyright (C) 2002-2006, 2008, 2011 Bruno Haible This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -56,7 +56,8 @@ handler (void *fault_address, int serious) handler_called++; if (handler_called > 10) abort (); - if (fault_address != (void *)(page + 0x678 + 8 * pass)) + if (fault_address != (void *)((page + 0x678 + 8 * pass) + & ~(SIGSEGV_FAULT_ADDRESS_ALIGNMENT - 1))) abort (); pass++; printf ("Stack overflow %d caught.\n", pass); -- 2.11.4.GIT