/*
** Breakpoints with ptrace()
**
** (c) Rainer Schnitker 1994-1997
*/

#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/reg.h>

#include "breakp.h"

struct breakpoint bp[MAX_BP];

static void insert_int3(struct breakpoint * bp, int pid)
{
    int r;
    errno = 0;
    r = ptrace(PTRACE_PEEKTEXT, pid, bp->addr, 0);
    if (errno != 0)
	return;
    bp->save = (unsigned char) r;
    r = (r & ~0xff) | 0xcc;
    ptrace(PTRACE_POKETEXT, pid, bp->addr, r);
}

static void remove_int3(struct breakpoint * bp, int pid)
{
    int r;

    errno = 0;
    r = ptrace(PTRACE_PEEKTEXT, pid, bp->addr, 0);
    if (errno != 0)
	return;
    r = (r & ~0xff) | bp->save;
    ptrace(PTRACE_POKETEXT, pid, bp->addr, r);
}

void insert_breakpoints(int pid)
{
    int i;
    for (i = 0; i < MAX_BP; i++)
	if (bp[i].status == BP_ENABLE)
	    insert_int3(bp+i, pid);
}

void remove_breakpoints(int pid)
{
    int i;
    for (i = 0; i < MAX_BP; i++)
	if (bp[i].status == BP_ENABLE)
	    remove_int3(bp+i, pid);
}

int set_bp(int addr)
{
    int i;
    for (i = 1; i < MAX_BP; i++)
	if (!(bp[i].status))
	    break;
    if (i == MAX_BP) {
	printf("no break free\n");
	return -1;
    }
    bp[i].addr = addr;
    bp[i].status = BP_ENABLE;
    return i;
}

int delete_bp(int no)
{
    if (no >= MAX_BP || bp[no].status == 0) {
	printf("invalid break-no\n");
	return -1;
    }
    bp[no].addr = 0;
    bp[no].status = BP_UNDEF;
    return 0;
}

int disable_bp(int no)
{
    if (no <= 1 && no >= MAX_BP) {
	printf("ivalid break-no\n");
	return -1;
    }
    if (bp[no].status == BP_DISABLE) {
	printf("already disabled\n");
	return -1;
    }
    bp[no].status = BP_DISABLE;
    return 0;
}

int enable_bp(int no)
{
    if (no <= 1 && no >= MAX_BP) {
	printf("ivalid break-no\n");
	return -1;
    }
    if (bp[no].status == BP_ENABLE) {
	printf("already enabled\n");
	return -1;
    }
    bp[no].status = BP_ENABLE;
    return 0;
}
