Blame dwarfdump/macrocheck.c

Packit cdaae3
/*
Packit cdaae3
  Copyright 2015-2016 David Anderson. All rights reserved.
Packit cdaae3
Packit cdaae3
  This program is free software; you can redistribute it and/or modify it
Packit cdaae3
  under the terms of version 2 of the GNU General Public License as
Packit cdaae3
  published by the Free Software Foundation.
Packit cdaae3
Packit cdaae3
  This program is distributed in the hope that it would be useful, but
Packit cdaae3
  WITHOUT ANY WARRANTY; without even the implied warranty of
Packit cdaae3
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Packit cdaae3
Packit cdaae3
  Further, this software is distributed without any warranty that it is
Packit cdaae3
  free of the rightful claim of any third person regarding infringement
Packit cdaae3
  or the like.  Any license provided herein, whether implied or
Packit cdaae3
  otherwise, applies only to this software file.  Patent licenses, if
Packit cdaae3
  any, provided herein do not apply to combinations of this program with
Packit cdaae3
  other software, or any other product whatsoever.
Packit cdaae3
Packit cdaae3
  You should have received a copy of the GNU General Public License along
Packit cdaae3
  with this program; if not, write the Free Software Foundation, Inc., 51
Packit cdaae3
  Franklin Street - Fifth Floor, Boston MA 02110-1301, USA.
Packit cdaae3
*/
Packit cdaae3
Packit cdaae3
#include "globals.h"
Packit cdaae3
#include "esb.h"
Packit cdaae3
#include "dwarf_tsearch.h"
Packit cdaae3
#include "macrocheck.h"
Packit cdaae3
Packit cdaae3
#define TRUE 1
Packit cdaae3
#define FALSE 0
Packit cdaae3
/*  WARNING: the tree walk functions will, if presented **tree
Packit cdaae3
    when *tree is wanted, simply find nothing. No error,
Packit cdaae3
    just bad results. So when a walk produces nothing
Packit cdaae3
    suspect a code mistake here.
Packit cdaae3
    The basic problem is void* is a terrible way to
Packit cdaae3
    pass in a pointer. But it's how tsearch was defined
Packit cdaae3
    long ago.
Packit cdaae3
*/
Packit cdaae3
Packit cdaae3
void *  macro_check_tree;    /* DWARF5 macros */
Packit cdaae3
void *  macinfo_check_tree; /* DWARF 2,3,4 macros */
Packit cdaae3
Packit cdaae3
static struct Macrocheck_Map_Entry_s * macrocheck_map_insert(
Packit cdaae3
    Dwarf_Unsigned off,
Packit cdaae3
    unsigned prim,unsigned sec, void **map);
Packit cdaae3
static struct Macrocheck_Map_Entry_s * macrocheck_map_find(
Packit cdaae3
    Dwarf_Unsigned offset,
Packit cdaae3
    void **map);
Packit cdaae3
static void macrocheck_map_destroy(void *map);
Packit cdaae3
static Dwarf_Unsigned macro_count_recs(void **base);
Packit cdaae3
Packit cdaae3
#ifdef SELFTEST
Packit cdaae3
int failcount = 0;
Packit cdaae3
#endif /* SELFTEST */
Packit cdaae3
Packit cdaae3
Packit cdaae3
static struct Macrocheck_Map_Entry_s *
Packit cdaae3
macrocheck_map_create_entry(Dwarf_Unsigned offset,
Packit cdaae3
    unsigned add_primary, unsigned add_secondary)
