/**********************************************************************
 * Copyright (c) 2005, 2009 IBM Corporation and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: ossdebug.cpp,v 1.9 2009/08/26 14:59:57 jwest Exp $
 *
 * Contributors:
 * IBM - Initial API and implementation
 **********************************************************************/

/*******************************************************************************

   Source File Name = ossdebug.C

   Descriptive Name = Run-time OSSe debugging code

   Function:
      Defines:
         ossAssertFailed
         ossCheckPtr
         ossIsBadReadPtr
         ossIsBadWritePtr
         ossIsBadStringPtr

   Dependencies:
      None

   Restrictions:
      None

   Change Activity:
   Defect Date        Who Description
   ====== =========== === ==============================================
   161486 Nov/25/2000 jpk Initial drop
   162796 Dec/19/2000 jpk Added "const" pointers to ossIsBadReadPtr and
                          ossIsBadStringPtr
   162924 Dec/19/2000 jpk Fixed ossIsBadStringPtr on Windows
   163585 Jan/09/2001 jpk Changed sys/signal.h to signal.h

   Last Changed =    02/08/27  12:38:12

*******************************************************************************/

#include <stddef.h>
#include <stdio.h>

#ifdef __OS400__
	#include <stdlib.h>
#endif

#if defined SQLUNIX
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#elif defined SQLWINT
#include <windows.h>
#endif
#if defined (SQLLinux) || defined (MVS)
/* 186135 - added this to define uintptr_t */
#include <stdint.h>
#endif

#include "oss.h"
#include "osserror.h"
#include "ossdebug.h"

/* Copyright */
static char *kCBIBMCopyright="(c) Copyright IBM Corporation 2000";

/******************************************************************************
   ASSERTIONS
******************************************************************************/

/******************************************************************************

   Function Name
      ossAssertFailed

   Function
      This function is called when the an assertion has failed.  The
      behaviour depends on the platform:

      Common - An assertion failed error message is sent to stderr.

      Windows - A debugger breakpoint is generated using inline
      assembly.

      UNIX - The abort() function is called to generate a core.

      OS/2 - TODO

   Inputs
      1. pszExpression
      Address of a null-terminated string that contains the expression
      that evaluated to failure.
      2. pszFilename
      Address of a null-terminated string that contains the source code
      filename where the assertion failed.
      3. lineNumber
      Source code line number where the assertion failed.

******************************************************************************/
OSS_EXTERNC void OSS_API ossAssertFailed(
      const char * pszExpression,
      const char * pszFilename,
      size_t       lineNumber )
{
   fprintf( stderr,
            "ASSERTION FAILED = %s\nFile = %s\nLine = %lu\n",
            pszExpression,
            pszFilename,
            lineNumber ) ;

#if defined SQLWINT
   /*
    * On Windows generate a debugger breakpoint using inline assembly.
    * A window will appear on the user's screen notifying them that a
    * breakpoint has been encountered.  If a debugger is installed they will
    * be able to attach at this instruction.
    */
#ifndef _WIN64
   __asm int 3
#else
   abort() ;
#endif
#elif defined SQLUNIX
   abort() ;
#else
   /* TODO */
#endif
}


/******************************************************************************
   MEMORY ACCESS VALIDATION
******************************************************************************/
#if defined SQLUNIX
#define OSS_CHECK_PTR_READ    1
#define OSS_CHECK_PTR_WRITE   2
#define OSS_CHECK_PTR_STRING  3

sigjmp_buf ossCheckPtrJmpBuffer ;

/******************************************************************************

   Function Name
      ossCheckPtrSignalHandler

   Function
      Signal handler for ossCheckPtr function.

   Inputs
      1. signal
      Signal received.

******************************************************************************/
static void ossCheckPtrSignalHandler( int signal )
{
   siglongjmp( ossCheckPtrJmpBuffer, 0 ) ;
}

