Beispiel #1
0
static void
mytest(char *in,char *expected,int testnum)
{
    struct esb_s out;
    esb_constructor(&out);
    translate_to_uri(in, &out);
    if (strcmp(expected, esb_get_string(&out))) {
        printf(" Fail test %d expected %s got %s\n",testnum,expected,esb_get_string(&out));
        ++errcnt;
    }
    esb_destructor(&out);
}
Beispiel #2
0
static void
mytestfrom(const char * in,const char *expected,int testnum)
{
    struct esb_s out;
    esb_constructor(&out);
    translate_from_uri(in, &out);
    if (strcmp(expected, esb_get_string(&out))) {
        printf(" Fail test %d expected \"%s\" got \"%s\"\n",
            testnum,expected,esb_get_string(&out));
        ++errcnt;
    }
    esb_destructor(&out);
}
Beispiel #3
0
void
check(string msg, struct esb_s *data, string v)
{
    string b = esb_get_string(data);
    size_t l = 0;
    size_t alloc = 0;

    if (strcmp(b, v)) {
        fprintf(stderr, "ERROR: %s  content error  %s != %s\n", msg, b,
            v);
    }

    l = esb_string_len(data);

    if (l != strlen(v)) {
        fprintf(stderr, "ERROR: %s length error  %lu != %lu\n", msg,
            (unsigned long) l, (unsigned long) strlen(v));
    }
    alloc = esb_get_allocated_size(data);
    if (l > alloc) {
        fprintf(stderr, "ERROR: %s allocation error  %lu > %lu\n", msg,
            (unsigned long) l, (unsigned long) alloc);

    }

    return;
}
Beispiel #4
0
static const char *
ellipname(int res, int val_in, const char *v,const char *ty,int printonerr)
{
#ifndef TRIVIAL_NAMING
    if (glflags.gf_check_dwarf_constants && checking_this_compiler()) {
        DWARF_CHECK_COUNT(dwarf_constants_result,1);
    }
#endif
    if (res != DW_DLV_OK) {
        char buf[100];
        char *n;
#ifdef ORIGINAL_SPRINTF
        snprintf(buf,sizeof(buf),"<Unknown %s value 0x%x>",ty,val_in);
#else
        struct esb_s eb;

        esb_constructor_fixed(&eb,buf,sizeof(buf));
        esb_append_printf_s(&eb,
            "<Unknown %s",ty);
        esb_append_printf_u(&eb,
            " value 0x%x>",val_in);
#endif
        /* Capture any name error in DWARF constants */
#ifndef TRIVIAL_NAMING
        if (printonerr && glflags.gf_check_dwarf_constants &&
            checking_this_compiler()) {
            if (glflags.gf_check_verbose_mode) {
                fprintf(stderr,"%s of %d (0x%x) is unknown to dwarfdump. "
                    "Continuing. \n",ty,val_in,val_in );
            }
            DWARF_ERROR_COUNT(dwarf_constants_result,1);
            DWARF_CHECK_ERROR_PRINT_CU();
        }
#else
        /* This is for the tree-generation, not dwarfdump itself. */
        if (printonerr) {
            fprintf(stderr,"%s of %d (0x%x) is unknown to dwarfdump. "
                "Continuing. \n",ty,val_in,val_in );
        }
#endif

#ifdef ORIGINAL_SPRINTF
        n = makename(buf);
#else
        n = makename(esb_get_string(&eb));
        esb_destructor(&eb);
#endif
        return n;
    }
#ifndef TRIVIAL_NAMING
    if (glflags.ellipsis) {
        return skipunder(v);
    }
#endif
    return v;
}
Beispiel #5
0
/* Get a copy of the internal data buffer */
string
esb_get_copy(struct esb_s *data)
{
    string copy = NULL;
    size_t len = esb_string_len(data);
    if (len) {
        copy = (string)malloc(len);
        strcpy(copy,esb_get_string(data));
    }

    return copy;
}
Beispiel #6
0
static void
print_secname(Dwarf_Debug dbg, const char *secname)
{
    struct esb_s truename;
    char buf[DWARF_SECNAME_BUFFER_SIZE];

    esb_constructor_fixed(&truename,buf,sizeof(buf));
    get_true_section_name(dbg,secname,
        &truename,TRUE);
    printf("\n%s\n",sanitized(esb_get_string(&truename)));
    esb_destructor(&truename);
}
Beispiel #7
0
/* Because we do not know what DIE is involved, if the
   object being printed has different address sizes 
   in different compilation units this will not work
   properly: anything could happen. */
