This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH, RFC] Enable libsanitizer on powerpc{,64}


On Fri, Nov 16, 2012 at 3:08 PM, Peter Bergner <bergner@vnet.ibm.com> wrote:
> Attached below is an initial port of ASAN to powerpc*-linux.
> With the patch below along with Jakub's ASAN testsuite patch:
>
>   http://gcc.gnu.org/ml/gcc-patches/2012-11/msg01365.html
>
> ASAN not only builds, but seems to be working.

Outstanding!

> The lone ASAN
> test case does fail, but it seems to be related to us using
> _Unwind_Backtrace() and we end up with two extra frames at the
> bottom of our stack frame, so we don't match the expected
> results.

Maybe just drop those two frames before reporting them?
(if we always have them)

>
> ==47550== ERROR: AddressSanitizer stack-buffer-overflow on address 0x0fffe65540a4 at pc 0xfff769d0d70 bp 0xfffe6553ed0 sp 0xfffe6553fe8
> READ of size 1 at 0x0fffe65540a4 thread T0
>     #0 0xfff769dc388 in _ZN6__asan13GetStackTraceEPN11__sanitizer10StackTraceEmmm /home/bergner/gcc/gcc-fsf-mainline-asan/libsanitizer/asan/asan_linux.cc:160
>     #1 0xfff769df4f0 in __asan_report_error /home/bergner/gcc/gcc-fsf-mainline-asan/libsanitizer/asan/asan_report.cc:471 (discriminator 5)
>     #2 0xfff769d0dbc in __interceptor_memcmp /home/bergner/gcc/gcc-fsf-mainline-asan/libsanitizer/asan/asan_interceptors.cc:218 (discriminator 1)
>     #3 0x10000b4c in main /home/bergner/gcc/gcc-fsf-mainline-asan/gcc/testsuite/c-c++-common/asan/memcmp-1.c:12
>
> ...which doesn't match:
>
> /* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)memcmp |\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> /* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>
> because the frame numbers are off.  Any ideas on how to fix that?
>
> We cannot use the FastUnwindStack, since that uses exclusively the
> frame pointer which ppc almost never uses.  We also can have stack
> frames above or below the stack pointer, depending on whether the
> function is a leaf or not.  And with shrink wrapping, can we even
> be sure if the frame pointer is even setup even on those systems
> that do use the frame pointer?  I've seen others say we should
> use libbacktrace, and I think I have to agree with them for the
> reasons above.

FastUnwindStack is clearly x86-only thing.
I'd love to have fast solutions for other architectures, but for now
libbacktrace (or any other library call)
is ok for non-x86.
We just need to make sure that those functions do not call malloc/etc.


>
> One question that I have is that the toplev.c test for port support
> tests for !FRAME_GROWS_DOWNWARD.  The rs6000 port has FRAME_GROWS_DOWNWARD
> defined as (flag_stack_protect != 0), so ASAN only works when we use
> -fstack-protector.  Is there a technical reason why FRAME_GROWS_DOWNWARD
> must be false?

<Hopefully some one else can comment here>

>
> I should also note, the code setting the page size is very fragile.
> On PPC/PPC64 kernels, you can configure the kernel to use different
> page sizes.  My systems are running 64K page sizes, but could just
> as easily be 4K or some other number.  Shouldn't we be calling
> getpagesize() or sysconf() to query the page size and then computing
> the other values from that?
>
> I also don't like all the #ifdef's sprinkling the code.  Can't we
> use some configure fragments to help remove many/most of these?

We'll probably have to add some config-like headers as we get more platforms.
Not necessarily now.

>
> Does anyone have any thoughts on the patch?  Does it look reasonable?
>
> Peter
>
>
> gcc/
>         * config/rs6000/rs6000.c (TARGET_ASAN_SHADOW_OFFSET): Define.
>         (rs6000_asan_shadow_offset): New function.
>
> libsanitizer/
>         * configure.tgt: Enable build on powerpc and powerpc64 linux.
>         * sanitizer_common/sanitizer_common.h (kPageSizeBits): Set for powerpc
>         and powerpc64.
>         (kPageSize): Likewise.
>         (kCacheLineSize): Likewise.
>         (kMmapGranularity): Likewise.
>         * sanitizer_common/sanitizer_linux.cc (__NR_mmap) Call for powerpc64.
>         (__NR_fstat): Likewise.
>         * sanitizer_common/sanitizer_stacktrace.cc (patch_pc): Align to 4 bytes.
>         * asan/asan_mapping.h (SHADOW_OFFSET): Define for powerpc and powerpc64.
>         (kHighMemEnd): Set for powerpc and powerpc64.
>         * asan/asan_linux.cc (GetPcSpBp): Add powerpc and powerpc64 support.
>         (GetStackTrace): Use _Unwind_Backtrace for powerpc and powerpc64.
>
> Index: libsanitizer/configure.tgt
> ===================================================================
> --- libsanitizer/configure.tgt  (revision 193575)
> +++ libsanitizer/configure.tgt  (working copy)
> @@ -20,6 +20,8 @@
>
>  # Filter out unsupported systems.
>  case "${target}" in
> +  powerpc*-*-linux*)
> +       ;;
>    x86_64-*-linux* | i?86-*-linux* | sparc*-*-linux*)
>         ;;
>    *)
> Index: libsanitizer/sanitizer_common/sanitizer_common.h
> ===================================================================
> --- libsanitizer/sanitizer_common/sanitizer_common.h    (revision 193575)
> +++ libsanitizer/sanitizer_common/sanitizer_common.h    (working copy)
> @@ -21,12 +21,24 @@
>  // Constants.
>  const uptr kWordSize = __WORDSIZE / 8;
>  const uptr kWordSizeInBits = 8 * kWordSize;
> +#if defined(__powerpc__) || defined(__powerpc64__)
> +// Current PPC64 kernels use 64K pages sizes, but they can be
> +// configured with 4K or even other sizes, so we should probably
> +// use getpagesize() or sysconf(_SC_PAGESIZE) here rather than
> +// hardcoding the values.
> +const uptr kPageSizeBits = 16;

Interesting. This may have some unexpected side effects. (or maybe not?)
It's of course ok to try like this and change it later if something got broken.

> +const uptr kPageSize = 1UL << kPageSizeBits;
> +const uptr kCacheLineSize = 128;
> +const uptr kMmapGranularity = kPageSize;
> +#elif !defined( _WIN32)
>  const uptr kPageSizeBits = 12;
>  const uptr kPageSize = 1UL << kPageSizeBits;
>  const uptr kCacheLineSize = 64;
> -#ifndef _WIN32
>  const uptr kMmapGranularity = kPageSize;
>  #else
> +const uptr kPageSizeBits = 12;
> +const uptr kPageSize = 1UL << kPageSizeBits;
> +const uptr kCacheLineSize = 64;
>  const uptr kMmapGranularity = 1UL << 16;
>  #endif
>
> Index: libsanitizer/sanitizer_common/sanitizer_linux.cc
> ===================================================================
> --- libsanitizer/sanitizer_common/sanitizer_linux.cc    (revision 193575)
> +++ libsanitizer/sanitizer_common/sanitizer_linux.cc    (working copy)
> @@ -34,7 +34,7 @@
>  // --------------- sanitizer_libc.h
>  void *internal_mmap(void *addr, uptr length, int prot, int flags,
>                      int fd, u64 offset) {
> -#if defined __x86_64__
> +#if defined(__x86_64__) || defined(__powerpc64__)
>    return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
>  #else
>    return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
> @@ -67,7 +67,7 @@
>  }
>
>  uptr internal_filesize(fd_t fd) {
> -#if defined __x86_64__
> +#if defined(__x86_64__) || defined(__powerpc64__)
>    struct stat st;
>    if (syscall(__NR_fstat, fd, &st))
>      return -1;
> Index: libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
> ===================================================================
> --- libsanitizer/sanitizer_common/sanitizer_stacktrace.cc       (revision 193575)
> +++ libsanitizer/sanitizer_common/sanitizer_stacktrace.cc       (working copy)
> @@ -31,7 +31,12 @@
>    // Cancel Thumb bit.
>    pc = pc & (~1);
>  #endif
> +#if defined(__powerpc__) || defined(__powerpc64__)
> +  // PCs are always 4 byte aligned.
> +  return pc - 4;
> +#else
>    return pc - 1;
> +#endif
>  }
>
>  static void PrintStackFramePrefix(uptr frame_num, uptr pc) {
> Index: libsanitizer/asan/asan_mapping.h
> ===================================================================
> --- libsanitizer/asan/asan_mapping.h    (revision 193575)
> +++ libsanitizer/asan/asan_mapping.h    (working copy)
> @@ -31,7 +31,11 @@
>  #  if __WORDSIZE == 32
>  #   define SHADOW_OFFSET (1 << 29)
>  #  else
> -#   define SHADOW_OFFSET (1ULL << 44)
> +#   if defined(__powerpc64__)
> +#    define SHADOW_OFFSET (1ULL << 41)
> +#   else
> +#    define SHADOW_OFFSET (1ULL << 44)
> +#   endif
>  #  endif
>  # endif
>  #endif  // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
> @@ -41,7 +45,11 @@
>  #define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
>
>  #if __WORDSIZE == 64
> +# if defined(__powerpc64__)
> +  static const uptr kHighMemEnd = 0x00000fffffffffffUL;
> +# else
>    static const uptr kHighMemEnd = 0x00007fffffffffffUL;
> +# endif
>  #else  // __WORDSIZE == 32
>    static const uptr kHighMemEnd = 0xffffffff;
>  #endif  // __WORDSIZE
> Index: libsanitizer/asan/asan_linux.cc
> ===================================================================
> --- libsanitizer/asan/asan_linux.cc     (revision 193575)
> +++ libsanitizer/asan/asan_linux.cc     (working copy)
> @@ -66,6 +66,13 @@
>    *pc = ucontext->uc_mcontext.gregs[REG_EIP];
>    *bp = ucontext->uc_mcontext.gregs[REG_EBP];
>    *sp = ucontext->uc_mcontext.gregs[REG_ESP];
> +# elif defined(__powerpc__) || defined(__powerpc64__)
> +  ucontext_t *ucontext = (ucontext_t*)context;
> +  *pc = ucontext->uc_mcontext.regs->nip;
> +  *sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
> +  // The powerpc{,64}-linux ABIs do not specify r31 as the frame
> +  // pointer, but GCC always uses r31 when we need a frame pointer.
> +  *bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
>  # elif defined(__sparc__)
>    ucontext_t *ucontext = (ucontext_t*)context;
>    uptr *stk_ptr;
> @@ -149,7 +156,7 @@
>    stack->trace[0] = pc;
>    if ((max_s) > 1) {
>      stack->max_size = max_s;
> -#ifdef __arm__
> +#if defined(__arm__) || defined(__powerpc__) || defined(__powerpc64__)
>      _Unwind_Backtrace(Unwind_Trace, stack);
>  #else
>      if (!asan_inited) return;
> Index: gcc/config/rs6000/rs6000.c
> ===================================================================
> --- gcc/config/rs6000/rs6000.c  (revision 193575)
> +++ gcc/config/rs6000/rs6000.c  (working copy)
> @@ -1186,6 +1186,9 @@
>  #undef TARGET_DELEGITIMIZE_ADDRESS
>  #define TARGET_DELEGITIMIZE_ADDRESS rs6000_delegitimize_address
>
> +#undef TARGET_ASAN_SHADOW_OFFSET
> +#define TARGET_ASAN_SHADOW_OFFSET rs6000_asan_shadow_offset
> +
>  #undef TARGET_CONST_NOT_OK_FOR_DEBUG_P
>  #define TARGET_CONST_NOT_OK_FOR_DEBUG_P rs6000_const_not_ok_for_debug_p
>
> @@ -27372,6 +27375,13 @@
>      }
>  }
>
> +/* Implement the TARGET_ASAN_SHADOW_OFFSET hook.  */
> +
> +static unsigned HOST_WIDE_INT
> +rs6000_asan_shadow_offset (void)
> +{
> +  return (unsigned HOST_WIDE_INT) 1 << (TARGET_64BIT ? 41 : 29);
> +}
>
>  /* Mask options that we want to support inside of attribute((target)) and
>     #pragma GCC target operations.  Note, we do not include things like
>
>


overall the patch looks great.
I really want it to go through LLVM tree first (otherwise we'll lose
control of the code very soon),
but I am boarding a plane and will not be available for a few days after that.
Hopefully other asan folks (CC-ed) can finish the review and commit to llvm.

Thanks!
--kcc


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]