view lwdisasm/range.c @ 414:010fb62b9f18

Fixed off by one bug in code generation for fcn
author lost@l-w.ca
date Tue, 10 Aug 2010 17:33:56 -0600
parents cba03436c720
children
line wrap: on
line source

/*
range.c

Copyright © 2010 William Astle

This file is part of LWTOOLS.

LWTOOLS is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <config.h>

#include <stdlib.h>

#include <lw_alloc.h>

#include "lwdisasm.h"

void register_range(disasmstate_t *as, int min, int max, int type)
{
	rangedata_t *nr;
	rangedata_t *r;

	// first remove any complete subsets of the new range
subsetagain:
	for (r = as -> rhead; r; r = r -> next)
	{
		// if we haven't run into an existing range yet, short circuit
		if (r -> min >= min && r -> max <= max)
		{
			if (r -> prev)
				r -> prev -> next = r -> next;
			else
				as -> rhead = r -> next;
			if (r -> next)
				r -> next -> prev = r -> prev;
			else
				as -> rtail = r -> prev;
			goto subsetagain;
		}		
	}

	// now shorten any subset that overlaps below or overlaps above
	for (r = as -> rhead; r; r = r -> next)
	{
		// are we a subset of this range?
		if (r -> min <= min && r -> max >= max)
		{
			// proper subset; split
			nr = lw_alloc(sizeof(rangedata_t));
			*nr = *r;
			r -> next = nr;
			nr -> prev = r;
			r -> max = min - 1;
			nr -> min = max + 1;
			break;
		}
		// overlap above us
		if (r -> max > max && r -> min < max)
		{
			r -> min = max + 1;
		}
		// overlap on the bottom
		if (r -> min < min &&  r -> max > min)
		{
			r -> max = min - 1;
		}
	}
	
	// now add new range
	for (r = as -> rhead; r; r = r -> next)
	{
		if (r -> min < max)
		{
			break;
		}
	}
	
	nr = lw_alloc(sizeof(rangedata_t));
	nr -> min = min;
	nr -> max = max;
	nr -> type = type;
	
	if (r)
	{
		if (r -> prev)
			r -> prev -> next = nr;
		else
			as -> rhead = nr;
		nr -> prev = r -> prev;
		nr -> next = r;
		r -> prev = nr;
	}
	else
	{
		nr -> next = NULL;
		nr -> prev = as -> rtail;
		as -> rtail -> next = nr;
		as -> rtail = nr;
	}
}

rangedata_t *lookup_range(disasmstate_t *as, int addr)
{
	rangedata_t *r;
	
	for (r = as -> rhead; r; r = r -> next)
	{
		if (r -> min <= addr && r -> max >= addr)
			return r;
	}
	return NULL;
}