Exemplo n.º 1
0
/*
        return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
        If err_count_out is non-NULL, this is a special 'check'
        call.
*/
int
_dwarf_internal_printlines(Dwarf_Die die, Dwarf_Error * error,
   int * err_count_out, int only_line_header)
{
    /* 
       This pointer is used to scan the portion of the .debug_line
       section for the current cu. */
    Dwarf_Small *line_ptr = 0;
    Dwarf_Small *orig_line_ptr = 0;

    /* 
       This points to the last byte of the .debug_line portion for the
       current cu. */
    Dwarf_Small *line_ptr_end = 0;

    /* 
       Pointer to a DW_AT_stmt_list attribute in case it exists in the
       die. */
    Dwarf_Attribute stmt_list_attr = 0;

    /* Pointer to DW_AT_comp_dir attribute in die. */
    Dwarf_Attribute comp_dir_attr = 0;

    /* Pointer to name of compilation directory. */
    Dwarf_Small *comp_dir = NULL;

    /* 
       Offset into .debug_line specified by a DW_AT_stmt_list
       attribute. */
    Dwarf_Unsigned line_offset = 0;

    struct Line_Table_Prefix_s prefix;


    /* These are the state machine state variables. */
    Dwarf_Addr address = 0;
    Dwarf_Word file = 1;
    Dwarf_Word line = 1;
    Dwarf_Word column = 0;
    Dwarf_Bool is_stmt = false;
    Dwarf_Bool basic_block = false;
    Dwarf_Bool end_sequence = false;
    Dwarf_Bool prologue_end = false;
    Dwarf_Bool epilogue_begin = false;
    Dwarf_Small isa = 0;


    Dwarf_Sword i=0;

    /* 
       This is the current opcode read from the statement program. */
    Dwarf_Small opcode=0;


    /* 
       These variables are used to decode leb128 numbers. Leb128_num
       holds the decoded number, and leb128_length is its length in
       bytes. */
    Dwarf_Word leb128_num=0;
    Dwarf_Word leb128_length=0;
    Dwarf_Sword advance_line=0;
    Dwarf_Half attrform = 0;
    /* 
       This is the operand of the latest fixed_advance_pc extended
       opcode. */
    Dwarf_Half fixed_advance_pc=0;

    /* In case there are wierd bytes 'after' the line table
     * prologue this lets us print something. This is a gcc
     * compiler bug and we expect the bytes count to be 12.
     */
    Dwarf_Small* bogus_bytes_ptr = 0;
    Dwarf_Unsigned bogus_bytes_count = 0;


    /* The Dwarf_Debug this die belongs to. */
    Dwarf_Debug dbg=0;
    int resattr = DW_DLV_ERROR;
    int lres =    DW_DLV_ERROR;
    int res  =    DW_DLV_ERROR;

    /* ***** BEGIN CODE ***** */

    if (error != NULL) {
        *error = NULL;
    }

    CHECK_DIE(die, DW_DLV_ERROR);
    dbg = die->di_cu_context->cc_dbg;

    res = _dwarf_load_section(dbg, &dbg->de_debug_line,error);
    if (res != DW_DLV_OK) {
        return res;
    }

    resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
    if (resattr != DW_DLV_OK) {
        return resattr;
    }


    /* The list of relevant FORMs is small. 
       DW_FORM_data4, DW_FORM_data8, DW_FORM_sec_offset 
    */
    lres = dwarf_whatform(stmt_list_attr,&attrform,error);
    if (lres != DW_DLV_OK) {
        return lres;
    }
    if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 &&
        attrform != DW_FORM_sec_offset ) {
        _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
        return (DW_DLV_ERROR);
    }
    lres = dwarf_global_formref(stmt_list_attr, &line_offset, error);
    if (lres != DW_DLV_OK) {
        return lres;
    }

    if (line_offset >= dbg->de_debug_line.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
        return (DW_DLV_ERROR);
    }
    orig_line_ptr = dbg->de_debug_line.dss_data;
    line_ptr = dbg->de_debug_line.dss_data + line_offset;
    dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);

    /* 
       If die has DW_AT_comp_dir attribute, get the string that names
       the compilation directory. */
    resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
    if (resattr == DW_DLV_ERROR) {
        return resattr;
    }
    if (resattr == DW_DLV_OK) {
        int cres = DW_DLV_ERROR;
        char *cdir = 0;

        cres = dwarf_formstring(comp_dir_attr, &cdir, error);
        if (cres == DW_DLV_ERROR) {
            return cres;
        } else if (cres == DW_DLV_OK) {
            comp_dir = (Dwarf_Small *) cdir;
        }
    }
    if (resattr == DW_DLV_OK) {
        dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
    }

    dwarf_init_line_table_prefix(&prefix);
    {
        Dwarf_Small *line_ptr_out = 0;
        int dres = dwarf_read_line_table_prefix(dbg,
            line_ptr,dbg->de_debug_line.dss_size - line_offset,
            &line_ptr_out,
            &prefix, 
            &bogus_bytes_ptr,
            &bogus_bytes_count,
            error,
            err_count_out);
        if (dres == DW_DLV_ERROR) {
            dwarf_free_line_table_prefix(&prefix);
            return dres;
        }
        if (dres == DW_DLV_NO_ENTRY) {
            dwarf_free_line_table_prefix(&prefix);
            return dres;
        }
        line_ptr_end = prefix.pf_line_ptr_end;
        line_ptr = line_ptr_out;
    }
    if(only_line_header) {
         /* Just checking for header errors, nothing more here.*/
         dwarf_free_line_table_prefix(&prefix);
         return DW_DLV_OK;
    }


    printf("total line info length %ld bytes, "
           "line offset 0x%" DW_PR_DUx " %" DW_PR_DSd "\n",
           (long) prefix.pf_total_length,
           (Dwarf_Unsigned) line_offset, 
           (Dwarf_Signed) line_offset);
    printf("line table version %d\n",(int) prefix.pf_version);
    printf("line table length field length %d prologue length %d\n",
           (int)prefix.pf_length_field_length,
           (int)prefix.pf_prologue_length);
    printf("compilation_directory %s\n",
           comp_dir ? ((char *) comp_dir) : "");

    printf("  min instruction length %d\n",
           (int) prefix.pf_minimum_instruction_length);
    printf("  default is stmt        %d\n", (int)
           prefix.pf_default_is_stmt);
    printf("  line base              %d\n", (int)
           prefix.pf_line_base);
    printf("  line_range             %d\n", (int)
           prefix.pf_line_range);
    printf("  opcode base            %d\n", (int)
           prefix.pf_opcode_base);
    printf("  standard opcode count  %d\n", (int)
           prefix.pf_std_op_count);

    for (i = 1; i < prefix.pf_opcode_base; i++) {
        printf("  opcode[%2d] length  %d\n", (int) i,
               (int) prefix.pf_opcode_length_table[i - 1]);
    }
    printf("  include directories count %d\n", (int)
           prefix.pf_include_directories_count);

    
    for (i = 0; i < prefix.pf_include_directories_count; ++i) {
        printf("  include dir[%d] %s\n",
               (int) i, prefix.pf_include_directories[i]);
    }
    printf("  files count            %d\n", (int)
           prefix.pf_files_count);

    for (i = 0; i < prefix.pf_files_count; ++i) {
        struct Line_Table_File_Entry_s *lfile =
            prefix.pf_line_table_file_entries + i;

        Dwarf_Unsigned tlm2 = lfile->lte_last_modification_time;
        Dwarf_Unsigned di = lfile->lte_directory_index;
        Dwarf_Unsigned fl = lfile->lte_length_of_file;

        printf("  file[%d]  %s (file-number: %d) \n",
               (int) i, (char *) lfile->lte_filename,
               (int)(i+1));

        printf("    dir index %d\n", (int) di);
        {
            time_t tt = (time_t) tlm2;

            printf("    last time 0x%x %s",     /* ctime supplies
                                                   newline */
                   (unsigned) tlm2, ctime(&tt));
        }
        printf("    file length %ld 0x%lx\n",
               (long) fl, (unsigned long) fl);


    }


    {
        Dwarf_Unsigned offset = 0;
        if(bogus_bytes_count > 0) {
            Dwarf_Unsigned wcount = bogus_bytes_count;
            Dwarf_Unsigned boffset = bogus_bytes_ptr - orig_line_ptr;
            printf("*** DWARF CHECK: the line table prologue  header_length "
                " is %" DW_PR_DUu " too high, we pretend it is smaller."
                "Section offset: %" DW_PR_DUu " (0x%" DW_PR_DUx ") ***\n",
                wcount, boffset,boffset);
            *err_count_out += 1;
        }
        offset = line_ptr - orig_line_ptr;

        printf("  statement prog offset in section: %" DW_PR_DUu " 0x%" DW_PR_DUx "\n",
               offset, offset);
    }

    /* Initialize the part of the state machine dependent on the
       prefix.  */
    is_stmt = prefix.pf_default_is_stmt;


    print_line_header();
    /* Start of statement program.  */
    while (line_ptr < line_ptr_end) {
        int type = 0;

        printf(" [0x%06" DW_PR_DSx "] ", 
            (Dwarf_Signed) (line_ptr - orig_line_ptr));
        opcode = *(Dwarf_Small *) line_ptr;
        line_ptr++;
        /* 'type' is the output */
        WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base,
                       prefix.pf_opcode_length_table, line_ptr,
                       prefix.pf_std_op_count);

        if (type == LOP_DISCARD) {
            int oc;
            int opcnt = prefix.pf_opcode_length_table[opcode];

            printf("*** DWARF CHECK: DISCARD standard opcode %d "
                "with %d operands: "
                "not understood.", opcode, opcnt);
            *err_count_out += 1;
            for (oc = 0; oc < opcnt; oc++) {
                /* 
                 * Read and discard operands we don't
                 * understand.
                 * Arbitrary choice of unsigned read.
                 * Signed read would work as well.
                 */
                Dwarf_Unsigned utmp2;

                DECODE_LEB128_UWORD(line_ptr, utmp2);
                printf(" %" DW_PR_DUu " (0x%" DW_PR_DUx ")",
                       (Dwarf_Unsigned) utmp2,
                       (Dwarf_Unsigned) utmp2);
            }

            printf("***\n");
            /* do nothing, necessary ops done */
        } else if (type == LOP_SPECIAL) {
            /* This op code is a special op in the object, no matter
               that it might fall into the standard op range in this
               compile Thatis, these are special opcodes between
               special_opcode_base and MAX_LINE_OP_CODE.  (including
               special_opcode_base and MAX_LINE_OP_CODE) */
            char special[50];
            unsigned origop = opcode;

            opcode = opcode - prefix.pf_opcode_base;
            address = address + prefix.pf_minimum_instruction_length *
                (opcode / prefix.pf_line_range);
            line =
                line + prefix.pf_line_base +
                opcode % prefix.pf_line_range;

            sprintf(special, "Specialop %3u", origop);
            print_line_detail(special,
                              opcode, address, (int) file, line, column,
                              is_stmt, basic_block, end_sequence,
                              prologue_end, epilogue_begin, isa);

            basic_block = false;

        } else if (type == LOP_STANDARD) {
            switch (opcode) {

            case DW_LNS_copy:{

                    print_line_detail("DW_LNS_copy",
                                      opcode, address, file, line,
                                      column, is_stmt, basic_block,
                                      end_sequence, prologue_end,
                                      epilogue_begin, isa);

                    basic_block = false;
                    break;
                }

            case DW_LNS_advance_pc:{
                    Dwarf_Unsigned utmp2;


                    DECODE_LEB128_UWORD(line_ptr, utmp2);
                    printf("DW_LNS_advance_pc val %" DW_PR_DSd " 0x%" DW_PR_DUx "\n",
                           (Dwarf_Signed) (Dwarf_Word) utmp2,
                           (Dwarf_Unsigned) (Dwarf_Word) utmp2);
                    leb128_num = (Dwarf_Word) utmp2;
                    address =
                        address +
                        prefix.pf_minimum_instruction_length *
                        leb128_num;
                    break;
                }

            case DW_LNS_advance_line:{
                    Dwarf_Signed stmp;


                    DECODE_LEB128_SWORD(line_ptr, stmp);
                    advance_line = (Dwarf_Sword) stmp;
                    printf("DW_LNS_advance_line val %" DW_PR_DSd " 0x%" DW_PR_DSx "\n",
                           (Dwarf_Signed) advance_line,
                           (Dwarf_Signed) advance_line);
                    line = line + advance_line;
                    break;
                }

            case DW_LNS_set_file:{
                    Dwarf_Unsigned utmp2;


                    DECODE_LEB128_UWORD(line_ptr, utmp2);
                    file = (Dwarf_Word) utmp2;
                    printf("DW_LNS_set_file  %ld\n", (long) file);
                    break;
                }

            case DW_LNS_set_column:{
                    Dwarf_Unsigned utmp2;


                    DECODE_LEB128_UWORD(line_ptr, utmp2);
                    column = (Dwarf_Word) utmp2;
                    printf("DW_LNS_set_column val %" DW_PR_DSd " 0x%" DW_PR_DSx "\n",
                           (Dwarf_Signed) column, (Dwarf_Signed) column);
                    break;
                }

            case DW_LNS_negate_stmt:{
                    is_stmt = !is_stmt;
                    printf("DW_LNS_negate_stmt\n");
                    break;
                }

            case DW_LNS_set_basic_block:{

                    printf("DW_LNS_set_basic_block\n");
                    basic_block = true;
                    break;
                }

            case DW_LNS_const_add_pc:{
                    opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base;
                    address =
                        address +
                        prefix.pf_minimum_instruction_length * (opcode /
                                                                prefix.
                                                                pf_line_range);

                    printf("DW_LNS_const_add_pc new address 0x%" DW_PR_DSx "\n",
                           (Dwarf_Signed) address);
                    break;
                }

            case DW_LNS_fixed_advance_pc:{

                    READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
                                   line_ptr, sizeof(Dwarf_Half));
                    line_ptr += sizeof(Dwarf_Half);
                    address = address + fixed_advance_pc;
                    printf("DW_LNS_fixed_advance_pc val %" DW_PR_DSd 
                       " 0x%" DW_PR_DSx " new address 0x%" DW_PR_DSx "\n",
                           (Dwarf_Signed) fixed_advance_pc,
                           (Dwarf_Signed) fixed_advance_pc,
                           (Dwarf_Signed) address);
                    break;
                }
            case DW_LNS_set_prologue_end:{

                    prologue_end = true;
                    printf("DW_LNS_set_prologue_end set true.\n");
                    break;


                }
                /* New in DWARF3 */
            case DW_LNS_set_epilogue_begin:{
                    epilogue_begin = true;
                    printf("DW_LNS_set_epilogue_begin set true.\n");
                    break;
                }

                /* New in DWARF3 */
            case DW_LNS_set_isa:{
                    Dwarf_Unsigned utmp2;

                    DECODE_LEB128_UWORD(line_ptr, utmp2);
                    isa = utmp2;
                    printf("DW_LNS_set_isa new value 0x%" DW_PR_DUx ".\n",
                           (Dwarf_Unsigned) utmp2);
                    if (isa != utmp2) {
                        /* The value of the isa did not fit in our
                           local so we record it wrong. declare an
                           error. */
                        dwarf_free_line_table_prefix(&prefix);

                        _dwarf_error(dbg, error,
                                     DW_DLE_LINE_NUM_OPERANDS_BAD);
                        return (DW_DLV_ERROR);
                    }
                    break;
                }
            }


        } else if (type == LOP_EXTENDED) {
            Dwarf_Unsigned utmp3 = 0;
            Dwarf_Word instr_length = 0;
            Dwarf_Small ext_opcode = 0;

            DECODE_LEB128_UWORD(line_ptr, utmp3);
            instr_length = (Dwarf_Word) utmp3;
            ext_opcode = *(Dwarf_Small *) line_ptr;
            line_ptr++;
            switch (ext_opcode) {

            case DW_LNE_end_sequence:{
                    end_sequence = true;

                    print_line_detail("DW_LNE_end_sequence extended",
                                      opcode, address, file, line,
                                      column, is_stmt, basic_block,
                                      end_sequence, prologue_end,
                                      epilogue_begin, isa);

                    address = 0;
                    file = 1;
                    line = 1;
                    column = 0;
                    is_stmt = prefix.pf_default_is_stmt;
                    basic_block = false;
                    end_sequence = false;
                    prologue_end = false;
                    epilogue_begin = false;


                    break;
                }

            case DW_LNE_set_address:{
                    {
                        READ_UNALIGNED(dbg, address, Dwarf_Addr,
                                       line_ptr, 
                                       die->di_cu_context->cc_address_size);

                        line_ptr += die->di_cu_context->cc_address_size;
                        printf("DW_LNE_set_address address 0x%" DW_PR_DUx "\n",
                               (Dwarf_Unsigned) address);
                    }

                    break;
                }

            case DW_LNE_define_file:{
                    Dwarf_Unsigned di = 0;
                    Dwarf_Unsigned tlm = 0;
                    Dwarf_Unsigned fl = 0;

                    Dwarf_Small *fn = (Dwarf_Small *) line_ptr;
                    line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

                    di = _dwarf_decode_u_leb128(line_ptr,
                                                &leb128_length);
                    line_ptr = line_ptr + leb128_length;

                    tlm = _dwarf_decode_u_leb128(line_ptr,
                                                 &leb128_length);
                    line_ptr = line_ptr + leb128_length;

                    fl = _dwarf_decode_u_leb128(line_ptr,
                                                &leb128_length);
                    line_ptr = line_ptr + leb128_length;


                    printf("DW_LNE_define_file %s \n", fn);
                    printf("    dir index %d\n", (int) di);
                    {
                        time_t tt3 = (time_t) tlm;

                        /* ctime supplies newline */
                        printf("    last time 0x%x %s",
                               (unsigned) tlm, ctime(&tt3));
                    }
                    printf("    file length %ld 0x%lx\n",
                           (long) fl, (unsigned long) fl);

                    break;
                }

            default:{
                 /* This is an extended op code we do not know about,
                    other than we know now many bytes it is
                    (and the op code and the bytes of operand). */

                 Dwarf_Unsigned remaining_bytes = instr_length -1;
                 if(instr_length < 1 || remaining_bytes > DW_LNE_LEN_MAX) {
                      dwarf_free_line_table_prefix(&prefix);
                      _dwarf_error(dbg, error,
                                 DW_DLE_LINE_EXT_OPCODE_BAD);
                      return (DW_DLV_ERROR);
                 }
                 printf("DW_LNE extended op 0x%x ",ext_opcode);
                 printf("Bytecount: " DW_PR_DUu , instr_length);
                 if(remaining_bytes > 0) {
                     printf(" linedata: 0x");
                     while (remaining_bytes > 0) {
                        printf("%02x",(unsigned char)(*(line_ptr)));
                        line_ptr++;
                        remaining_bytes--;
                     }
                 }
                 printf("\n");
                }
                break;
            }

        }
    }

    dwarf_free_line_table_prefix(&prefix);
    return (DW_DLV_OK);
}
Exemplo n.º 2
0
/*
	return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
*/
int
_dwarf_internal_printlines(Dwarf_Die die, Dwarf_Error * error)
{
    /* 
       This pointer is used to scan the portion of the .debug_line
       section for the current cu. */
    Dwarf_Small *line_ptr;
    Dwarf_Small *orig_line_ptr;

    /* 
       This points to the last byte of the .debug_line portion for the 
       current cu. */
    Dwarf_Small *line_ptr_end;

    /* 
       This points to the end of the statement program prologue for the 
       current cu, and serves to check that the prologue was correctly 
       decoded. */
    Dwarf_Small *check_line_ptr;

    /* 
       Pointer to a DW_AT_stmt_list attribute in case it exists in the 
       die. */
    Dwarf_Attribute stmt_list_attr;

    /* Pointer to DW_AT_comp_dir attribute in die. */
    Dwarf_Attribute comp_dir_attr;

    /* Pointer to name of compilation directory. */
    Dwarf_Small *comp_dir = NULL;

    /* 
       Offset into .debug_line specified by a DW_AT_stmt_list
       attribute. */
    Dwarf_Unsigned line_offset;

    /* These are the fields of the statement program header. */
    Dwarf_Unsigned total_length;
    Dwarf_Half version;
    Dwarf_Unsigned prologue_length;
    Dwarf_Small minimum_instruction_length;
    Dwarf_Small default_is_stmt;
    Dwarf_Sbyte line_base;
    Dwarf_Small line_range;
    Dwarf_Small opcode_base;

    Dwarf_Small *opcode_length;

    /* These are the state machine state variables. */
    Dwarf_Addr address;
    Dwarf_Word file;
    Dwarf_Word line;
    Dwarf_Word column;
    Dwarf_Bool is_stmt;
    Dwarf_Bool basic_block;
    Dwarf_Bool end_sequence;

    Dwarf_Sword i, file_entry_count, include_directories_count;

    /* 
       This is the current opcode read from the statement program. */
    Dwarf_Small opcode;

    /* 
       Pointer to a Dwarf_Line_Context_s structure that contains the
       context such as file names and include directories for the set
       of lines being generated. */
    Dwarf_Line_Context line_context;


    /* 
       These variables are used to decode leb128 numbers. Leb128_num
       holds the decoded number, and leb128_length is its length in
       bytes. */
    Dwarf_Word leb128_num;
    Dwarf_Word leb128_length;
    Dwarf_Sword advance_line;

    /* 
       This is the operand of the latest fixed_advance_pc extended
       opcode. */
    Dwarf_Half fixed_advance_pc;

    /* This is the length of an extended opcode instr.  */
    Dwarf_Word instr_length;
    Dwarf_Small ext_opcode;
    int local_length_size;
    /*REFERENCED*/ /* Not used in this instance of the macro */
    int local_extension_size;

    /* The Dwarf_Debug this die belongs to. */
    Dwarf_Debug dbg;
    int resattr;
    int lres;

    int res;

    /* ***** BEGIN CODE ***** */

    if (error != NULL)
	*error = NULL;

    CHECK_DIE(die, DW_DLV_ERROR)
	dbg = die->di_cu_context->cc_dbg;

    res =
       _dwarf_load_section(dbg,
		           dbg->de_debug_line_index,
			   &dbg->de_debug_line,
		           error);
    if (res != DW_DLV_OK) {
	return res;
    }

    resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
    if (resattr != DW_DLV_OK) {
	return resattr;
    }



    lres = dwarf_formudata(stmt_list_attr, &line_offset, error);
    if (lres != DW_DLV_OK) {
	return lres;
    }

    if (line_offset >= dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
	return (DW_DLV_ERROR);
    }
    orig_line_ptr = dbg->de_debug_line;
    line_ptr = dbg->de_debug_line + line_offset;
    dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);

    /* 
       If die has DW_AT_comp_dir attribute, get the string that names
       the compilation directory. */
    resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
    if (resattr == DW_DLV_ERROR) {
	return resattr;
    }
    if (resattr == DW_DLV_OK) {
	int cres;
	char *cdir;

	cres = dwarf_formstring(comp_dir_attr, &cdir, error);
	if (cres == DW_DLV_ERROR) {
	    return cres;
	} else if (cres == DW_DLV_OK) {
	    comp_dir = (Dwarf_Small *) cdir;
	}
    }
    if (resattr == DW_DLV_OK) {
	dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
    }

    /* 
       Following is a straightforward decoding of the statement
       program prologue information. */

    /* READ_AREA_LENGTH updates line_ptr for consumed bytes */
    READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned,
		     line_ptr, local_length_size, local_extension_size);



    line_ptr_end = line_ptr + total_length;
    if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    printf("total line info length %ld bytes, "
	   "line offset 0x%llx %lld\n",
	   (long) total_length,
	   (long long) line_offset, (long long) line_offset);
    printf("compilation_directory %s\n",
	   comp_dir ? ((char *) comp_dir) : "");
    READ_UNALIGNED(dbg, version, Dwarf_Half,
		   line_ptr, sizeof(Dwarf_Half));
    line_ptr += sizeof(Dwarf_Half);
    if (version != CURRENT_VERSION_STAMP) {
	_dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	return (DW_DLV_ERROR);
    }

    READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned,
		   line_ptr, local_length_size);
    line_ptr += local_length_size;
    check_line_ptr = line_ptr;

    minimum_instruction_length = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    default_is_stmt = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    line_base = *(Dwarf_Sbyte *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Sbyte);

    line_range = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    opcode_base = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);
    printf("  min instruction length %d\n",
	   (int) minimum_instruction_length);
    printf("  default is stmt        %d\n", (int) default_is_stmt);
    printf("  line base              %d\n", (int) line_base);
    printf("  line_range             %d\n", (int) line_range);

    opcode_length = (Dwarf_Small *)
	alloca(sizeof(Dwarf_Small) * opcode_base);

    for (i = 1; i < opcode_base; i++) {
	opcode_length[i] = *(Dwarf_Small *) line_ptr;
	printf("  opcode[%d] length %d\n", (int) i,
	       (int) opcode_length[i]);
	line_ptr = line_ptr + sizeof(Dwarf_Small);
    }

    include_directories_count = 0;
    while ((*(char *) line_ptr) != '\0') {
	printf("  include dir[%d] %s\n",
	       (int) include_directories_count, line_ptr);
	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
	include_directories_count++;
    }
    line_ptr++;

    file_entry_count = 0;
    while (*(char *) line_ptr != '\0') {

	Dwarf_Unsigned tlm2;
	Dwarf_Unsigned di;
	Dwarf_Unsigned fl;

	printf("  file[%d]  %s\n",
	       (int) file_entry_count, (char *) line_ptr);

	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

	di = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	tlm2 = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	fl = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	printf("    dir index %d\n", (int) di);
	{
	    time_t tt = (time_t) tlm2;

	    printf("    last time 0x%x %s",	/* ctime supplies
						   newline */
		   (unsigned) tlm2, ctime(&tt));
	}
	printf("    file length %ld 0x%lx\n",
	       (long) fl, (unsigned long) fl);


	file_entry_count++;
    }
    line_ptr++;

    if (line_ptr != check_line_ptr + prologue_length) {
	_dwarf_error(dbg, error, DW_DLE_LINE_PROLOG_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    /* Set up context structure for this set of lines. */
    line_context = (Dwarf_Line_Context)
	_dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1);
    if (line_context == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    printf("  statement prog offset in section: %lld 0x%llx\n",
	   (long long) (line_ptr - orig_line_ptr),
	   (long long) (line_ptr - orig_line_ptr));

    /* Initialize the state machine.  */
    address = 0;
    file = 1;
    line = 1;
    column = 0;
    is_stmt = default_is_stmt;
    basic_block = false;
    end_sequence = false;

    print_line_header();
    /* Start of statement program.  */
    while (line_ptr < line_ptr_end) {
	int type;

	printf(" [0x%06llx] ", (long long) (line_ptr - orig_line_ptr));
	opcode = *(Dwarf_Small *) line_ptr;
	line_ptr++;
	/* 'type' is the output */
	WHAT_IS_OPCODE(type, opcode, opcode_base,
		       opcode_length, line_ptr);



	if (type == LOP_DISCARD) {
	    /* do nothing, necessary ops done */
	} else if (type == LOP_SPECIAL) {
	    /* This op code is a special op in the object, no matter
	       that it might fall into the standard op range in this
	       compile Thatis, these are special opcodes between
	       special_opcode_base and MAX_LINE_OP_CODE.  (including
	       special_opcode_base and MAX_LINE_OP_CODE) */
	    char special[50];
	    unsigned origop = opcode;

	    opcode = opcode - opcode_base;
	    address = address + minimum_instruction_length *
		(opcode / line_range);
	    line = line + line_base + opcode % line_range;

	    sprintf(special, "Specialop %3u", origop);
	    print_line_detail(special,
			      opcode, address, (int) file, line, column,
			      is_stmt, basic_block, end_sequence);

	    basic_block = false;

	} else if (type == LOP_STANDARD) {
	    switch (opcode) {

	    case DW_LNS_copy:{
		    if (opcode_length[DW_LNS_copy] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    print_line_detail("DW_LNS_copy",
				      opcode, address, file, line,
				      column, is_stmt, basic_block,
				      end_sequence);

		    basic_block = false;
		    break;
		}

	    case DW_LNS_advance_pc:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_advance_pc] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			printf("DW_LNS_advance_pc val %lld 0x%llx\n",
			       (long long) (Dwarf_Word) utmp2,
			       (long long) (Dwarf_Word) utmp2);
		    leb128_num = (Dwarf_Word) utmp2;
		    address =
			address +
			minimum_instruction_length * leb128_num;
		    break;
		}

	    case DW_LNS_advance_line:{
		    Dwarf_Signed stmp;

		    if (opcode_length[DW_LNS_advance_line] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_SWORD(line_ptr, stmp)
			advance_line = (Dwarf_Sword) stmp;
		    printf("DW_LNS_advance_line val %lld 0x%llx\n",
			   (long long) advance_line,
			   (long long) advance_line);
		    line = line + advance_line;
		    break;
		}

	    case DW_LNS_set_file:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_set_file] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			file = (Dwarf_Word) utmp2;
		    printf("DW_LNS_set_file  %ld\n", (long) file);
		    break;
		}

	    case DW_LNS_set_column:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_set_column] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			column = (Dwarf_Word) utmp2;
		    printf("DW_LNS_set_column val %lld 0x%llx\n",
			   (long long) column, (long long) column);
		    break;
		}

	    case DW_LNS_negate_stmt:{
		    if (opcode_length[DW_LNS_negate_stmt] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    is_stmt = !is_stmt;
		    printf("DW_LNS_negate_stmt\n");
		    break;
		}

	    case DW_LNS_set_basic_block:{
		    if (opcode_length[DW_LNS_set_basic_block] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    printf("DW_LNS_set_basic_block\n");
		    basic_block = true;
		    break;
		}

	    case DW_LNS_const_add_pc:{
		    opcode = MAX_LINE_OP_CODE - opcode_base;
		    address = address + minimum_instruction_length *
			(opcode / line_range);

		    printf("DW_LNS_const_add_pc new address 0x%llx\n",
			   (long long) address);
		    break;
		}

	    case DW_LNS_fixed_advance_pc:{
		    if (opcode_length[DW_LNS_fixed_advance_pc] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
				   line_ptr, sizeof(Dwarf_Half));
		    line_ptr += sizeof(Dwarf_Half);
		    address = address + fixed_advance_pc;
		    printf("DW_LNS_fixed_advance_pc val %lld 0x%llx"
			   " new address 0x%llx\n",
			   (long long) fixed_advance_pc,
			   (long long) fixed_advance_pc,
			   (long long) address);
		    break;
		}
	    }

	} else if (type == LOP_EXTENDED) {
	    Dwarf_Unsigned utmp3;

	    DECODE_LEB128_UWORD(line_ptr, utmp3)
		instr_length = (Dwarf_Word) utmp3;
	    ext_opcode = *(Dwarf_Small *) line_ptr;
	    line_ptr++;
	    switch (ext_opcode) {

	    case DW_LNE_end_sequence:{
		    end_sequence = true;

		    print_line_detail("DW_LNE_end_sequence extended",
				      opcode, address, file, line,
				      column, is_stmt, basic_block,
				      end_sequence);

		    address = 0;
		    file = 1;
		    line = 1;
		    column = 0;
		    is_stmt = default_is_stmt;
		    basic_block = false;
		    end_sequence = false;

		    break;
		}

	    case DW_LNE_set_address:{
		    if (instr_length - 1 == dbg->de_pointer_size) {
			READ_UNALIGNED(dbg, address, Dwarf_Addr,
				       line_ptr, dbg->de_pointer_size);

			line_ptr += dbg->de_pointer_size;
			printf("DW_LNE_set_address address 0x%llx\n",
			       (long long) address);
		    } else {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_SET_ADDR_ERROR);
			return (DW_DLV_ERROR);
		    }

		    break;
		}

	    case DW_LNE_define_file:{


		    Dwarf_Small *fn;
		    Dwarf_Signed di;
		    Dwarf_Signed tlm;
		    Dwarf_Unsigned fl;

		    fn = (Dwarf_Small *) line_ptr;
		    line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

		    di = _dwarf_decode_u_leb128(line_ptr,
						&leb128_length);
		    line_ptr = line_ptr + leb128_length;

		    tlm =
			_dwarf_decode_u_leb128(line_ptr,
					       &leb128_length);
		    line_ptr = line_ptr + leb128_length;

		    fl = _dwarf_decode_u_leb128(line_ptr,
						&leb128_length);
		    line_ptr = line_ptr + leb128_length;


		    printf("DW_LNE_define_file %s \n", fn);
		    printf("    dir index %d\n", (int) di);
		    {
			time_t tt3 = (time_t) tlm;

			/* ctime supplies newline */
			printf("    last time 0x%x %s",
			       (unsigned) tlm, ctime(&tt3));
		    }
		    printf("    file length %ld 0x%lx\n",
			   (long) fl, (unsigned long) fl);

		    break;
		}

	    default:{
		    _dwarf_error(dbg, error,
				 DW_DLE_LINE_EXT_OPCODE_BAD);
		    return (DW_DLV_ERROR);
		}
	    }

	}
    }

    return (DW_DLV_OK);
}