Packit cdaae3
{
Packit cdaae3
    struct Macrocheck_Map_Entry_s *mp =
Packit cdaae3
        (struct Macrocheck_Map_Entry_s *)
Packit cdaae3
        calloc(1,sizeof(struct Macrocheck_Map_Entry_s));
Packit cdaae3
    if (!mp) {
Packit cdaae3
        return 0;
Packit cdaae3
    }
Packit cdaae3
    mp->mp_key = offset;
Packit cdaae3
    mp->mp_len = 0;
Packit cdaae3
    mp->mp_printed = 0;
Packit cdaae3
    mp->mp_refcount_primary = add_primary;
Packit cdaae3
    mp->mp_refcount_secondary = add_secondary;
Packit cdaae3
    return mp;
Packit cdaae3
}
Packit cdaae3
static void
Packit cdaae3
macrocheck_map_free_func(void *mx)
Packit cdaae3
{
Packit cdaae3
    struct Macrocheck_Map_Entry_s *m = mx;
Packit cdaae3
    free(m);
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static int
Packit cdaae3
macrocheck_map_compare_func(const void *l, const void *r)
Packit cdaae3
{
Packit cdaae3
    const struct Macrocheck_Map_Entry_s *ml = l;
Packit cdaae3
    const struct Macrocheck_Map_Entry_s *mr = r;
Packit cdaae3
    if (ml->mp_key < mr->mp_key) {
Packit cdaae3
        return -1;
Packit cdaae3
    }
Packit cdaae3
    if (ml->mp_key > mr->mp_key) {
Packit cdaae3
        return 1;
Packit cdaae3
    }
Packit cdaae3
    return 0;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static struct Macrocheck_Map_Entry_s *
Packit cdaae3
macrocheck_map_insert(Dwarf_Unsigned offset,
Packit cdaae3
    unsigned add_prim,unsigned add_sec,void **tree1)
Packit cdaae3
{
Packit cdaae3
    void *retval = 0;
Packit cdaae3
    struct Macrocheck_Map_Entry_s *re = 0;
Packit cdaae3
    struct Macrocheck_Map_Entry_s *e;
Packit cdaae3
    e  = macrocheck_map_create_entry(offset,add_prim,add_sec);
Packit cdaae3
    /*  tsearch records e's contents unless e
Packit cdaae3
        is already present . We must not free it till
Packit cdaae3
        destroy time if it got added to tree1.  */
Packit cdaae3
    retval = dwarf_tsearch(e,tree1, macrocheck_map_compare_func);
Packit cdaae3
    if (retval) {
Packit cdaae3
        re = *(struct Macrocheck_Map_Entry_s **)retval;
Packit cdaae3
        if (re != e) {
Packit cdaae3
            /*  We returned an existing record, e not needed.
Packit cdaae3
                Increment refcounts. */
Packit cdaae3
            re->mp_refcount_primary += add_prim;
Packit cdaae3
            re->mp_refcount_secondary += add_sec;
Packit cdaae3
            macrocheck_map_free_func(e);
Packit cdaae3
        } else {
Packit cdaae3
            /* Record e got added to tree1, do not free record e. */
Packit cdaae3
        }
Packit cdaae3
    }
Packit cdaae3
    return NULL;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static struct Macrocheck_Map_Entry_s *
Packit cdaae3
macrocheck_map_find(Dwarf_Unsigned offset,void **tree1)
Packit cdaae3
{
Packit cdaae3
    void *retval = 0;
Packit cdaae3
    struct Macrocheck_Map_Entry_s *re = 0;
Packit cdaae3
    struct Macrocheck_Map_Entry_s *e = 0;
Packit cdaae3
Packit cdaae3
    e = macrocheck_map_create_entry(offset,0,0);
Packit cdaae3
    retval = dwarf_tfind(e,tree1, macrocheck_map_compare_func);
Packit cdaae3
    if (retval) {
Packit cdaae3
        re = *(struct Macrocheck_Map_Entry_s **)retval;
Packit cdaae3
    }
Packit cdaae3
    /*  The one we created here must be deleted, it is dead.
Packit cdaae3
        We look at the returned one instead. */
Packit cdaae3
    macrocheck_map_free_func(e);
Packit cdaae3
    return re;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static void
Packit cdaae3
macrocheck_map_destroy(void *map)
Packit cdaae3
{
Packit cdaae3
    /* tdestroy is not part of Posix. */
Packit cdaae3
    dwarf_tdestroy(map,macrocheck_map_free_func);
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
Packit cdaae3
void
Packit cdaae3
add_macro_import(void **base,Dwarf_Bool is_primary,Dwarf_Unsigned offset)
Packit cdaae3
{
Packit cdaae3
    Dwarf_Unsigned prim_count  = 0;
Packit cdaae3
    Dwarf_Unsigned sec_count  = 0;
Packit cdaae3
Packit cdaae3
    if(is_primary) {
Packit cdaae3
        prim_count = 1;
Packit cdaae3
    } else {
Packit cdaae3
        sec_count = 1;
Packit cdaae3
    }
Packit cdaae3
    macrocheck_map_insert(offset,prim_count,sec_count,base);
Packit cdaae3
}
Packit cdaae3
void
Packit cdaae3
add_macro_import_sup(UNUSEDARG void **base,
Packit cdaae3
    UNUSEDARG Dwarf_Unsigned offset)
Packit cdaae3
{
Packit cdaae3
    /* FIXME */
Packit cdaae3
    return;
Packit cdaae3
}
Packit cdaae3
void
Packit cdaae3
add_macro_area_len(void **base, Dwarf_Unsigned offset,
Packit cdaae3
    Dwarf_Unsigned len)
Packit cdaae3
{
Packit cdaae3
    struct Macrocheck_Map_Entry_s *re = 0;
Packit cdaae3
Packit cdaae3
    re = macrocheck_map_find(offset,base);
Packit cdaae3
    if (re) {
Packit cdaae3
        re->mp_len = len;
Packit cdaae3
    }
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static Dwarf_Unsigned reccount = 0;
Packit cdaae3
Packit cdaae3
static void
Packit cdaae3
macro_walk_count_recs(UNUSEDARG const void *nodep,
Packit cdaae3
    const DW_VISIT which,
Packit cdaae3
    UNUSEDARG const int depth)
Packit cdaae3
{
Packit cdaae3
    if (which == dwarf_postorder || which == dwarf_endorder) {
Packit cdaae3
        return;
Packit cdaae3
    }
Packit cdaae3
    reccount += 1;
Packit cdaae3
}
Packit cdaae3
static Dwarf_Unsigned
Packit cdaae3
macro_count_recs(void **base)
Packit cdaae3
{
Packit cdaae3
    reccount = 0;
Packit cdaae3
    dwarf_twalk(*base,macro_walk_count_recs);
Packit cdaae3
    return reccount;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static Dwarf_Unsigned lowestoff = 0;
Packit cdaae3
static Dwarf_Bool lowestfound = FALSE;
Packit cdaae3
static void
Packit cdaae3
macro_walk_find_lowest(const void *nodep,const DW_VISIT  which,
Packit cdaae3
    UNUSEDARG const int  depth)
Packit cdaae3
{
Packit cdaae3
    struct Macrocheck_Map_Entry_s * re =
Packit cdaae3
        *(struct Macrocheck_Map_Entry_s**)nodep;
Packit cdaae3
Packit cdaae3
    if (which == dwarf_postorder || which == dwarf_endorder) {
Packit cdaae3
        return;
Packit cdaae3
    }
Packit cdaae3
    if (!re->mp_printed) {
Packit cdaae3
        if (lowestfound) {
Packit cdaae3
            if (lowestoff > re->mp_key) {
Packit cdaae3
                lowestoff = re->mp_key;
Packit cdaae3
            }
Packit cdaae3
        } else {
Packit cdaae3
            lowestfound = TRUE;
Packit cdaae3
            lowestoff = re->mp_key;
Packit cdaae3
        }
Packit cdaae3
    }
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
int
Packit cdaae3
get_next_unprinted_macro_offset(void **tree, Dwarf_Unsigned * off)
Packit cdaae3
{
Packit cdaae3
    lowestfound = FALSE;
Packit cdaae3
    lowestoff = 0;
Packit cdaae3
Packit cdaae3
    /*  This walks the tree to find one entry.
Packit cdaae3
        Which could get slow if the tree has lots of entries. */
Packit cdaae3
    dwarf_twalk(*tree,macro_walk_find_lowest);
Packit cdaae3
    if (!lowestfound) {
Packit cdaae3
        return DW_DLV_NO_ENTRY;
Packit cdaae3
    }
Packit cdaae3
    *off = lowestoff;
Packit cdaae3
    return DW_DLV_OK;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
void
Packit cdaae3
mark_macro_offset_printed(void **base, Dwarf_Unsigned offset)
Packit cdaae3
{
Packit cdaae3
    struct Macrocheck_Map_Entry_s *re = 0;
Packit cdaae3
Packit cdaae3
    re = macrocheck_map_find(offset,base);
Packit cdaae3
    if (re) {
Packit cdaae3
        re->mp_printed = TRUE;
Packit cdaae3
    }
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
Packit cdaae3
static struct Macrocheck_Map_Entry_s **mac_as_array = 0;
Packit cdaae3
static unsigned mac_as_array_next = 0;
Packit cdaae3
static void
Packit cdaae3
macro_walk_to_array(const void *nodep,const DW_VISIT  which,
Packit cdaae3
    UNUSEDARG const int  depth)
Packit cdaae3
{
Packit cdaae3
    struct Macrocheck_Map_Entry_s * re =
Packit cdaae3
        *(struct Macrocheck_Map_Entry_s**)nodep;
Packit cdaae3
Packit cdaae3
    if (which == dwarf_postorder || which == dwarf_endorder) {
Packit cdaae3
        return;
Packit cdaae3
    }
Packit cdaae3
    mac_as_array[mac_as_array_next] = re;
Packit cdaae3
    mac_as_array_next++;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static int
Packit cdaae3
qsort_compare(const void *lin, const void *rin)
Packit cdaae3
{
Packit cdaae3
    const struct Macrocheck_Map_Entry_s *l =
Packit cdaae3
        *(const struct Macrocheck_Map_Entry_s **)lin;
Packit cdaae3
    const struct Macrocheck_Map_Entry_s *r =
Packit cdaae3
        *(const struct Macrocheck_Map_Entry_s **)rin;
Packit cdaae3
    if (l->mp_key < r->mp_key) {
Packit cdaae3
        return -1;
Packit cdaae3
    }
Packit cdaae3
    if (l->mp_key > r->mp_key) {
Packit cdaae3
        return 1;
Packit cdaae3
    }
Packit cdaae3
    if (l->mp_len < r->mp_len) {
Packit cdaae3
        return -1;
Packit cdaae3
    }
Packit cdaae3
    if (l->mp_len > r->mp_len) {
Packit cdaae3
        return 1;
Packit cdaae3
    }
Packit cdaae3
    return 0;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
void
Packit cdaae3
print_macro_statistics(const char *name,void **tsbase,
Packit cdaae3
    Dwarf_Unsigned section_size)
Packit cdaae3
{
Packit cdaae3
    Dwarf_Unsigned count = 0;
Packit cdaae3
    Dwarf_Unsigned lowest = -1ll;
Packit cdaae3
    Dwarf_Unsigned highest = 0;
Packit cdaae3
    Dwarf_Unsigned lastend = 0;
Packit cdaae3
    Dwarf_Unsigned laststart = 0;
Packit cdaae3
    Dwarf_Unsigned internalgap = 0;
Packit cdaae3
    Dwarf_Unsigned wholegap = 0;
Packit cdaae3
    Dwarf_Unsigned i = 0;
Packit cdaae3
Packit cdaae3
    if(! *tsbase) {
Packit cdaae3
        return;
Packit cdaae3
    }
Packit cdaae3
    count = macro_count_recs(tsbase);
Packit cdaae3
    if (count < 1) {
Packit cdaae3
        return;
Packit cdaae3
    }
Packit cdaae3
    free(mac_as_array);
Packit cdaae3
    mac_as_array = 0;
Packit cdaae3
    mac_as_array_next = 0;
Packit cdaae3
    mac_as_array = (struct Macrocheck_Map_Entry_s **)calloc(count,
Packit cdaae3
        sizeof(struct Macrocheck_Map_Entry_s *));
Packit cdaae3
    if(!mac_as_array) {
Packit cdaae3
#ifdef SELFTEST
Packit cdaae3
        ++failcount;
Packit cdaae3
#endif
Packit cdaae3
        printf("  Macro checking ERROR %s: "
Packit cdaae3
            "unable to allocate %" DW_PR_DUu "pointers\n",
Packit cdaae3
            name,
Packit cdaae3
            count);
Packit cdaae3
        return;
Packit cdaae3
    }
Packit cdaae3
    dwarf_twalk(*tsbase,macro_walk_to_array);
Packit cdaae3
    printf("  Macro unit count %s: %" DW_PR_DUu "\n",name,count);
Packit cdaae3
    qsort(mac_as_array,
Packit cdaae3
        count,sizeof(struct Macrocheck_Map_Entry_s *),
Packit cdaae3
        qsort_compare);
Packit cdaae3
    for (i = 0; i < count ; ++i) {
Packit cdaae3
        Dwarf_Unsigned end = 0;
Packit cdaae3
        struct Macrocheck_Map_Entry_s *r = mac_as_array[i];
Packit cdaae3
#if 0
Packit cdaae3
        printf("debugging: i %u off 0x%x len 0x%x printed? %u "
Packit cdaae3
            " ref prim: %u  sec: %u\n",
Packit cdaae3
            (unsigned)i,
Packit cdaae3
            (unsigned)r->mp_key,
Packit cdaae3
            (unsigned)r->mp_len,
Packit cdaae3
            (unsigned)r->mp_printed,
Packit cdaae3
            (unsigned)r->mp_refcount_primary,
Packit cdaae3
            (unsigned)r->mp_refcount_secondary);
Packit cdaae3
#endif
Packit cdaae3
        if (r->mp_key < lowest) {
Packit cdaae3
            lowest = r->mp_key;
Packit cdaae3
        }
Packit cdaae3
        end = r->mp_key + r->mp_len;
Packit cdaae3
        if (end > highest) {
Packit cdaae3
            highest = end;
Packit cdaae3
        }
Packit cdaae3
        if (r->mp_refcount_primary > 1) {
Packit cdaae3
#ifdef SELFTEST
Packit cdaae3
            ++failcount;
Packit cdaae3
#endif
Packit cdaae3
            printf(" ERROR: For offset 0x%" DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
                " %" DW_PR_DUu
Packit cdaae3
                " there is a primary count of "
Packit cdaae3
                "0x%"  DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
                " %"  DW_PR_DUu "\n",
Packit cdaae3
                r->mp_key,
Packit cdaae3
                r->mp_key,
Packit cdaae3
                r->mp_refcount_primary,
Packit cdaae3
                r->mp_refcount_primary);
Packit cdaae3
        }
Packit cdaae3
        if (r->mp_refcount_primary && r->mp_refcount_secondary) {
Packit cdaae3
#ifdef SELFTEST
Packit cdaae3
            ++failcount;
Packit cdaae3
#endif
Packit cdaae3
            printf(" ERROR: For offset 0x%" DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
                " %" DW_PR_DUu
Packit cdaae3
                " there is a nonzero primary count of "
Packit cdaae3
                "0x%"  DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
                " %" DW_PR_DUu
Packit cdaae3
                " with a secondary count of "
Packit cdaae3
                "0x%"  DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
                " %" DW_PR_DUu
Packit cdaae3
                "\n",
Packit cdaae3
                r->mp_key,
Packit cdaae3
                r->mp_key,
Packit cdaae3
                r->mp_refcount_primary,
Packit cdaae3
                r->mp_refcount_primary,
Packit cdaae3
                r->mp_refcount_secondary,
Packit cdaae3
                r->mp_refcount_secondary);
Packit cdaae3
        }
Packit cdaae3
    }
Packit cdaae3
    lastend =
Packit cdaae3
        mac_as_array[0]->mp_key +
Packit cdaae3
        mac_as_array[0]->mp_len;
Packit cdaae3
    laststart = mac_as_array[0]->mp_key;
Packit cdaae3
    printf("  Macro Offsets start at 0x%" DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
        " and end at 0x%" DW_PR_XZEROS DW_PR_DUx "\n",
Packit cdaae3
        lowest, highest);
Packit cdaae3
    for (i = 1; i < count ; ++i) {
Packit cdaae3
        struct Macrocheck_Map_Entry_s *r = mac_as_array[i];
Packit cdaae3
#if 0
Packit cdaae3
        printf("debugging i %u off 0x%x len 0x%x\n",
Packit cdaae3
            (unsigned)i,
Packit cdaae3
            (unsigned)r->mp_key,
Packit cdaae3
            (unsigned)r->mp_len);
Packit cdaae3
#endif
Packit cdaae3
        if (r->mp_key > lastend) {
Packit cdaae3
            internalgap += (r->mp_key - lastend);
Packit cdaae3
        } else if (r->mp_key < lastend) {
Packit cdaae3
            /* crazy overlap */
Packit cdaae3
#ifdef SELFTEST
Packit cdaae3
            ++failcount;
Packit cdaae3
#endif
Packit cdaae3
            printf(" ERROR: For offset 0x%" DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
                " %" DW_PR_DUu
Packit cdaae3
                " there is a crazy overlap with the previous end offset of "
Packit cdaae3
                "0x%"  DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
                " %"  DW_PR_DUu
Packit cdaae3
                " (previous start offset of 0x%"  DW_PR_XZEROS DW_PR_DUx ")"
Packit cdaae3
                " %"  DW_PR_DUu
Packit cdaae3
                "\n",
Packit cdaae3
                r->mp_key,
Packit cdaae3
                r->mp_key,
Packit cdaae3
                lastend,
Packit cdaae3
                lastend,
Packit cdaae3
                laststart,
Packit cdaae3
                laststart);
Packit cdaae3
        }
Packit cdaae3
        laststart = r->mp_key;
Packit cdaae3
        lastend   = laststart + r->mp_len;
Packit cdaae3
    }
Packit cdaae3
    /*  wholegap is a) starting offset > 0 and b)
Packit cdaae3
        space after used area before end of section. */
Packit cdaae3
    wholegap = mac_as_array[0]->mp_key + internalgap;
Packit cdaae3
    if (lastend > section_size) {
Packit cdaae3
        /* Something seriously wrong */
Packit cdaae3
#ifdef SELFTEST
Packit cdaae3
        ++failcount;
Packit cdaae3
#endif
Packit cdaae3
        printf(" ERROR: For offset 0x%" DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
            " %" DW_PR_DUu
Packit cdaae3
            " there is an overlap with the end of section "
Packit cdaae3
            "0x%"  DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
            " %" DW_PR_DUu
Packit cdaae3
            "\n",laststart,laststart,
Packit cdaae3
            lastend, lastend);
Packit cdaae3
    } else {
Packit cdaae3
        wholegap += (section_size - lastend);
Packit cdaae3
    }
Packit cdaae3
    if(wholegap) {
Packit cdaae3
        printf("  Macro Offsets internal unused space: "
Packit cdaae3
            "0x%" DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
            "\n",
Packit cdaae3
            internalgap);
Packit cdaae3
        printf("  Macro Offsets total    unused space: "
Packit cdaae3
            "0x%" DW_PR_XZEROS DW_PR_DUx
Packit cdaae3
            "\n",
Packit cdaae3
            wholegap);
Packit cdaae3
    }
Packit cdaae3
    free (mac_as_array);
Packit cdaae3
    mac_as_array = 0;
Packit cdaae3
    mac_as_array_next = 0;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
void
Packit cdaae3
clear_macro_statistics(void **tsbase)
Packit cdaae3
{
Packit cdaae3
    if(! *tsbase) {
Packit cdaae3
        return;
Packit cdaae3
    }
Packit cdaae3
    macrocheck_map_destroy(*tsbase);
Packit cdaae3
    *tsbase = 0;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
Packit cdaae3
#ifdef SELFTEST
Packit cdaae3
int
Packit cdaae3
main()
Packit cdaae3
{
Packit cdaae3
    void * base = 0;
Packit cdaae3
    Dwarf_Unsigned count = 0;
Packit cdaae3
    int basefailcount = 0;
Packit cdaae3
Packit cdaae3
    /* Test 1 */
Packit cdaae3
    add_macro_import(&base,TRUE,200);
Packit cdaae3
    count = macro_count_recs(&base);
Packit cdaae3
    if (count != 1) {
Packit cdaae3
        printf("FAIL: expect count 1, got %" DW_PR_DUu "\n",count);
Packit cdaae3
        ++failcount;
Packit cdaae3
    }
Packit cdaae3
    print_macro_statistics("test1",&base,2000);
Packit cdaae3
Packit cdaae3
    /* Test two */
Packit cdaae3
    add_macro_area_len(&base,200,100);
Packit cdaae3
    add_macro_import(&base,FALSE,350);
Packit cdaae3
    add_macro_area_len(&base,350,100);
Packit cdaae3
    count = macro_count_recs(&base);
Packit cdaae3
    if (count != 2) {
Packit cdaae3
        printf("FAIL: expect count 2, got %" DW_PR_DUu "\n",count);
Packit cdaae3
        ++failcount;
Packit cdaae3
    }
Packit cdaae3
    print_macro_statistics("test 2",&base,2000);
Packit cdaae3
    clear_macro_statistics(&base);
Packit cdaae3
Packit cdaae3
    /* Test three */
Packit cdaae3
    basefailcount = failcount;
Packit cdaae3
    add_macro_import(&base,TRUE,0);
Packit cdaae3
    add_macro_area_len(&base,0,1000);
Packit cdaae3
    add_macro_import(&base,FALSE,2000);
Packit cdaae3
    add_macro_area_len(&base,2000,100);
Packit cdaae3
    mark_macro_offset_printed(&base,2000);
Packit cdaae3
    add_macro_import(&base,FALSE,1000);
Packit cdaae3
    add_macro_area_len(&base,1000,900);
Packit cdaae3
    add_macro_import(&base,FALSE,1000);
Packit cdaae3
    add_macro_area_len(&base,1000,900);
Packit cdaae3
    count = macro_count_recs(&base);
Packit cdaae3
    if (count != 3) {
Packit cdaae3
        printf("FAIL: expect count 3, got %" DW_PR_DUu "\n",count);
Packit cdaae3
        ++failcount;
Packit cdaae3
    }
Packit cdaae3
    printf("\n  Expect an ERROR about overlap with "
Packit cdaae3
        "the end of section\n");
Packit cdaae3
    print_macro_statistics("test 3",&base,2000);
Packit cdaae3
    clear_macro_statistics(&base);
Packit cdaae3
    if ((basefailcount+1) != failcount) {
Packit cdaae3
        printf("FAIL: Found no error in test 3 checking!\n");
Packit cdaae3
        ++failcount;
Packit cdaae3
    } else {
Packit cdaae3
        failcount = basefailcount;
Packit cdaae3
    }
Packit cdaae3
Packit cdaae3
    /* Test Four */
Packit cdaae3
    basefailcount = failcount;
Packit cdaae3
    add_macro_import(&base,TRUE,50);
Packit cdaae3
    add_macro_import(&base,TRUE,50);
Packit cdaae3
    add_macro_area_len(&base,50,50);
Packit cdaae3
    add_macro_import(&base,FALSE,200);
Packit cdaae3
    add_macro_import(&base,FALSE,50);
Packit cdaae3
    add_macro_import(&base,FALSE,60);
Packit cdaae3
    add_macro_area_len(&base,60,10);
Packit cdaae3
    printf( "\n  Expect an ERROR about offset 50 having 2 primaries\n");
Packit cdaae3
    printf( "  and Expect an ERROR about offset 50 having 2\n"
Packit cdaae3
        "  primaries"
Packit cdaae3
        " and a secondary\n");
Packit cdaae3
    printf( "  and Expect an ERROR about crazy overlap 60\n\n");
Packit cdaae3
    print_macro_statistics("test 4",&base,2000);
Packit cdaae3
    clear_macro_statistics(&base);
Packit cdaae3
    if ((basefailcount + 3) != failcount) {
Packit cdaae3
        printf("FAIL: Found wrong errors in test 4 checking!\n");
Packit cdaae3
    } else {
Packit cdaae3
        failcount = basefailcount;
Packit cdaae3
    }
Packit cdaae3
    if (failcount > 0) {
Packit cdaae3
        printf("FAIL macrocheck selftest\n");
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
    printf("PASS macrocheck selftest\n");
Packit cdaae3
    return 0;
Packit cdaae3
}
Packit cdaae3
#endif /* SELFTEST */