/******************************************************************************

   Function Name
      ossCheckPtr

   Function
      Implements the ossIsBadReadptr, ossIsBadWritePtr,
      ossIsBadStringPtr functions.

******************************************************************************/
static OSSErr ossCheckPtr(
      const void * ptr,
      size_t size,
      Uint32 option )
{
   OSSErr osserr = OSS_OK ;
   void (*oldSIGSEGV) (int) ;
#if defined SIGTRAP
   void (*oldSIGTRAP) (int) ;
#endif
   sigset_t newMask ;
   sigset_t oldMask ;
   ptrdiff_t diff ;
   char * pByte ;
   volatile char firstByte ;
   volatile char lastByte ;
#ifdef __OS400__
   Uint32 lastByteIndex ; //230912: changed to Uint32 instead
#else
   uintptr_t lastByteIndex ;
#endif

   if ( NULL == ptr )
   {
      osserr = OSS_ERR_FAILED ;
      goto exit ;
   }

   if ( 0 == size )
   {
      osserr = OSS_OK ;
      goto exit ;
   }

   /* Install signal handler and unmask the signals */
   oldSIGSEGV = signal( SIGSEGV, ossCheckPtrSignalHandler ) ;
#if defined SIGTRAP
   /* SIGTRAP is sometimes received on illegal accesses */
   oldSIGTRAP = signal( SIGTRAP, ossCheckPtrSignalHandler ) ;
#endif
   sigemptyset( &newMask ) ;
   sigaddset( &newMask, SIGSEGV ) ;
#if defined SIGTRAP
   sigaddset( &newMask, SIGTRAP ) ;
#endif
   sigprocmask( SIG_UNBLOCK, &newMask, &oldMask ) ;

   /* Setup the long jump buffer in case we trap while validating the memory */
   if ( sigsetjmp( ossCheckPtrJmpBuffer, 1 ) != 0 )
   {
      osserr = OSS_ERR_FAILED ;
      goto restoreSignalState ;
   }

   /* Test for valid memory access depending on the specified option */
   pByte = (char *)ptr ;
   lastByteIndex = size - 1 ;

   /* Check the location of the string's null-terminator */
   if ( OSS_CHECK_PTR_STRING == option )
   {
#ifdef __OS400__
      diff = (ptrdiff_t)( (char*)strchr( pByte, '\0' ) - pByte );
#else
      diff = (ptrdiff_t)( strchr( pByte, '\0' ) - pByte );
#endif
      if ( ( diff < 0 ) || ( diff > (ptrdiff_t)size ) )
      {
         osserr = OSS_ERR_FAILED ;
         goto restoreSignalState ;
      }
   }

   /* Access the first and last byte in the memory range */
   switch ( option )
   {
   case OSS_CHECK_PTR_STRING :
   case OSS_CHECK_PTR_READ :
      /* Read first and last byte */
      firstByte = *pByte ;
      lastByte  = *(pByte + lastByteIndex) ;
      break ;

   case OSS_CHECK_PTR_WRITE :
      /* Read and write first byte */
      firstByte = *pByte ;
      *(volatile char *)pByte = firstByte ;

      /* Read and write last byte */
      lastByte  = *(pByte + lastByteIndex) ;
      *((volatile char *)pByte + lastByteIndex) = lastByte ;
      break ;

   default :
      OSS_ASSERT( !"Invalid option" ) ;
      break ;
   }

   OSS_ASSERT( OSS_OK == osserr ) ;

restoreSignalState:
   sigprocmask( SIG_SETMASK, &oldMask, NULL ) ;
   signal( SIGSEGV, oldSIGSEGV ) ;
#if defined SIGTRAP
   signal( SIGTRAP, oldSIGTRAP ) ;
#endif

exit:
   return osserr ;
}
#endif /* SQLUNIX */

/******************************************************************************
   See description in the header file
******************************************************************************/
OSS_EXTERNC OSSErr OSS_API ossIsBadReadPtr(
      const void * ptr,
      size_t size )
{
#if defined SQLUNIX
   return ossCheckPtr( ptr, size, OSS_CHECK_PTR_READ ) ;
#elif defined SQLWINT
   if ( IsBadReadPtr( ptr, (UINT)size ) )
      return OSS_ERR_FAILED ;
   else
      return OSS_OK ;
#elif defined SQLOS2
   /* TODO */
   return OSS_OK ;
#else
#error Undefined operating system
#endif
}

/******************************************************************************
   See description in the header file
******************************************************************************/
OSS_EXTERNC OSSErr OSS_API ossIsBadWritePtr(
      void * ptr,
      size_t size )
{
#if defined SQLUNIX
   return ossCheckPtr( ptr, size, OSS_CHECK_PTR_WRITE ) ;
#elif defined SQLWINT
   if ( IsBadWritePtr( ptr, (UINT)size ) )
      return OSS_ERR_FAILED ;
   else
      return OSS_OK ;
#elif defined SQLOS2
   /* TODO */
   return OSS_OK ;
#else
#error Undefined operating system
#endif
}

/******************************************************************************
   See description in the header file
******************************************************************************/
OSS_EXTERNC OSSErr OSS_API ossIsBadStringPtr(
      const char * psz,
      size_t length )
{
#if defined SQLUNIX
   return ossCheckPtr( (const void *)psz, ( length * sizeof( char ) ),
                       OSS_CHECK_PTR_STRING ) ;
#elif defined SQLWINT
   if ( IsBadStringPtr( psz, (UINT)length ) )
      return OSS_ERR_FAILED ;
   else
      return OSS_OK ;
#elif defined SQLOS2
   /* TODO */
   return OSS_OK ;
#else
#error Undefined operating system
#endif
}

/******************************************************************************
 *  The following functions are required to build on linux/390.
 *  osslatch.h includes asm/system.h which defines __xchg().
 *  __xchg() calls these functions, that are defined in the 2.4 Kernel in misaligned.c,
 *  for debugging purposes.  We'll define them here so we aren't dependent on
 *  the Kernel.
 ******************************************************************************/
#if defined(__linux__) && defined(__s390__)

 #ifdef __cplusplus
 extern "C" {
 #endif 

void __misaligned_u16(void)
{
   printf("misaligned (__u16 *) in __xchg\n");
}

void __misaligned_u32(void)
{
   printf("misaligned (__u32 *) in __xchg\n");
}

void __misaligned_u64(void)
{
   printf("misaligned (__u64 *) in __xchg\n");
}

#ifdef __cplusplus
 }
 #endif 
 
#endif