extern void
print_ranges(Dwarf_Debug dbg)
{
    Dwarf_Unsigned off = 0;
    int group_number = 0;
    int wasdense = 0;

    current_section_id = DEBUG_RANGES;
    if (!do_print_dwarf) {
        return;
    }
    printf("\n.debug_ranges\n");

    /*  Turn off dense, we do not want  print_ranges_list_to_extra
        to use dense form here. */
    wasdense = dense;
    dense = 0;
    for(;;) {
        Dwarf_Ranges *rangeset = 0;
        Dwarf_Signed rangecount = 0;
        Dwarf_Unsigned bytecount = 0;

        /*  We do not know what DIE is involved, we use
            the older call here. */
        int rres = dwarf_get_ranges(dbg,off,&rangeset,
            &rangecount,&bytecount,&err);
        if(rres == DW_DLV_OK) {
            char *val = 0;
            printf(" Ranges group %d:\n",group_number);
            esb_empty_string(&esb_string);
            print_ranges_list_to_extra(dbg,off,
                rangeset,rangecount,bytecount,
                &esb_string);
            dwarf_ranges_dealloc(dbg,rangeset,rangecount);
            val = esb_get_string(&esb_string);
            printf("%s",val);
            ++group_number;
        } else if (rres == DW_DLV_NO_ENTRY) {
            printf("End of .debug_ranges.\n");
            break;
        } else { 
            /*  ERROR, which does not quite mean a real error,
                as we might just be misaligned reading things without
                a DW_AT_ranges offset.*/
            printf("End of .debug_ranges..\n");
            break;
        }
        off += bytecount;
    }
    dense = wasdense;
}
Beispiel #8
0
void
validate_esb(int instance,
   struct esb_s* d,
   size_t explen,
   size_t expalloc,
   const char *expout)
{
    printf("TEST instance %d\n",instance);
    if (esb_string_len(d) != explen) {
        ++failcount;
        printf("FAIL instance %d  slen %u explen %u\n",
            instance,(unsigned)esb_string_len(d),(unsigned)explen);
    }
    if (d->esb_allocated_size != expalloc) {
        ++failcount;
        printf("FAIL instance %d  alloclen %u expalloc %u\n",
            instance,(unsigned)d->esb_allocated_size,(unsigned)expalloc);
    }
    if(strcmp(esb_get_string(d),expout)) {
        ++failcount;
        printf("FAIL instance %d  str %s expstr %s\n",
            instance,esb_get_string(d),expout);
    }
}
Beispiel #9
0
void
validate_esb(int instance,
   struct esb_s* d,
   size_t explen,
   size_t expalloc,
   const char *expout,
   int line )
{
    if (esb_string_len(d) != explen) {
        ++failcount;
        printf("  FAIL instance %d  esb_string_len() %u explen %u line %d\n",
            instance,(unsigned)esb_string_len(d),(unsigned)explen,line);
    }
    if (d->esb_allocated_size != expalloc) {
        ++failcount;
        printf("  FAIL instance %d  esb_allocated_size  %u expalloc %u line %d\n",
            instance,(unsigned)d->esb_allocated_size,(unsigned)expalloc,line);
    }
    if(strcmp(esb_get_string(d),expout)) {
        ++failcount;
        printf("  FAIL instance %d esb_get_string %s expstr %s line %d\n",
            instance,esb_get_string(d),expout,line);
    }
}
/* Unified pubnames style output.
   The error checking here against maxoff may be useless
   (in that libdwarf may return an error if the offset is bad
   and we will not get called here).
   But we leave it in nonetheless as it looks sensible.
   In at least one gigantic executable such offsets turned out wrong.
*/
void
print_pubname_style_entry(Dwarf_Debug dbg,
   char *line_title,
   char *name,
   Dwarf_Unsigned die_off,
   Dwarf_Unsigned cu_off,
   Dwarf_Unsigned global_cu_offset,
   Dwarf_Unsigned maxoff)
{
    Dwarf_Die die = NULL;
    Dwarf_Off die_CU_off = 0;
    int dres = 0;
    int ddres = 0;
    int cudres = 0;
    char tmp_buf[100];

    /* get die at die_off */
    dres = dwarf_offdie(dbg, die_off, &die, &err);
    if (dres != DW_DLV_OK) {
        struct esb_s details;
        esb_constructor(&details);
        esb_append(&details,line_title);
        esb_append(&details," dwarf_offdie : "
            "die offset does not reference valid DIE.  ");
        snprintf(tmp_buf,sizeof(tmp_buf),"0x%"  DW_PR_DUx, die_off);
        esb_append(&details,tmp_buf);
        esb_append(&details,".");
        print_error(dbg, esb_get_string(&details), dres, err);
        esb_destructor(&details);
    }

    /* get offset of die from its cu-header */
    ddres = dwarf_die_CU_offset(die, &die_CU_off, &err);
    if (ddres != DW_DLV_OK) {
        struct esb_s details;
        esb_constructor(&details);
        esb_append(&details,line_title);
        esb_append(&details," cannot get CU die offset");
        print_error(dbg, esb_get_string(&details), dres, err);
        esb_destructor(&details);
        die_CU_off = 0;
    }

    /* Get die at offset cu_off to check its existence. */
    {
        Dwarf_Die cu_die = NULL;
        cudres = dwarf_offdie(dbg, cu_off, &cu_die, &err);
        if (cudres != DW_DLV_OK) {
            struct esb_s details;
            esb_constructor(&details);
            esb_append(&details,line_title);
            esb_append(&details," dwarf_offdie: "
                "cu die offset  does not reference valid CU DIE.  ");
            snprintf(tmp_buf,sizeof(tmp_buf),"0x%"  DW_PR_DUx, cu_off);
            esb_append(&details,tmp_buf);
            esb_append(&details,".");
            print_error(dbg, esb_get_string(&details), dres, err);
            esb_destructor(&details);
        } else {
            /* It exists, all is well. */
            dwarf_dealloc(dbg, cu_die, DW_DLA_DIE);
        }
    }
    /* Display offsets */
    if (display_offsets) {
        /* Print 'name'at the end for better layout */
        printf("%s die-in-sect 0x%" DW_PR_XZEROS DW_PR_DUx
            ", cu-in-sect 0x%" DW_PR_XZEROS DW_PR_DUx ","
            " die-in-cu 0x%" DW_PR_XZEROS DW_PR_DUx
            ", cu-header-in-sect 0x%" DW_PR_XZEROS DW_PR_DUx ,
            line_title,
            die_off, cu_off,
            (Dwarf_Unsigned) die_CU_off,
            /*  Following is absolute offset of the ** beginning of the
                cu */
            (Dwarf_Signed) (die_off - die_CU_off));
    }

    if ((die_off - die_CU_off) != global_cu_offset) {
        printf(" error: real cuhdr 0x%" DW_PR_XZEROS DW_PR_DUx,
            global_cu_offset);
        exit(1);
    }

    /* Display offsets */
    if (display_offsets && verbose) {
        printf(" cuhdr 0x%" DW_PR_XZEROS DW_PR_DUx , global_cu_offset);
    }

    /* Print 'name'at the end for better layout */
    printf(" '%s'\n",name);

    dwarf_dealloc(dbg, die, DW_DLA_DIE);

    check_info_offset_sanity(line_title,
        "die offset", name, die_off, maxoff);
    check_info_offset_sanity(line_title,
        "die cu offset", name, die_CU_off, maxoff);
    check_info_offset_sanity(line_title,
        "cu offset", name,
        (die_off - die_CU_off), maxoff);

}
/* Get all the data in .debug_pubnames */
void
print_pubnames(Dwarf_Debug dbg)
{
    Dwarf_Global *globbuf = NULL;
    Dwarf_Signed count = 0;
    Dwarf_Signed i = 0;
    Dwarf_Off die_off = 0;
    Dwarf_Off cu_off = 0;

    /* Offset to previous CU */
    Dwarf_Off prev_cu_off = elf_max_address;

    char *name = 0;
    int res = 0;

    current_section_id = DEBUG_PUBNAMES;
    if (do_print_dwarf) {
        printf("\n.debug_pubnames\n");
    }
    res = dwarf_get_globals(dbg, &globbuf, &count, &err);
    if (res == DW_DLV_ERROR) {
        print_error(dbg, "dwarf_get_globals", res, err);
    } else if (res == DW_DLV_NO_ENTRY) {
        /*  (err == 0 && count == DW_DLV_NOCOUNT) means there are no
            pubnames.  */
    } else {
        Dwarf_Unsigned maxoff = get_info_max_offset(dbg);

        for (i = 0; i < count; i++) {
            int nres = 0;
            int cures3 = 0;
            Dwarf_Off global_cu_off = 0;

            nres = dwarf_global_name_offsets(globbuf[i],
                &name, &die_off, &cu_off,
                &err);
            deal_with_name_offset_err(dbg, "dwarf_global_name_offsets",
                name, die_off, nres, err);
            cures3 = dwarf_global_cu_offset(globbuf[i],
                &global_cu_off, &err);
            if (cures3 != DW_DLV_OK) {
                print_error(dbg, "dwarf_global_cu_offset", cures3, err);
            }

            if (check_pubname_attr) {
                Dwarf_Bool has_attr;
                int ares;
                int dres;
                Dwarf_Die die;

                /*  We are processing a new set of pubnames
                    for a different CU; get the producer ID, at 'cu_off'
                    to see if we need to skip these pubnames */
                if (cu_off != prev_cu_off) {

                    /* Record offset for previous CU */
                    prev_cu_off = cu_off;

                    dres = dwarf_offdie(dbg, cu_off, &die, &err);
                    if (dres != DW_DLV_OK) {
                        print_error(dbg, "print pubnames: dwarf_offdie a", dres,err);
                    }

                    {
                        /*  Get producer name for this CU
                            and update compiler list */
                        struct esb_s producername;
                        esb_constructor(&producername);
                        get_producer_name(dbg,die,err,&producername);
                        update_compiler_target(esb_get_string(&producername));
                        esb_destructor(&producername);
                    }

                    dwarf_dealloc(dbg, die, DW_DLA_DIE);
                }

                /* get die at die_off */
                dres = dwarf_offdie(dbg, die_off, &die, &err);
                if (dres != DW_DLV_OK) {
                    print_error(dbg, "print pubnames: dwarf_offdie b", dres, err);
                }


                ares =
                    dwarf_hasattr(die, DW_AT_external, &has_attr, &err);
                if (ares == DW_DLV_ERROR) {
                    print_error(dbg, "hassattr on DW_AT_external", ares,
                        err);
                }

                /*  Check for specific compiler */
                if (checking_this_compiler()) {
                    DWARF_CHECK_COUNT(pubname_attr_result,1);
                    if (ares == DW_DLV_OK && has_attr) {
                        /* Should the value of flag be examined? */
                    } else {
                        DWARF_CHECK_ERROR2(pubname_attr_result,name,
                            "pubname does not have DW_AT_external");
                    }
                }
                dwarf_dealloc(dbg, die, DW_DLA_DIE);
            }

            /* Now print pubname, after the test */
            if (do_print_dwarf || (record_dwarf_error && check_verbose_mode)) {
                print_pubname_style_entry(dbg,
                    "global",
                    name, die_off, cu_off,
                    global_cu_off, maxoff);
                record_dwarf_error = FALSE;  /* Clear error condition */
            }

        }
        dwarf_globals_dealloc(dbg, globbuf, count);
    }
}   /* print_pubnames() */
Beispiel #12
0
/* get all the data in .debug_aranges */
extern void
print_aranges(Dwarf_Debug dbg)
{
    Dwarf_Signed count = 0;
    Dwarf_Signed i = 0;
    Dwarf_Arange *arange_buf = NULL;
    int ares = 0;
    int aires = 0;
    Dwarf_Off prev_off = 0; /* Holds previous CU offset */
    Dwarf_Bool first_cu = TRUE;
    Dwarf_Off cu_die_offset_prev = 0;

    /* Reset the global state, so we can traverse the debug_info */
    seen_CU = FALSE;
    need_CU_name = TRUE;
    need_CU_base_address = TRUE;
    need_CU_high_address = TRUE;

    current_section_id = DEBUG_ARANGES;
    if (do_print_dwarf) {
        printf("\n.debug_aranges\n");
    }
    ares = dwarf_get_aranges(dbg, &arange_buf, &count, &err);
    if (ares == DW_DLV_ERROR) {
        print_error(dbg, "dwarf_get_aranges", ares, err);
    } else if (ares == DW_DLV_NO_ENTRY) {
        /* no arange is included */
    } else {
        for (i = 0; i < count; i++) {
            Dwarf_Unsigned segment = 0;
            Dwarf_Unsigned segment_entry_size = 0;
            Dwarf_Addr start = 0;
            Dwarf_Unsigned length = 0;
            Dwarf_Off cu_die_offset = 0;
            Dwarf_Die cu_die = NULL;
            aires = dwarf_get_arange_info_b(arange_buf[i],
                &segment,
                &segment_entry_size,
                &start, &length,
                &cu_die_offset, &err);
            if (aires != DW_DLV_OK) {
                print_error(dbg, "dwarf_get_arange_info", aires, err);
            } else {
                int dres;
                struct esb_s producer_name;
                esb_constructor(&producer_name);
                /*  Get basic locations for error reporting */
                dres = dwarf_offdie(dbg, cu_die_offset, &cu_die, &err);
                if (dres != DW_DLV_OK) {
                    print_error(dbg, "dwarf_offdie", dres, err);
                }

                if (cu_name_flag) {
                    if (should_skip_this_cu(dbg,cu_die,err)) {
                        continue;
                    }
                }
                /* Get producer name for this CU and update compiler list */
                get_producer_name(dbg,cu_die,err,&producer_name);
                update_compiler_target(esb_get_string(&producer_name));
                esb_destructor(&producer_name);
                if (!checking_this_compiler()) {
                    continue;
                }

                if (check_aranges) {
                    do_checking(dbg,arange_buf,i,cu_die_offset,first_cu,
                        cu_die_offset_prev,cu_die);
                }
                /*  Get the offset of the cu header itself in the
                    section, but not for end-entries. */
                if (start || length) {
                    Dwarf_Off off = 0;
                    int cures3 = dwarf_get_arange_cu_header_offset(
                        arange_buf[i], &off, &err);
                    if (cures3 != DW_DLV_OK) {
                        print_error(dbg, "dwarf_get_cu_hdr_offset",
                            cures3, err);
                    }

                    /* Print the CU information if different.  */
                    if (prev_off != off || first_cu) {
                        first_cu = FALSE;
                        prev_off = off;
                        /*  We are faking the indent level. We do not know
                            what level it is, really.

                            If do_check_dwarf we do not want to do
                            the die print call as it will do
                            check/print we may not have asked for.
                            And if we did ask for debug_info checks
                            this will do the checks a second time!
                            So only call print_one_die if printing.
                        */
                        if (do_print_dwarf){
                            /* There is no die if its a set-end entry */
                            print_one_die(dbg, cu_die,
                                /* print_information= */ (boolean2) TRUE,
                                /* indent_level = */0,
                                /* srcfiles= */ 0,
                                /* cnt= */ 0,
                                /* ignore_die_stack= */TRUE);
                        }
                        /* Reset the state, so we can traverse the debug_info */
                        seen_CU = FALSE;
                        need_CU_name = TRUE;
                        if (do_print_dwarf) {
                            printf("\n");
                        }
                    }

                    if (do_print_dwarf) {
                        /* Print current aranges record */
                        if (segment_entry_size) {
                            printf(
                                "\narange starts at seg,off 0x%"
                                DW_PR_XZEROS DW_PR_DUx
                                ",0x%" DW_PR_XZEROS DW_PR_DUx
                                ", ",
                                segment,
                                (Dwarf_Unsigned)start);
                        } else {
                            printf("\narange starts at 0x%"
                                DW_PR_XZEROS DW_PR_DUx ", ",
                                (Dwarf_Unsigned)start);
                        }
                        printf("length of 0x%" DW_PR_XZEROS DW_PR_DUx
                            ", cu_die_offset = 0x%" DW_PR_XZEROS DW_PR_DUx,
                            length,
                            (Dwarf_Unsigned)cu_die_offset);

                    }
                    if (verbose && do_print_dwarf) {
                        printf(" cuhdr 0x%" DW_PR_XZEROS DW_PR_DUx "\n",
                            (Dwarf_Unsigned)off);
                    }
                    dwarf_dealloc(dbg, cu_die, DW_DLA_DIE);
                    cu_die = 0;
                } else {
                    /*  Must be a range end. We really do want to print
                        this as there is a real record here, an
                        'arange end' record. */
                    if (do_print_dwarf) {
                        printf("\narange end");
                    }
                }/* end start||length test */
            }  /* end aires DW_DLV_OK test */

            /* print associated die too? */
            dwarf_dealloc(dbg, arange_buf[i], DW_DLA_ARANGE);
        }
        dwarf_dealloc(dbg, arange_buf, DW_DLA_LIST);
    }
}
Beispiel #13
0
/* print data in .debug_loc 
   There is no guarantee this will work because we are assuming
   that all bytes are valid loclist data, that there are no
   odd padding or garbage bytes.  In normal use one gets
   into here via an offset from .debug_info, so it could be
   that bytes not referenced from .debug_info are garbage
   or even zero padding.  So this can fail (error off) as such bytes
   can lead dwarf_get_loclist_entry() astray.

   It's also wrong because we don't know what CU or frame each
   loclist is from, so we don't know the address_size for sure.
*/
extern void
print_locs(Dwarf_Debug dbg)
{
    Dwarf_Unsigned offset = 0;
    Dwarf_Addr hipc_offset = 0;
    Dwarf_Addr lopc_offset = 0;
    Dwarf_Ptr data = 0;
    Dwarf_Unsigned entry_len = 0;
    Dwarf_Unsigned next_entry = 0;
    struct esb_s  exprstring;
    int index = 0; 
    int lres = 0;
    int fres = 0;

    /* This is sometimes wrong, we need a frame-specific size. */
    Dwarf_Half address_size = 0;

    current_section_id = DEBUG_LOC;

    /* Do nothing if not printing. */
    if (!do_print_dwarf) {
        return;
    }

    fres = dwarf_get_address_size(dbg, &address_size, &err);
    if (fres != DW_DLV_OK) {
        print_error(dbg, "dwarf_get_address_size", fres, err);
    }

    printf("\n.debug_loc");
  
    printf("\nFormat <i o b e l>: "
        "index section-offset begin-addr end-addr length-of-block-entry\n");
    esb_constructor(&exprstring);
    while ((lres = dwarf_get_loclist_entry(dbg, offset,
        &hipc_offset, &lopc_offset,
        &data, &entry_len,
        &next_entry,
        &err)) == DW_DLV_OK) {
        get_string_from_locs(dbg,data,entry_len,address_size,
            &exprstring);
        /* Display offsets */
        if (display_offsets) {
            ++index;
            printf(" <iobel> [%8d] 0x%" DW_PR_XZEROS DW_PR_DUx,
                index, offset);
            if(verbose) {
                printf(" <expr-off 0x%"  DW_PR_XZEROS  DW_PR_DUx ">",
                    next_entry - entry_len);
            }
        }
        printf(" 0x%"  DW_PR_XZEROS  DW_PR_DUx 
            " 0x%" DW_PR_XZEROS DW_PR_DUx  
            " %8" DW_PR_DUu " %s\n",
            (Dwarf_Unsigned) lopc_offset,
            (Dwarf_Unsigned) hipc_offset,  entry_len,
            esb_get_string(&exprstring));
        esb_empty_string(&exprstring);
        offset = next_entry;
    }
    esb_destructor(&exprstring);
    if (lres == DW_DLV_ERROR) {
        print_error(dbg, "dwarf_get_loclist_entry", lres, err);
    }
}
Beispiel #14
0
/* Here we test the interfaces into Dwarf_Line_Context. */
static void
print_line_context_record(Dwarf_Debug dbg,
    Dwarf_Line_Context line_context)
{
    int vres = 0;
    Dwarf_Unsigned lsecoff = 0;
    Dwarf_Unsigned version = 0;
    Dwarf_Signed count = 0;
    Dwarf_Signed i = 0;
    const char *name = 0;
    struct esb_s bufr;
    Dwarf_Small table_count = 0;

    esb_constructor(&bufr);
    printf("Line Context data\n");
    vres = dwarf_srclines_table_offset(line_context,&lsecoff,&err);
    if (vres != DW_DLV_OK) {
        print_error(dbg,"Error accessing line context"
            "Something broken.",
            vres,err);
        return;
    }
    printf(" Line Section Offset 0x%"
        DW_PR_XZEROS DW_PR_DUx "\n", lsecoff);
    vres = dwarf_srclines_version(line_context,&version,
        &table_count, &err);
    if (vres != DW_DLV_OK) {
        print_error(dbg,"Error accessing line context"
            "Something broken.",
            vres,err);
        return;
    }
    printf(" version number      0x%" DW_PR_DUx " %" DW_PR_DUu "\n",
        version,version);
    printf(" number of line tables  %d.\n", table_count);


    vres = dwarf_srclines_comp_dir(line_context,&name,&err);
    if (vres != DW_DLV_OK) {
        print_error(dbg,"Error accessing line context"
            "Something broken.",
            vres,err);
        return;
    }
    if (name) {
        printf(" Compilation directory: %s\n",name);
    } else {
        printf(" Compilation directory: <unknown no DW_AT_comp_dir>\n");
    }

    vres = dwarf_srclines_include_dir_count(line_context,&count,&err);
    if (vres != DW_DLV_OK) {
        print_error(dbg,"Error accessing line context"
            "Something broken.",
            vres,err);
        return;
    }
    printf(" include directory count 0x%"
        DW_PR_DUx " %" DW_PR_DSd "\n",
        (Dwarf_Unsigned)count,count);
    for(i = 1; i <= count; ++i) {
        vres = dwarf_srclines_include_dir_data(line_context,i,
            &name,&err);
        if (vres != DW_DLV_OK) {
            print_error(dbg,"Error accessing line context"
                "Something broken.",
                vres,err);
            return;
        }
        printf("  [%2" DW_PR_DSd "]  \"%s\"\n",i,name);
    }

    vres = dwarf_srclines_files_count(line_context,&count,&err);
    if (vres != DW_DLV_OK) {
        print_error(dbg,"Error accessing line context"
            "Something broken.",
            vres,err);
        return;
    }
    printf( " files count 0x%"
        DW_PR_DUx " %" DW_PR_DUu "\n",
        count,count);
    for(i = 1; i <= count; ++i) {
        Dwarf_Unsigned dirindex = 0;
        Dwarf_Unsigned modtime = 0;
        Dwarf_Unsigned flength = 0;

        vres = dwarf_srclines_files_data(line_context,i,
            &name,&dirindex, &modtime,&flength,&err);
        if (vres != DW_DLV_OK) {
            print_error(dbg,"Error accessing line context"
                "Something broken.",
                vres,err);
            return;
        }
        esb_empty_string(&bufr);
        if (name) {
            esb_empty_string(&bufr);
            esb_append(&bufr,"\"");
            esb_append(&bufr,name);
            esb_append(&bufr,"\"");
        } else {
            esb_append(&bufr,"<ERROR:NULL name in files list>");
        }
        printf("  [%2" DW_PR_DSd "]  %-24s ,",
            i,esb_get_string(&bufr));
        printf(" directory index  %2" DW_PR_DUu ,modtime);
        printf(",  file length %2" DW_PR_DUu ,flength);
        if (modtime) {
            time_t tt3 = (time_t)modtime;

            /* ctime supplies newline */
            printf(
                "file mod time 0x%x %s", (unsigned)tt3, ctime(&tt3));
        } else {
            printf("  file mod time 0\n");
        }
    }
    esb_destructor(&bufr);

    vres = dwarf_srclines_subprog_count(line_context,&count,&err);
    if (vres != DW_DLV_OK) {
        print_error(dbg,"Error accessing line context"
            "Something broken.",
            vres,err);
        return;
    }
    if (count == 0) {
        return;
    }
    printf(" subprograms count (experimental) 0x%"
        DW_PR_DUx " %" DW_PR_DUu "\n",
        count,count);
    for(i = 1; i <= count; ++i) {
        Dwarf_Unsigned decl_file = 0;
        Dwarf_Unsigned decl_line = 0;
        vres = dwarf_srclines_subprog_data(line_context,i,
            &name,&decl_file, &decl_line,&err);
        if (vres != DW_DLV_OK) {
            print_error(dbg,"Error accessing line context"
                "Something broken.",
                vres,err);
            return;
        }
        printf("  [%2" DW_PR_DSd "]  \"%s\""
            ", fileindex %2" DW_PR_DUu
            ", lineindex  %2" DW_PR_DUu
            "\n",
            i,name,decl_file,decl_line);
    }
}
Beispiel #15
0
/* print data in .debug_str_offsets.
   There is no guarantee this will work because
   the DWARF5 standard is silent about
   whether arbitrary non-zero bytes, or odd
   alignments, or unused data spaces  are allowed
   in the section
*/
void
print_str_offsets_section(Dwarf_Debug dbg)
{
    int res = 0;
    Dwarf_Str_Offsets_Table sot = 0;
    Dwarf_Unsigned wasted_byte_count = 0;
    Dwarf_Unsigned table_count = 0;
    Dwarf_Error error = 0;
    Dwarf_Unsigned tabnum = 0;

    res = dwarf_open_str_offsets_table_access(dbg, &sot,&error);
    if(res == DW_DLV_NO_ENTRY) {
        /* No such table */
        return;
    }
    if(res == DW_DLV_ERROR) {
        print_error_and_continue(dbg,
            "dwarf_open_str_offsets_table_access",
            res, error);
        return;
    }
    for(;; ++tabnum) {
        Dwarf_Unsigned unit_length =0;
        Dwarf_Unsigned unit_length_offset =0;
        Dwarf_Unsigned table_start_offset =0;
        Dwarf_Half     entry_size = 0;
        Dwarf_Half     version =0;
        Dwarf_Half     padding =0;
        Dwarf_Unsigned table_value_count =0;
        Dwarf_Unsigned i = 0;
        Dwarf_Unsigned table_entry_value = 0;
        unsigned rowlim = 4;
        unsigned count_in_row = 0;

        res = dwarf_next_str_offsets_table(sot,
            &unit_length, &unit_length_offset,
            &table_start_offset,
            &entry_size,&version,&padding,
            &table_value_count,&error);
        if (res == DW_DLV_NO_ENTRY) {
            /* We have dealt with all tables */
            break;
        }
        if (res == DW_DLV_ERROR) {
            print_error_and_continue(dbg,
                "dwarf_next_str_offsets_table", res,error);
            return;
        }
        if (tabnum == 0) {
            struct esb_s truename;
            char buf[DWARF_SECNAME_BUFFER_SIZE];

            esb_constructor_fixed(&truename,buf,sizeof(buf));
            get_true_section_name(dbg,".debug_str_offsets",
                &truename,TRUE);
            printf("\n%s\n",sanitized(esb_get_string(&truename)));
            esb_destructor(&truename);
        } else {
            printf("\n");
        }
        printf(" table %" DW_PR_DUu "\n",tabnum);
        printf(" tableheader 0x%" DW_PR_XZEROS DW_PR_DUx "\n",
            unit_length_offset);
        printf(" arrayoffset 0x%" DW_PR_XZEROS DW_PR_DUx "\n",
            table_start_offset);
        printf(" unit length 0x%" DW_PR_XZEROS DW_PR_DUx "\n",
            unit_length);
        printf(" entry size  %u\n",entry_size);
        printf(" version     %u\n",version);
        if (padding) {
            printf("Error: padding is non-zero. Something is wrong.\n");
        }
        printf(" padding     0x%x\n",padding);
        printf(" arraysize   %" DW_PR_DUu "\n",table_value_count);

        /*  Lets print 4 per row. */
        count_in_row = 0;
        for (i=0; i < table_value_count; ++i) {

            res = dwarf_str_offsets_value_by_index(sot,i,
                &table_entry_value,&error);
            if (res != DW_DLV_OK) {
                print_error_and_continue(dbg,
                    "dwarf_next_str_offsets_table", res,error);
                return;
            }
            if (!count_in_row) {
                printf(" Entry [%4" DW_PR_DUu "]: ",i);
            }
            printf(" 0x%" DW_PR_XZEROS DW_PR_DUx ,
                table_entry_value);
            ++count_in_row;
            if( count_in_row < rowlim) {
                continue;
            }
            printf("\n");
            count_in_row = 0;
        }
        if (count_in_row) {
            printf("\n");
            count_in_row = 0;
        }
        res = dwarf_str_offsets_statistics(sot,&wasted_byte_count,
            &table_count,&error);
        if (res == DW_DLV_OK) {
            printf(" wasted      %" DW_PR_DUu " bytes\n",
                wasted_byte_count);
        }
    }
    if (wasted_byte_count) {
        res = dwarf_str_offsets_statistics(sot,&wasted_byte_count,
            &table_count,&error);
        if (res == DW_DLV_OK) {
            printf(" finalwasted %" DW_PR_DUu " bytes\n",
                wasted_byte_count);
        } else {
            print_error_and_continue(dbg,
                "dwarf_open_str_offsets_statistics",
                res, error);
            return;
        }
    }
    res = dwarf_close_str_offsets_table_access(sot,&error);
    if (res != DW_DLV_OK) {
        print_error_and_continue(dbg,
            "dwarf_close_str_offsets_table_access",
            res, error);
        return;
    }
    sot = 0;
}
static void
print_one_frame_reg_col(Dwarf_Debug dbg,
                        Dwarf_Unsigned rule_id,
                        Dwarf_Small value_type,
                        Dwarf_Unsigned reg_used,
                        struct dwconf_s *config_data,
                        Dwarf_Signed offset_relevant,
                        Dwarf_Signed offset, 
                        Dwarf_Ptr block_ptr)
{
    char *type_title = "";
    int print_type_title = 1;

    if (config_data->cf_interface_number == 2)
	print_type_title = 0;

    switch (value_type) {
    case DW_EXPR_OFFSET:
	type_title = "off";
	goto preg2;
    case DW_EXPR_VAL_OFFSET:
	type_title = "valoff";
      preg2:
	if (reg_used == config_data->cf_initial_rule_value) {
	    break;
	}
	if (print_type_title)
	    printf("<%s ", type_title);
	printreg((Dwarf_Signed) rule_id, config_data);
	printf("=");
	if (offset_relevant == 0) {
	    printreg((Dwarf_Signed) reg_used, config_data);
	    printf(" ");
	} else {
	    printf("%02lld", offset);
	    printf("(");
	    printreg((Dwarf_Signed) reg_used, config_data);
	    printf(") ");
	}
	if (print_type_title)
	    printf("%s", "> ");
	break;
    case DW_EXPR_EXPRESSION:
	type_title = "expr";
	goto pexp2;
    case DW_EXPR_VAL_EXPRESSION:
	type_title = "valexpr";
      pexp2:
	if (print_type_title)
	    printf("<%s ", type_title);
	printreg((Dwarf_Signed) rule_id, config_data);
	printf("=");
	printf("expr-block-len=%lld", (long long) offset);
	if (print_type_title)
	    printf("%s", "> ");
	if (verbose) {
	    char pref[40];

	    strcpy(pref, "<");
	    strcat(pref, type_title);
	    strcat(pref, "bytes:");
	    dump_block(pref, block_ptr, offset);
	    printf("%s", "> ");
            if(verbose) {
                      struct esb_s exprstring;
                      esb_constructor(&exprstring);
                      get_string_from_locs(dbg,
			    block_ptr,offset,&exprstring);
                      printf("<expr:%s>",esb_get_string(&exprstring));
                      esb_destructor(&exprstring);
            }
	}
	break;
    default:
	printf("Internal error in libdwarf, value type %d\n",
	       value_type);
	exit(1);
    }
    return;
}
Beispiel #17
0
/* print data in .debug_loc
   There is no guarantee this will work because we are assuming
   that all bytes are valid loclist data, that there are no
   odd padding or garbage bytes.  In normal use one gets
   into here via an offset from .debug_info, so it could be
   that bytes not referenced from .debug_info are garbage
   or even zero padding.  So this can fail (error off) as such bytes
   can lead dwarf_get_loclist_entry() astray.

   It's also wrong because we don't know what CU or frame each
   loclist is from, so we don't know the address_size for sure.
*/
extern void
print_locs(Dwarf_Debug dbg)
{
    Dwarf_Unsigned offset = 0;
    Dwarf_Addr hipc_offset = 0;
    Dwarf_Addr lopc_offset = 0;
    Dwarf_Ptr data = 0;
    Dwarf_Unsigned entry_len = 0;
    Dwarf_Unsigned next_entry = 0;
    int index = 0;
    int lres = 0;
    int fres = 0;
    Dwarf_Half address_size = 0;
    Dwarf_Half offset_size = 0;
    Dwarf_Half version = 2; /* FAKE */
    Dwarf_Error err = 0;
    struct esb_s  exprstring;
    unsigned loopct = 0;

    esb_constructor(&exprstring);
    glflags.current_section_id = DEBUG_LOC;

    /* Do nothing if not printing. */
    if (!glflags.gf_do_print_dwarf) {
        return;
    }
    if(!glflags.gf_use_old_dwarf_loclist) {
        printf("\n");
        printf("Printing location lists with -c is no longer supported\n");
        return;
    }

    fres = dwarf_get_address_size(dbg, &address_size, &err);
    if (fres != DW_DLV_OK) {
        print_error(dbg, "dwarf_get_address_size", fres, err);
    }
    fres = dwarf_get_offset_size(dbg, &offset_size, &err);
    if (fres != DW_DLV_OK) {
        print_error(dbg, "dwarf_get_address_size", fres, err);
    }
#if 0
    /*  This print code not needed as cannot be safely used
        and uses old interface. */
    {
        struct esb_s truename;
        char buf[DWARF_SECNAME_BUFFER_SIZE];

        esb_constructor_fixed(&truename,buf,sizeof(buf));
        get_true_section_name(dbg,".debug_loc",
            &truename,TRUE);
        printf("\n%s\n",sanitized(esb_get_string(&truename)));
        esb_destructor(&truename);
    }
#endif

    printf("Format <i o b e l>: "
        "index section-offset begin-addr end-addr length-of-block-entry\n");
    /*  Pre=October 2015 version. */
    for (loopct = 0;
        (lres = dwarf_get_loclist_entry(dbg, offset,
        &hipc_offset, &lopc_offset,
        &data, &entry_len,
        &next_entry,
        &err)) == DW_DLV_OK;
        ++loopct) {
        get_string_from_locs(dbg,data,entry_len,address_size,
            offset_size,
            version,
            &exprstring);
        /* Display offsets */
        if (!loopct) {
            /*  This print code not needed as cannot be safely used
                and uses old interface. */
            print_secname(dbg,".debug_loc");
        }
        if (glflags.gf_display_offsets) {
            ++index;
            printf("  <iobel> [%8d] 0x%" DW_PR_XZEROS DW_PR_DUx,
                index, offset);
            if (glflags.verbose) {
                printf(" <expr-off 0x%"  DW_PR_XZEROS  DW_PR_DUx ">",
                    next_entry - entry_len);
            }
        }
        printf(" 0x%"  DW_PR_XZEROS  DW_PR_DUx
            " 0x%" DW_PR_XZEROS DW_PR_DUx
            " %8" DW_PR_DUu " %s\n",
            (Dwarf_Unsigned) lopc_offset,
            (Dwarf_Unsigned) hipc_offset,  entry_len,
            esb_get_string(&exprstring));
        esb_empty_string(&exprstring);
        offset = next_entry;
    }
    if (!loopct) {
        /*  This print code not needed as cannot be safely used
            and uses old interface. */
        print_secname(dbg,".debug_loc");
    }
    esb_destructor(&exprstring);
    if (lres == DW_DLV_ERROR) {
        print_error(dbg, "dwarf_get_loclist_entry", lres, err);
    }
}
 /*ARGSUSED*/ void
