/**
 *
 * ChoX11: XLib replacement for RISC OS
 *
 * ChoX11 debugging functions
 *
 * Copyright 2003 by Peter Naulls
 * Written by Peter Naulls
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation. No representations are made about the suitability of this
 * software for any purpose.  It is provided "as is" without express or
 * implied warranty.
 *
 */


#define XLIB_ILLEGAL_ACCESS
#define NeedFunctionPrototypes 1
#define NeedNestedPrototypes   1

#include <X11/Xlib.h> 

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <kernel.h>
#define Debugger_Disassemble 0x40380

#include "chox11.h"
#include "fortify.h"

/* RISC OS applications are loaded at 0x8000 in memory */
#define APP_BASE_ADDRESS ((unsigned char *)0x8000)

static void Chox11Debug_FatalError(const char *error) {
//  printf("*** Aiieee! ChoX11 has encountered a fatal error:\n");
//  printf("%s\nExiting.\n", error);
//  abort();
  printf(error);
}


#ifdef FORTIFY
static void Chox11Debug_Exit(void) {
  Fortify_ListAllMemory();
}
#endif


void Chox11Debug_Init(void) {

  /* Check to see if we want debugging */
  if (!getenv("Chox11$Debug")) {
    freopen("null:", "r", stdout);
    freopen("null:", "r", stderr);
  }

#ifdef FORTIFY
  printf("Chox11Debug_Init: Using Fortify memory library!\n");
  printf("Chox11Debug_Init: Fortify policy is to bail on memory faults\n");
  Fortify_SetOutputFunc(Chox11Debug_FatalError);
  atexit(Chox11Debug_Exit);
#endif

  printf("*** Using ChoX11 built on %s %s\n", __DATE__, __TIME__);
}

Bool Chox11Debug_CheckWindow(Drawable draw) {
  XDrawable *window = (XDrawable *)draw;

  return window && window->isWindow == 1;
}


Bool Chox11Debug_CheckImage(Drawable draw) {
  XDrawable *image = (XDrawable *)draw;

  return image && image->isWindow == 0;
}


Bool Chox11Debug_CheckDrawable(Drawable draw) {
  XDrawable *image = (XDrawable *)draw;

  return image && (image->isWindow == 0 || image->isWindow == 1);
}

void Chox11Debug_MemoryDump(const char *descript,
                            const void *base_address,
                            unsigned int size) {
  const unsigned int *data;
  _kernel_swi_regs regs;

  Chox11Debug_CheckPointer(base_address);
  printf("Chox11Debug_MemoryDump: %s, dumping %u bytes from %p\n",
         descript, size, base_address);  
 
  data = base_address;
  while (data < (unsigned int *)base_address + size)
  {
    regs.r[0] = *data;
    regs.r[1] = (int)data;
    _kernel_swi(Debugger_Disassemble, &regs, &regs);
    printf("%08X : %08X : %s\n", (int)data, *data, regs.r[1]);
    data++;
  }

  printf("Dumped %d bytes from %p\n\n", size, base_address);
}


/* Check that a pointer lies within our application space.
   Return True if it does, False if it's a wild pointer */
void Chox11Debug_CheckPointer(const void *ptr) {
  unsigned int current = -1, next = -1, free = -1;
  const unsigned char *top_limit, *value = ptr;

  Wimp_SlotSize(&current, &next, &free);
  top_limit = APP_BASE_ADDRESS + current;

  printf("Chox11Debug_CheckPointer: Checking %p is within %p...%p\n",
         value, APP_BASE_ADDRESS, top_limit);

  /* if the pointer is invalid, Chox11Debug_FatalError doesn't return */ 
  if(value < APP_BASE_ADDRESS || value > top_limit)
    Chox11Debug_FatalError("Chox11Debug_CheckPointer hit a wild pointer.");
}