print_frame_inst_bytes(Dwarf_Debug dbg,
		       Dwarf_Ptr cie_init_inst, Dwarf_Signed len,
		       Dwarf_Signed data_alignment_factor,
		       int code_alignment_factor, Dwarf_Half addr_size,
		       struct dwconf_s *config_data)
{
    unsigned char *instp = (unsigned char *) cie_init_inst;
    Dwarf_Unsigned uval;
    Dwarf_Unsigned uval2;
    unsigned int uleblen;
    unsigned int off = 0;
    unsigned int loff = 0;
    unsigned short u16;
    unsigned int u32;
    unsigned long long u64;

    for (; len > 0;) {
	unsigned char ibyte = *instp;
	int top = ibyte & 0xc0;
	int bottom = ibyte & 0x3f;
	int delta;
	int reg;

	switch (top) {
	case DW_CFA_advance_loc:
	    delta = ibyte & 0x3f;
	    printf("\t%2u DW_CFA_advance_loc %d", off,
		   (int) (delta * code_alignment_factor));
	    if (verbose) {
		printf("  (%d * %d)", (int) delta,
		       (int) code_alignment_factor);
	    }
	    printf("\n");
	    break;
	case DW_CFA_offset:
	    loff = off;
	    reg = ibyte & 0x3f;
	    uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
	    instp += uleblen;
	    len -= uleblen;
	    off += uleblen;
	    printf("\t%2u DW_CFA_offset ", loff);
	    printreg((Dwarf_Signed) reg, config_data);
	    printf(" %lld", (signed long long)
		   (((Dwarf_Signed) uval) * data_alignment_factor));
	    if (verbose) {
		printf("  (%llu * %d)", (unsigned long long) uval,
		       (int) data_alignment_factor);
	    }
	    printf("\n");
	    break;

	case DW_CFA_restore:
	    reg = ibyte & 0x3f;
	    printf("\t%2u DW_CFA_restore \n", off);
	    printreg((Dwarf_Signed) reg, config_data);
	    printf("\n");
	    break;

	default:
	    loff = off;
	    switch (bottom) {
	    case DW_CFA_set_loc:
		/* operand is address, so need address size */
		/* which will be 4 or 8. */
		switch (addr_size) {
		case 4:
		    {
			__uint32_t v32;

			memcpy(&v32, instp + 1, addr_size);
			uval = v32;
		    }
		    break;
		case 8:
		    {
			__uint64_t v64;

			memcpy(&v64, instp + 1, addr_size);
			uval = v64;
		    }
		    break;
		default:
		    printf
			("Error: Unexpected address size %d in DW_CFA_set_loc!\n",
			 addr_size);
		    uval = 0;
		}

		instp += addr_size;
		len -= (Dwarf_Signed) addr_size;
		off += addr_size;
		printf("\t%2u DW_CFA_set_loc %llu\n",
		       loff, (unsigned long long) uval);
		break;
	    case DW_CFA_advance_loc1:
		delta = (unsigned char) *(instp + 1);
		uval2 = delta;
		instp += 1;
		len -= 1;
		off += 1;
		printf("\t%2u DW_CFA_advance_loc1 %llu\n",
		       loff, (unsigned long long) uval2);
		break;
	    case DW_CFA_advance_loc2:
		memcpy(&u16, instp + 1, 2);
		uval2 = u16;
		instp += 2;
		len -= 2;
		off += 2;
		printf("\t%2u DW_CFA_advance_loc2 %llu\n",
		       loff, (unsigned long long) uval2);
		break;
	    case DW_CFA_advance_loc4:
		memcpy(&u32, instp + 1, 4);
		uval2 = u32;
		instp += 4;
		len -= 4;
		off += 4;
		printf("\t%2u DW_CFA_advance_loc4 %llu\n",
		       loff, (unsigned long long) uval2);
		break;
	    case DW_CFA_MIPS_advance_loc8:
		memcpy(&u64, instp + 1, 8);
		uval2 = u64;
		instp += 8;
		len -= 8;
		off += 8;
		printf("\t%2u DW_CFA_MIPS_advance_loc8 %llu\n",
		       loff, (unsigned long long) uval2);
		break;
	    case DW_CFA_offset_extended:
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		uval2 =
		    local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		printf("\t%2u DW_CFA_offset_extended ", loff);
		printreg((Dwarf_Signed) uval, config_data);
		printf(" %lld", (signed long long)
		       (((Dwarf_Signed) uval2) *
			data_alignment_factor));
		if (verbose) {
		    printf("  (%llu * %d)", (unsigned long long) uval2,
			   (int) data_alignment_factor);
		}
		printf("\n");
		break;

	    case DW_CFA_restore_extended:
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		printf("\t%2u DW_CFA_restore_extended ", loff);
		printreg((Dwarf_Signed) uval, config_data);
		printf("\n");
		break;
	    case DW_CFA_undefined:
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		printf("\t%2u DW_CFA_undefined ", loff);
		printreg((Dwarf_Signed) uval, config_data);
		printf("\n");
		break;
	    case DW_CFA_same_value:
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		printf("\t%2u DW_CFA_same_value ", loff);
		printreg((Dwarf_Signed) uval, config_data);
		printf("\n");
		break;
	    case DW_CFA_register:
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		uval2 =
		    local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		printf("\t%2u DW_CFA_register ", loff);
		printreg((Dwarf_Signed) uval, config_data);
		printf(" = ");
		printreg((Dwarf_Signed) uval2, config_data);
		printf("\n");
		break;
	    case DW_CFA_remember_state:
		printf("\t%2u DW_CFA_remember_state\n", loff);
		break;
	    case DW_CFA_restore_state:
		printf("\t%2u DW_CFA_restore_state\n", loff);
		break;
	    case DW_CFA_def_cfa:
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		uval2 =
		    local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		printf("\t%2u DW_CFA_def_cfa ", loff);
		printreg((Dwarf_Signed) uval, config_data);
		printf(" %llu", (unsigned long long) uval2);
		printf("\n");
		break;
	    case DW_CFA_def_cfa_register:
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		printf("\t%2u DW_CFA_def_cfa_register ", loff);
		printreg((Dwarf_Signed) uval, config_data);
		printf("\n");
		break;
	    case DW_CFA_def_cfa_offset:
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		printf("\t%2u DW_CFA_def_cfa_offset %llu\n",
		       loff, (unsigned long long) uval);
		break;

	    case DW_CFA_nop:
		printf("\t%2u DW_CFA_nop\n", loff);
		break;

	    case DW_CFA_def_cfa_expression:	/* DWARF3 */
		{
		    Dwarf_Unsigned block_len =
			local_dwarf_decode_u_leb128(instp + 1,
						    &uleblen);

		    instp += uleblen;
		    len -= uleblen;
		    off += uleblen;
		    printf
			("\t%2u DW_CFA_def_cfa_expression expr block len %lld\n",
			 loff, (unsigned long long)
			 block_len);
		    dump_block("\t\t", (char *) instp+1,
			       (Dwarf_Signed) block_len);
                    printf("\n");
                    if(verbose) {
                      struct esb_s exprstring;
                      esb_constructor(&exprstring);
                      get_string_from_locs(dbg,
			    instp+1,block_len,&exprstring);
                      printf("\t\t%s\n",esb_get_string(&exprstring));
                      esb_destructor(&exprstring);
                    }
		    instp += block_len;
		    len -= block_len;
		    off += block_len;
		}
		break;
	    case DW_CFA_expression:	/* DWARF3 */
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		{
                    /* instp is always 1 byte back, so we need +1
			when we use it. See the final increment
                        of this for loop. */
		    Dwarf_Unsigned block_len =
			local_dwarf_decode_u_leb128(instp + 1,
						    &uleblen);

		    instp += uleblen;
		    len -= uleblen;
		    off += uleblen;
		    printf
			("\t%2u DW_CFA_expression %llu expr block len %lld\n",
			 loff, (unsigned long long) uval,
			 (unsigned long long)
			 block_len);
		    dump_block("\t\t", (char *) instp+1,
			       (Dwarf_Signed) block_len);
                    printf("\n");
                    if(verbose) {
                      struct esb_s exprstring;
                      esb_constructor(&exprstring);
                      get_string_from_locs(dbg,
			    instp+1,block_len,&exprstring);
                      printf("\t\t%s\n",esb_get_string(&exprstring));
                      esb_destructor(&exprstring);
                    }
		    instp += block_len;
		    len -= block_len;
		    off += block_len;
		}

		break;
	    case DW_CFA_cfa_offset_extended_sf:	/* DWARF3 */
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		{
                    /* instp is always 1 byte back, so we need +1
			when we use it. See the final increment
                        of this for loop. */
		    Dwarf_Signed sval2 =
			local_dwarf_decode_s_leb128(instp + 1,
						    &uleblen);

		    instp += uleblen;
		    len -= uleblen;
		    off += uleblen;
		    printf("\t%2u DW_CFA_offset_extended_sf ", loff);
		    printreg((Dwarf_Signed) uval, config_data);
		    printf(" %lld", (signed long long)
			   ((sval2) * data_alignment_factor));
		    if (verbose) {
			printf("  (%lld * %d)", (long long) sval2,
			       (int) data_alignment_factor);
		    }
		}
		printf("\n");
		break;
	    case DW_CFA_def_cfa_sf:	/* DWARF3 */
                    /* instp is always 1 byte back, so we need +1
			when we use it. See the final increment
                        of this for loop. */
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		{
		    Dwarf_Signed sval2 =
			local_dwarf_decode_s_leb128(instp + 1,
						    &uleblen);

		    instp += uleblen;
		    len -= uleblen;
		    off += uleblen;
		    printf("\t%2u DW_CFA_def_cfa_sf ", loff);
		    printreg((Dwarf_Signed) uval, config_data);
		    printf(" %lld", (long long) sval2); 
                    printf(" (*data alignment factor=>%lld)",
                     (long long)(sval2*data_alignment_factor));
		}
		printf("\n");
		break;
	    case DW_CFA_def_cfa_offset_sf:	/* DWARF3 */
		{
                    /* instp is always 1 byte back, so we need +1
			when we use it. See the final increment
                        of this for loop. */
		    Dwarf_Signed sval =
			local_dwarf_decode_s_leb128(instp + 1,
						    &uleblen);

		    instp += uleblen;
		    len -= uleblen;
		    off += uleblen;
		    printf("\t%2u DW_CFA_def_cfa_offset_sf %lld (*data alignment factor=> %lld)\n",
			   loff, (long long) sval,
                           (long long)(data_alignment_factor*sval));

		}
		break;
	    case DW_CFA_val_offset:	/* DWARF3 */
                    /* instp is always 1 byte back, so we need +1
			when we use it. See the final increment
                        of this for loop. */
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		{
		    uval2 =
			local_dwarf_decode_s_leb128(instp + 1,
						    &uleblen);
		    instp += uleblen;
		    len -= uleblen;
		    off += uleblen;
		    printf("\t%2u DW_CFA_val_offset ", loff);
		    printreg((Dwarf_Signed) uval, config_data);
		    printf(" %lld", (unsigned long long)
			   (((Dwarf_Signed) uval2) *
			    data_alignment_factor));
		    if (verbose) {
			printf("  (%lld * %d)", (long long) uval2,
			       (int) data_alignment_factor);
		    }
		}
		printf("\n");

		break;
	    case DW_CFA_val_offset_sf:	/* DWARF3 */
                    /* instp is always 1 byte back, so we need +1
			when we use it. See the final increment
                        of this for loop. */
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		{
		    Dwarf_Signed sval2 =
			local_dwarf_decode_s_leb128(instp + 1,
						    &uleblen);

		    instp += uleblen;
		    len -= uleblen;
		    off += uleblen;
		    printf("\t%2u DW_CFA_val_offset_sf ", loff);
		    printreg((Dwarf_Signed) uval, config_data);
		    printf(" %lld", (signed long long)
			   ((sval2) * data_alignment_factor));
		    if (verbose) {
			printf("  (%lld * %d)", (long long) sval2,
			       (int) data_alignment_factor);
		    }
		}
		printf("\n");

		break;
	    case DW_CFA_val_expression:	/* DWARF3 */
                    /* instp is always 1 byte back, so we need +1
			when we use it. See the final increment
                        of this for loop. */
		uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen);
		instp += uleblen;
		len -= uleblen;
		off += uleblen;
		{
		    Dwarf_Unsigned block_len =
			local_dwarf_decode_u_leb128(instp + 1,
						    &uleblen);

		    instp += uleblen;
		    len -= uleblen;
		    off += uleblen;
		    printf
			("\t%2u DW_CFA_val_expression %llu expr block len %lld\n",
			 loff, (unsigned long long) uval,
			 (unsigned long long)
			 block_len);
		    dump_block("\t\t", (char *) instp+1,
			       (Dwarf_Signed) block_len);
                    printf("\n");
                    if(verbose) {
                      struct esb_s exprstring;
                      esb_constructor(&exprstring);
                      get_string_from_locs(dbg,
			    instp+1,block_len,&exprstring);
                      printf("\t\t%s\n",esb_get_string(&exprstring));
                      esb_destructor(&exprstring);
                    }
		    instp += block_len;
		    len -= block_len;
		    off += block_len;
		}


		break;


#ifdef DW_CFA_GNU_window_save
	    case DW_CFA_GNU_window_save:{
		    /* no information: this just tells unwinder to
		       restore the window registers from the previous
		       frame's window save area */
		    printf("\t%2u DW_CFA_GNU_window_save \n", loff);
		    break;
		}
#endif
#ifdef DW_CFA_GNU_negative_offset_extended
	    case DW_CFA_GNU_negative_offset_extended:{
		    printf
			("\t%2u DW_CFA_GNU_negative_offset_extended \n",
			 loff);
		}
#endif
#ifdef  DW_CFA_GNU_args_size
		/* single uleb128 is the current arg area size in
		   bytes. no register exists yet to save this in */
	    case DW_CFA_GNU_args_size:{
		    Dwarf_Unsigned lreg;

                    /* instp is always 1 byte back, so we need +1
			when we use it. See the final increment
                        of this for loop. */
		    lreg =
			local_dwarf_decode_u_leb128(instp + 1,
						    &uleblen);
		    printf
			("\t%2u DW_CFA_GNU_args_size arg size: %llu\n",
			 loff, (unsigned long long) lreg);
		    instp += uleblen;
		    len -= uleblen;
		    off += uleblen;

		    break;
		}
#endif

	    default:
		printf("\t%u Unexpected op 0x%x: \n",
		       loff, (unsigned int) bottom);
		len = 0;
		break;
	    }
	}
	instp++;
	len--;
	off++;
    }
}
Beispiel #19
0
static void
process_line_table(Dwarf_Debug dbg,
    const char *sec_name,
    Dwarf_Line *linebuf, Dwarf_Signed linecount,
    Dwarf_Bool is_logicals_table, Dwarf_Bool is_actuals_table)
{
    char *padding = 0;
    Dwarf_Signed i = 0;
    Dwarf_Addr pc = 0;
    Dwarf_Unsigned lineno = 0;
    Dwarf_Unsigned logicalno = 0;
    Dwarf_Unsigned column = 0;
    Dwarf_Unsigned call_context = 0;
    string subprog_name = 0;
    string subprog_filename = 0;
    Dwarf_Unsigned subprog_line = 0;

    Dwarf_Error err = 0;

    Dwarf_Bool newstatement = 0;
    Dwarf_Bool lineendsequence = 0;
    Dwarf_Bool new_basic_block = 0;
    int sres = 0;
    int ares = 0;
    int lires = 0;
    int cores = 0;
    Dwarf_Addr elf_max_address = 0;

    Dwarf_Bool SkipRecord = FALSE;

    current_section_id = DEBUG_LINE;
    struct esb_s lastsrc;

    /* line_flag is TRUE */
    esb_constructor(&lastsrc);

    get_address_size_and_max(dbg,0,&elf_max_address,&err);
    /* Padding for a nice layout */
    padding = line_print_pc ? "            " : "";
    if (do_print_dwarf) {
        /* Check if print of <pc> address is needed. */
        printf("\n");
        if (is_logicals_table) {
            printf("Logicals Table:\n");
            printf("%sNS new statement, PE prologue end, "
                "EB epilogue begin\n",padding);
            printf("%sDI=val discriminator value\n",
                padding);
            printf("%sCC=val context, SB=val subprogram\n",
                padding);
        } else if (is_actuals_table) {
            printf("Actuals Table:\n");
            printf("%sBB new basic block, ET end of text sequence\n"
                "%sIS=val ISA number\n",padding,padding);

        } else {
            /* Standard DWARF line table. */
            printf("%sNS new statement, BB new basic block, "
                "ET end of text sequence\n",padding);
            printf("%sPE prologue end, EB epilogue begin\n",padding);
            printf("%sIS=val ISA number, DI=val discriminator value\n",
                padding);
        }
        if (is_logicals_table || is_actuals_table) {
            printf("[ row]  ");
        }
        if (line_print_pc) {
            printf("<pc>        ");
        }
        if (is_logicals_table) {
            printf("[lno,col] NS PE EB DI= CC= SB= uri: \"filepath\"\n");
        } else if (is_actuals_table) {
            printf("[logical] BB ET IS=\n");
        } else {
            printf("[row,col] NS BB ET PE EB IS= DI= uri: \"filepath\"\n");
        }
    }
    for (i = 0; i < linecount; i++) {
        Dwarf_Line line = linebuf[i];
        string filename = 0;
        int nsres = 0;
        Dwarf_Bool found_line_error = FALSE;
        Dwarf_Bool has_is_addr_set = FALSE;
        char *where = NULL;

        if (check_decl_file && checking_this_compiler()) {
            /* A line record with addr=0 was detected */
            if (SkipRecord) {
                /* Skip records that do not have ís_addr_set' */
                ares = dwarf_line_is_addr_set(line, &has_is_addr_set, &err);
                if (ares == DW_DLV_OK && has_is_addr_set) {
                    SkipRecord = FALSE;
                }
                else {
                    /*  Keep ignoring records until we have
                        one with 'is_addr_set' */
                    continue;
                }
            }
        }

        if (check_lines && checking_this_compiler()) {
            DWARF_CHECK_COUNT(lines_result,1);
        }

        filename = "<unknown>";
        if (!is_actuals_table) {
            sres = dwarf_linesrc(line, &filename, &err);
            if (sres == DW_DLV_ERROR) {
                /* Do not terminate processing */
                where = "dwarf_linesrc()";
                record_line_error(where,err);
                found_line_error = TRUE;
            }
        }

        pc = 0;
        ares = dwarf_lineaddr(line, &pc, &err);

        if (ares == DW_DLV_ERROR) {
            /* Do not terminate processing */
            where = "dwarf_lineaddr()";
            record_line_error(where,err);
            found_line_error = TRUE;
            pc = 0;
        }
        if (ares == DW_DLV_NO_ENTRY) {
            pc = 0;
        }

        if (is_actuals_table) {
            lires = dwarf_linelogical(line, &logicalno, &err);
            if (lires == DW_DLV_ERROR) {
                /* Do not terminate processing */
                where = "dwarf_linelogical()";
                record_line_error(where,err);
                found_line_error = TRUE;
            }
            if (lires == DW_DLV_NO_ENTRY) {
                logicalno = -1LL;
            }
            column = 0;
        } else {
            lires = dwarf_lineno(line, &lineno, &err);
            if (lires == DW_DLV_ERROR) {
                /* Do not terminate processing */
                where = "dwarf_lineno()";
                record_line_error(where,err);
                found_line_error = TRUE;
            }
            if (lires == DW_DLV_NO_ENTRY) {
                lineno = -1LL;
            }
            cores = dwarf_lineoff_b(line, &column, &err);
            if (cores == DW_DLV_ERROR) {
                /* Do not terminate processing */
                where = "dwarf_lineoff()";
                record_line_error(where,err);
                found_line_error = TRUE;
            }
            if (cores == DW_DLV_NO_ENTRY) {
                /*  Zero was always the correct default, meaning
                    the left edge. DWARF2/3/4 spec sec 6.2.2 */
                column = 0;
            }
        }

        /*  Process any possible error condition, though
            we won't be at the first such error. */
        if (check_decl_file && checking_this_compiler()) {
            DWARF_CHECK_COUNT(decl_file_result,1);
            if (found_line_error) {
                DWARF_CHECK_ERROR2(decl_file_result,where,dwarf_errmsg(err));
            } else if (do_check_dwarf) {
                /*  Check the address lies with a valid [lowPC:highPC]
                    in the .text section*/
                if (IsValidInBucketGroup(pRangesInfo,pc)) {
                    /* Valid values; do nothing */
                } else {
                    /*  At this point may be we are dealing with
                        a linkonce symbol. The problem we have here
                        is we have consumed the deug_info section
                        and we are dealing just with the records
                        from the .debug_line, so no PU_name is
                        available and no high_pc. Traverse the linkonce
                        table if try to match the pc value with
                        one of those ranges.
                    */
                    if (check_lines && checking_this_compiler()) {
                        DWARF_CHECK_COUNT(lines_result,1);
                    }
                    if (FindAddressInBucketGroup(pLinkonceInfo,pc)){
                        /* Valid values; do nothing */
                    } else {
                        /*  The SN Systems Linker generates
                            line records
                            with addr=0, when dealing with linkonce
                            symbols and no stripping */
                        if (pc) {
                            char addr_tmp[100];
                            if (check_lines && checking_this_compiler()) {
                                snprintf(addr_tmp,sizeof(addr_tmp),
                                    "%s: Address"
                                    " 0x%" DW_PR_XZEROS DW_PR_DUx
                                    " outside a valid .text range",
                                    sec_name,pc);
                                DWARF_CHECK_ERROR(lines_result,
                                    addr_tmp);
                            }
                        } else {
                            SkipRecord = TRUE;
                        }
                    }
                }
                /*  Check the last record for the .debug_line,
                    the one created by DW_LNE_end_sequence,
                    is the same as the high_pc
                    address for the last known user program
                    unit (PU) */
                if ((i + 1 == linecount) &&
                    seen_PU_high_address &&
                    !is_logicals_table) {
                    /*  Ignore those PU that have been stripped
                        by the linker; their low_pc values are
                        set to -1 (snc linker only) */
                    /*  It is perfectly sensible for a compiler
                        to leave a few bytes of NOP or other stuff
                        after the last instruction in a subprogram,
                        for cache-alignment or other purposes, so
                        a mismatch here is not necessarily
                        an error.  */

                    if (check_lines && checking_this_compiler()) {
                        DWARF_CHECK_COUNT(lines_result,1);
                        if ((pc != PU_high_address) &&
                            (PU_base_address != elf_max_address)) {
                            char addr_tmp[100];
                            snprintf(addr_tmp,sizeof(addr_tmp),
                                "%s: Address"
                                " 0x%" DW_PR_XZEROS DW_PR_DUx
                                " may be incorrect"
                                " as DW_LNE_end_sequence address",
                                sec_name,pc);
                            DWARF_CHECK_ERROR(lines_result,
                                addr_tmp);
                        }
                    }
                }
            }
        }

        /* Display the error information */
        if (found_line_error || record_dwarf_error) {
            if (check_verbose_mode && PRINTING_UNIQUE) {
                /* Print the record number for better error description */
                printf("Record = %"  DW_PR_DUu
                    " Addr = 0x%" DW_PR_XZEROS DW_PR_DUx
                    " [%4" DW_PR_DUu ",%2" DW_PR_DUu "] '%s'\n",
                    i, pc,lineno,column,filename);
                /* The compilation unit was already printed */
                if (!check_decl_file) {
                    PRINT_CU_INFO();
                }
            }
            record_dwarf_error = FALSE;
            /* Due to a fatal error, skip current record */
            if (found_line_error) {
                continue;
            }
        }
        if (do_print_dwarf) {
            if (is_logicals_table || is_actuals_table) {
                printf("[%4" DW_PR_DUu "]  ", i + 1);
            }
            /* Check if print of <pc> address is needed. */
            if (line_print_pc) {
                printf("0x%" DW_PR_XZEROS DW_PR_DUx "  ", pc);
            }
            if (is_actuals_table) {
                printf("[%7" DW_PR_DUu "]", logicalno);
            } else {
                printf("[%4" DW_PR_DUu ",%2" DW_PR_DUu "]", lineno, column);
            }
        }

        if (!is_actuals_table) {
            nsres = dwarf_linebeginstatement(line, &newstatement, &err);
            if (nsres == DW_DLV_OK) {
                if (newstatement && do_print_dwarf) {
                    printf(" %s","NS");
                }
            } else if (nsres == DW_DLV_ERROR) {
                print_error(dbg, "linebeginstatment failed", nsres, err);
            }
        }

        if (!is_logicals_table) {
            nsres = dwarf_lineblock(line, &new_basic_block, &err);
            if (nsres == DW_DLV_OK) {
                if (new_basic_block && do_print_dwarf) {
                    printf(" %s","BB");
                }
            } else if (nsres == DW_DLV_ERROR) {
                print_error(dbg, "lineblock failed", nsres, err);
            }
            nsres = dwarf_lineendsequence(line, &lineendsequence, &err);
            if (nsres == DW_DLV_OK) {
                if (lineendsequence && do_print_dwarf) {
                    printf(" %s", "ET");
                }
            } else if (nsres == DW_DLV_ERROR) {
                print_error(dbg, "lineendsequence failed", nsres, err);
            }
        }

        if (do_print_dwarf) {
            Dwarf_Bool prologue_end = 0;
            Dwarf_Bool epilogue_begin = 0;
            Dwarf_Unsigned isa = 0;
            Dwarf_Unsigned discriminator = 0;
            int disres = dwarf_prologue_end_etc(line,
                &prologue_end,&epilogue_begin,
                &isa,&discriminator,&err);
            if (disres == DW_DLV_ERROR) {
                print_error(dbg, "dwarf_prologue_end_etc() failed",
                    disres, err);
            }
            if (prologue_end && !is_actuals_table) {
                printf(" PE");
            }
            if (epilogue_begin && !is_actuals_table) {
                printf(" EB");
            }
            if (isa && !is_logicals_table) {
                printf(" IS=0x%" DW_PR_DUx, isa);
            }
            if (discriminator && !is_actuals_table) {
                printf(" DI=0x%" DW_PR_DUx, discriminator);
            }
            if (is_logicals_table) {
                call_context = 0;
                disres = dwarf_linecontext(line, &call_context, &err);
                if (disres == DW_DLV_ERROR) {
                    print_error(dbg, "dwarf_linecontext() failed",
                        disres, err);
                }
                if (call_context) {
                    printf(" CC=%" DW_PR_DUu, call_context);
                }
                subprog_name = 0;
                disres = dwarf_line_subprog(line, &subprog_name,
                    &subprog_filename, &subprog_line, &err);
                if (disres == DW_DLV_ERROR) {
                    print_error(dbg, "dwarf_line_subprog() failed",
                        disres, err);
                }
                if (subprog_name && strlen(subprog_name)) {
                    /*  We do not print an empty name.
                        Clutters things up. */
                    printf(" SB=\"%s\"", subprog_name);
                }
            }
        }

        if (!is_actuals_table) {
            if (i > 0 &&  verbose < 3  &&
                strcmp(filename,esb_get_string(&lastsrc)) == 0) {
                /* Do not print name. */
            } else {
                struct esb_s urs;
                esb_constructor(&urs);
                esb_append(&urs, " uri: \"");
                translate_to_uri(filename,&urs);
                esb_append(&urs,"\"");
                if (do_print_dwarf) {
                    printf("%s",esb_get_string(&urs));
                }
                esb_destructor(&urs);
                esb_empty_string(&lastsrc);
                esb_append(&lastsrc,filename);
            }
            if (sres == DW_DLV_OK) {
                dwarf_dealloc(dbg, filename, DW_DLA_STRING);
            }
        }

        if (do_print_dwarf) {
            printf("\n");
        }
    }
    esb_destructor(&lastsrc);
}
Beispiel #20
0
/*  Extracted this from print_range_attribute() to isolate the check of
    the range list.
*/
static void
check_ranges_list(Dwarf_Debug dbg,
    Dwarf_Off die_off,
    Dwarf_Die cu_die,
    Dwarf_Unsigned original_off,
    Dwarf_Ranges *rangeset,
    Dwarf_Signed rangecount,
    Dwarf_Unsigned bytecount)
{
    Dwarf_Unsigned off = original_off;

    Dwarf_Signed index = 0;
    Dwarf_Addr base_address = CU_base_address;
    Dwarf_Addr lopc = 0;
    Dwarf_Addr hipc = 0;
    Dwarf_Bool bError = FALSE;

    static boolean do_print = TRUE;
#if 0
{
/* START -> Just for debugging */
struct esb_s rangesstr;
esb_constructor(&rangesstr);
printf("\n**** START ****\n");
printf("\tGLB_OFF: (0x%" DW_PR_XZEROS DW_PR_DUx ") ",die_off);
printf("\tRGN_OFF: (0x%" DW_PR_XZEROS DW_PR_DUx ")\n",original_off);
print_ranges_list_to_extra(dbg,original_off,
    rangeset,rangecount,bytecount,
    &rangesstr);
printf("%s\n", esb_get_string(&rangesstr));
printf("**** END ****\n");
/* END <- Just for debugging */
}
#endif /* 0 */

    /* Ignore last entry, is the end-of-list */
    for (index = 0; index < rangecount - 1; index++) {
        Dwarf_Ranges *r = rangeset + index;

        if (r->dwr_addr1 == elf_max_address) {
            /* (0xffffffff,addr), use specific address (current PU address) */
            base_address = r->dwr_addr2;
        } else {
            /* (offset,offset), update using CU address */
            lopc = r->dwr_addr1 + base_address;
            hipc = r->dwr_addr2 + base_address;
            DWARF_CHECK_COUNT(ranges_result,1);

            /*  Check the low_pc and high_pc
                are within a valid range in
                the .text section */
            if (IsValidInBucketGroup(pRangesInfo,lopc) &&
                IsValidInBucketGroup(pRangesInfo,hipc)) {
                /* Valid values; do nothing */
            } else {
                /*  At this point may be we
                    are dealing with a
                    linkonce symbol */
                if (IsValidInLinkonce(pLinkonceInfo,
                    PU_name,lopc,hipc)) {
                    /* Valid values; do nothing */
                } else {
                    bError = TRUE;
                    DWARF_CHECK_ERROR(ranges_result,
                        ".debug_ranges: Address outside a "
                        "valid .text range");
                    if (check_verbose_mode && do_print) {
                        /*  Update DIEs offset just for printing */
                        int res = dwarf_die_offsets(cu_die,
                            &DIE_overall_offset,&DIE_offset,&err);
                        if (res != DW_DLV_OK) {
                            print_error(dbg, "dwarf_die_offsets",res,err);
                        }
                        printf(
                            "Offset = 0x%" DW_PR_XZEROS DW_PR_DUx
                            ", Base = 0x%" DW_PR_XZEROS DW_PR_DUx
                            ", "
                            "Low = 0x%" DW_PR_XZEROS DW_PR_DUx
                            " (0x%" DW_PR_XZEROS  DW_PR_DUx
                            "), High = 0x%"
                            DW_PR_XZEROS  DW_PR_DUx
                            " (0x%" DW_PR_XZEROS DW_PR_DUx
                            ")\n",
                            off,base_address,lopc,
                            r->dwr_addr1,hipc,
                            r->dwr_addr2);
                    }
                }
            }
        }
        /*  Each entry holds 2 addresses (offsets) */
        off += elf_address_size * 2;
    }

    /*  In the case of errors, we have to print the range records that
        caused the error. */
    if (bError && check_verbose_mode && do_print) {
        struct esb_s rangesstr;
        esb_constructor(&rangesstr);

        printf("\n");
        print_ranges_list_to_extra(dbg,original_off,
            rangeset,rangecount,bytecount,
            &rangesstr);
        printf("%s\n", esb_get_string(&rangesstr));
    }

    /*  In the case of printing unique errors, stop the printing of any
        subsequent errors, which have the same text. */
    if (bError && check_verbose_mode && print_unique_errors) {
        do_print = FALSE;
    }
}