tools/elf4rom/libs/dwarf-20071209/libdwarf/dwarf_line.c
changeset 34 92d87f2e53c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/elf4rom/libs/dwarf-20071209/libdwarf/dwarf_line.c	Fri Jan 15 09:07:44 2010 +0000
@@ -0,0 +1,1827 @@
+/*
+
+  Copyright (C) 2000,2002,2004,2005,2006 Silicon Graphics, Inc.  All Rights Reserved.
+  Portions Copyright (C) 2007 David Anderson. All Rights Reserved.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2.1 of the GNU Lesser General Public License 
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it would be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+
+  Further, this software is distributed without any warranty that it is
+  free of the rightful claim of any third person regarding infringement 
+  or the like.  Any license provided herein, whether implied or 
+  otherwise, applies only to this software file.  Patent licenses, if
+  any, provided herein do not apply to combinations of this program with 
+  other software, or any other product whatsoever.  
+
+  You should have received a copy of the GNU Lesser General Public 
+  License along with this program; if not, write the Free Software 
+  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+  USA.
+
+  Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
+  Mountain View, CA 94043, or:
+
+  http://www.sgi.com
+
+  For further information regarding this notice, see:
+
+  http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 
+   Boston, MA 02110-1301, USA.
+   SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "dwarf_line.h"
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+
+/* 
+    Although source files is supposed to return the
+    source files in the compilation-unit, it does
+    not look for any in the statement program.  In
+    other words, it ignores those defined using the
+    extended opcode DW_LNE_define_file.
+*/
+int
+dwarf_srcfiles(Dwarf_Die die,
+	       char ***srcfiles,
+	       Dwarf_Signed * srcfilecount, Dwarf_Error * error)
+{
+    /* 
+       This pointer is used to scan the portion of the .debug_line
+       section for the current cu. */
+    Dwarf_Small *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 = 0;
+
+    /* Offset into .debug_line specified by a DW_AT_stmt_list
+       attribute. */
+    Dwarf_Unsigned line_offset = 0;
+
+
+
+    /* 
+       This points to a block of char *'s, each of which points to a
+       file name. */
+    char **ret_files = 0;
+
+    /* The Dwarf_Debug this die belongs to. */
+    Dwarf_Debug dbg = 0;
+
+    /* Used to chain the file names. */
+    Dwarf_Chain curr_chain = NULL;
+    Dwarf_Chain prev_chain = NULL;
+    Dwarf_Chain head_chain = NULL;
+    int resattr = 0;
+    int lres = 0;
+    struct Line_Table_Prefix_s line_prefix;
+    int i = 0;
+    int res = 0;
+
+
+    /* ***** BEGIN CODE ***** */
+
+    /* Reset error. */
+    if (error != NULL)
+	*error = NULL;
+
+    CHECK_DIE(die, DW_DLV_ERROR);
+    dbg = die->di_cu_context->cc_dbg;
+
+    resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
+    if (resattr != DW_DLV_OK) {
+	return resattr;
+    }
+
+    if (dbg->de_debug_line_index == 0) {
+	_dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_NULL);
+	return (DW_DLV_ERROR);
+    }
+
+    res =
+	_dwarf_load_section(dbg,
+			    dbg->de_debug_line_index,
+			    &dbg->de_debug_line, error);
+    if (res != DW_DLV_OK) {
+	return res;
+    }
+
+    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);
+    }
+    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);
+    }
+    dwarf_init_line_table_prefix(&line_prefix);
+    {
+	Dwarf_Small *line_ptr_out = 0;
+	int dres = dwarf_read_line_table_prefix(dbg,
+						line_ptr,
+						dbg->de_debug_line_size,
+						&line_ptr_out,
+						&line_prefix, error);
+
+	if (dres == DW_DLV_ERROR) {
+	    dwarf_free_line_table_prefix(&line_prefix);
+	    return dres;
+	}
+	if (dres == DW_DLV_NO_ENTRY) {
+	    dwarf_free_line_table_prefix(&line_prefix);
+	    return dres;
+	}
+
+	line_ptr = line_ptr_out;
+    }
+
+    for (i = 0; i < line_prefix.pf_files_count; ++i) {
+	struct Line_Table_File_Entry_s *fe =
+	    line_prefix.pf_line_table_file_entries + i;
+	char *file_name = (char *) fe->lte_filename;
+	char *dir_name = 0;
+	char *full_name = 0;
+	Dwarf_Unsigned dir_index = fe->lte_directory_index;
+
+	if (dir_index == 0) {
+	    dir_name = (char *) comp_dir;
+	} else {
+	    dir_name =
+		(char *) line_prefix.pf_include_directories[fe->
+							    lte_directory_index
+							    - 1];
+	}
+
+	/* dir_name can be NULL if there is no DW_AT_comp_dir */
+	if ((*file_name) == '/' || dir_name == 0) {
+	    /* This is safe because dwarf_dealloc is careful to not
+	       dealloc strings which are part of the raw .debug_* data. 
+	     */
+	    full_name = file_name;
+	} else {
+	    full_name = (char *) _dwarf_get_alloc(dbg, DW_DLA_STRING,
+						  strlen(dir_name) + 1 +
+						  strlen(file_name) +
+						  1);
+	    if (full_name == NULL) {
+		dwarf_free_line_table_prefix(&line_prefix);
+		_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+		return (DW_DLV_ERROR);
+	    }
+
+	    /* This is not careful to avoid // in the output, Nothing
+	       forces a 'canonical' name format here. Unclear if this
+	       needs to be fixed. */
+	    strcpy(full_name, dir_name);
+	    strcat(full_name, "/");
+	    strcat(full_name, file_name);
+	}
+	curr_chain =
+	    (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+	if (curr_chain == NULL) {
+	    dwarf_free_line_table_prefix(&line_prefix);
+	    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+	    return (DW_DLV_ERROR);
+	}
+	curr_chain->ch_item = full_name;
+	if (head_chain == NULL)
+	    head_chain = prev_chain = curr_chain;
+	else {
+	    prev_chain->ch_next = curr_chain;
+	    prev_chain = curr_chain;
+	}
+
+
+    }
+
+    curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+    if (curr_chain == NULL) {
+	dwarf_free_line_table_prefix(&line_prefix);
+	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+	return (DW_DLV_ERROR);
+    }
+
+
+
+
+    if (line_prefix.pf_files_count == 0) {
+	*srcfiles = NULL;
+	*srcfilecount = 0;
+	dwarf_free_line_table_prefix(&line_prefix);
+	return (DW_DLV_NO_ENTRY);
+    }
+
+    ret_files = (char **)
+	_dwarf_get_alloc(dbg, DW_DLA_LIST, line_prefix.pf_files_count);
+    if (ret_files == NULL) {
+	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+	dwarf_free_line_table_prefix(&line_prefix);
+	return (DW_DLV_ERROR);
+    }
+
+    curr_chain = head_chain;
+    for (i = 0; i < line_prefix.pf_files_count; i++) {
+	*(ret_files + i) = curr_chain->ch_item;
+	prev_chain = curr_chain;
+	curr_chain = curr_chain->ch_next;
+	dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
+    }
+
+    *srcfiles = ret_files;
+    *srcfilecount = line_prefix.pf_files_count;
+    dwarf_free_line_table_prefix(&line_prefix);
+    return (DW_DLV_OK);
+}
+
+
+/*
+	return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
+*/
+int
+_dwarf_internal_srclines(Dwarf_Die die,
+			 Dwarf_Line ** linebuf,
+			 Dwarf_Signed * count,
+			 Dwarf_Bool doaddrs,
+			 Dwarf_Bool dolines, Dwarf_Error * error)
+{
+    /* 
+       This pointer is used to scan the portion of the .debug_line
+       section for the current cu. */
+    Dwarf_Small *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;
+
+    Dwarf_File_Entry file_entries = 0;
+
+    /* These are the state machine state variables. */
+    Dwarf_Addr address = 0;
+    Dwarf_Word file = 1;
+    Dwarf_Word line = 1;
+    Dwarf_Word column = 0;
+
+    /* phony init. See below for true initialization. */
+    Dwarf_Bool is_stmt = false;
+
+    Dwarf_Bool basic_block = false;
+    Dwarf_Bool prologue_end = false;
+    Dwarf_Bool epilogue_begin = false;
+    Dwarf_Small isa = 0;
+    Dwarf_Bool end_sequence = false;
+
+    /* 
+       These pointers are used to build the list of files names by this 
+       cu.  cur_file_entry points to the file name being added, and
+       prev_file_entry to the previous one. */
+    Dwarf_File_Entry cur_file_entry, prev_file_entry;
+
+    Dwarf_Sword i = 0;
+    Dwarf_Sword file_entry_count = 0;
+
+    /* 
+       This is the current opcode read from the statement program. */
+    Dwarf_Small opcode = 0;
+
+    /* 
+       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 = 0;
+
+    /* 
+       This is a pointer to the current line being added to the line
+       matrix. */
+    Dwarf_Line curr_line = 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;
+
+    /* 
+       This is the operand of the latest fixed_advance_pc extended
+       opcode. */
+    Dwarf_Half fixed_advance_pc = 0;
+
+    /* 
+       Counts the number of lines in the line matrix. */
+    Dwarf_Sword line_count = 0;
+
+    /* This is the length of an extended opcode instr.  */
+    Dwarf_Word instr_length = 0;
+    Dwarf_Small ext_opcode = 0;
+    struct Line_Table_Prefix_s prefix;
+
+    /* 
+       Used to chain together pointers to line table entries that are
+       later used to create a block of Dwarf_Line entries. */
+    Dwarf_Chain chain_line = NULL;
+    Dwarf_Chain head_chain = NULL;
+    Dwarf_Chain curr_chain = NULL;
+
+    /* 
+       This points to a block of Dwarf_Lines, a pointer to which is
+       returned in linebuf. */
+    Dwarf_Line *block_line = 0;
+
+    /* The Dwarf_Debug this die belongs to. */
+    Dwarf_Debug dbg = 0;
+    int resattr = 0;
+    int lres = 0;
+
+    int res = 0;
+
+    /* ***** 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);
+    }
+    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);
+    }
+    dwarf_init_line_table_prefix(&prefix);
+
+    {
+	Dwarf_Small *newlinep = 0;
+	int res = dwarf_read_line_table_prefix(dbg,
+					       line_ptr,
+					       dbg->de_debug_line_size,
+					       &newlinep,
+					       &prefix,
+					       error);
+
+	if (res == DW_DLV_ERROR) {
+	    dwarf_free_line_table_prefix(&prefix);
+	    return res;
+	}
+	if (res == DW_DLV_NO_ENTRY) {
+	    dwarf_free_line_table_prefix(&prefix);
+	    return res;
+	}
+	line_ptr_end = prefix.pf_line_ptr_end;
+	line_ptr = newlinep;
+    }
+
+
+    /* 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_free_line_table_prefix(&prefix);
+	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+	return (DW_DLV_ERROR);
+    }
+
+    /* Fill out a Dwarf_File_Entry list as we use that to implement the 
+       define_file operation. */
+    file_entries = prev_file_entry = NULL;
+    for (i = 0; i < prefix.pf_files_count; ++i) {
+	struct Line_Table_File_Entry_s *pfxfile =
+	    prefix.pf_line_table_file_entries + i;
+
+	cur_file_entry = (Dwarf_File_Entry)
+	    _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
+	if (cur_file_entry == NULL) {
+	    dwarf_free_line_table_prefix(&prefix);
+	    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+	    return (DW_DLV_ERROR);
+	}
+
+	cur_file_entry->fi_file_name = pfxfile->lte_filename;
+	cur_file_entry->fi_dir_index = pfxfile->lte_directory_index;
+	cur_file_entry->fi_time_last_mod =
+	    pfxfile->lte_last_modification_time;
+
+	cur_file_entry->fi_file_length = pfxfile->lte_length_of_file;
+
+	if (file_entries == NULL)
+	    file_entries = cur_file_entry;
+	else
+	    prev_file_entry->fi_next = cur_file_entry;
+	prev_file_entry = cur_file_entry;
+
+	file_entry_count++;
+    }
+
+
+    /* Initialize the one state machine variable that depends on the
+       prefix.  */
+    is_stmt = prefix.pf_default_is_stmt;
+
+
+    /* Start of statement program.  */
+    while (line_ptr < line_ptr_end) {
+	int type;
+
+	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];
+
+	    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);
+	    }
+	} 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. That is, these are special opcodes between
+	       opcode_base and MAX_LINE_OP_CODE.  (including
+	       opcode_base and MAX_LINE_OP_CODE) */
+
+	    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;
+
+	    if (dolines) {
+		curr_line =
+		    (Dwarf_Line) _dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
+		if (curr_line == NULL) {
+		    dwarf_free_line_table_prefix(&prefix);
+		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+		    return (DW_DLV_ERROR);
+		}
+
+		curr_line->li_address = address;
+		curr_line->li_addr_line.li_l_data.li_file =
+		    (Dwarf_Sword) file;
+		curr_line->li_addr_line.li_l_data.li_line =
+		    (Dwarf_Sword) line;
+		curr_line->li_addr_line.li_l_data.li_column =
+		    (Dwarf_Half) column;
+		curr_line->li_addr_line.li_l_data.li_is_stmt = is_stmt;
+		curr_line->li_addr_line.li_l_data.li_basic_block =
+		    basic_block;
+		curr_line->li_addr_line.li_l_data.li_end_sequence =
+		    curr_line->li_addr_line.li_l_data.
+		    li_epilogue_begin = epilogue_begin;
+		curr_line->li_addr_line.li_l_data.li_prologue_end =
+		    prologue_end;
+		curr_line->li_addr_line.li_l_data.li_isa = isa;
+		curr_line->li_context = line_context;
+		line_count++;
+
+		chain_line = (Dwarf_Chain)
+		    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+		if (chain_line == NULL) {
+		    dwarf_free_line_table_prefix(&prefix);
+		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+		    return (DW_DLV_ERROR);
+		}
+		chain_line->ch_item = curr_line;
+
+		if (head_chain == NULL)
+		    head_chain = curr_chain = chain_line;
+		else {
+		    curr_chain->ch_next = chain_line;
+		    curr_chain = chain_line;
+		}
+	    }
+
+	    basic_block = false;
+	} else if (type == LOP_STANDARD) {
+	    switch (opcode) {
+
+	    case DW_LNS_copy:{
+		    if (dolines) {
+
+			curr_line =
+			    (Dwarf_Line) _dwarf_get_alloc(dbg,
+							  DW_DLA_LINE,
+							  1);
+			if (curr_line == NULL) {
+			    dwarf_free_line_table_prefix(&prefix);
+			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+			    return (DW_DLV_ERROR);
+			}
+
+			curr_line->li_address = address;
+			curr_line->li_addr_line.li_l_data.li_file =
+			    (Dwarf_Sword) file;
+			curr_line->li_addr_line.li_l_data.li_line =
+			    (Dwarf_Sword) line;
+			curr_line->li_addr_line.li_l_data.li_column =
+			    (Dwarf_Half) column;
+			curr_line->li_addr_line.li_l_data.li_is_stmt =
+			    is_stmt;
+			curr_line->li_addr_line.li_l_data.
+			    li_basic_block = basic_block;
+			curr_line->li_addr_line.li_l_data.
+			    li_end_sequence = end_sequence;
+			curr_line->li_context = line_context;
+			curr_line->li_addr_line.li_l_data.
+			    li_epilogue_begin = epilogue_begin;
+			curr_line->li_addr_line.li_l_data.
+			    li_prologue_end = prologue_end;
+			curr_line->li_addr_line.li_l_data.li_isa = isa;
+			line_count++;
+
+			chain_line = (Dwarf_Chain)
+			    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+			if (chain_line == NULL) {
+			    dwarf_free_line_table_prefix(&prefix);
+			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+			    return (DW_DLV_ERROR);
+			}
+			chain_line->ch_item = curr_line;
+			if (head_chain == NULL)
+			    head_chain = curr_chain = chain_line;
+			else {
+			    curr_chain->ch_next = chain_line;
+			    curr_chain = chain_line;
+			}
+		    }
+
+		    basic_block = false;
+		    prologue_end = false;
+		    epilogue_begin = false;
+		    break;
+		}
+
+	    case DW_LNS_advance_pc:{
+		    Dwarf_Unsigned utmp2;
+
+		    DECODE_LEB128_UWORD(line_ptr, 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;
+		    line = line + advance_line;
+		    break;
+		}
+
+	    case DW_LNS_set_file:{
+		    Dwarf_Unsigned utmp2;
+
+		    DECODE_LEB128_UWORD(line_ptr, utmp2);
+		    file = (Dwarf_Word) utmp2;
+		    break;
+		}
+
+	    case DW_LNS_set_column:{
+		    Dwarf_Unsigned utmp2;
+
+		    DECODE_LEB128_UWORD(line_ptr, utmp2);
+		    column = (Dwarf_Word) utmp2;
+		    break;
+		}
+
+	    case DW_LNS_negate_stmt:{
+
+		    is_stmt = !is_stmt;
+		    break;
+		}
+
+	    case DW_LNS_set_basic_block:{
+
+		    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);
+
+		    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;
+		    break;
+		}
+
+		/* New in DWARF3 */
+	    case DW_LNS_set_prologue_end:{
+
+		    prologue_end = true;
+		    break;
+
+
+		}
+		/* New in DWARF3 */
+	    case DW_LNS_set_epilogue_begin:{
+		    epilogue_begin = true;
+		    break;
+		}
+
+		/* New in DWARF3 */
+	    case DW_LNS_set_isa:{
+		    Dwarf_Unsigned utmp2;
+
+		    DECODE_LEB128_UWORD(line_ptr, utmp2);
+		    isa = 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;
+
+	    DECODE_LEB128_UWORD(line_ptr, utmp3);
+	    instr_length = (Dwarf_Word) utmp3;
+	    /* Dwarf_Small is a ubyte and the extended opcode is a
+	       ubyte, though not stated as clearly in the 2.0.0 spec as 
+	       one might hope. */
+	    ext_opcode = *(Dwarf_Small *) line_ptr;
+	    line_ptr++;
+	    switch (ext_opcode) {
+
+	    case DW_LNE_end_sequence:{
+		    end_sequence = true;
+
+		    if (dolines) {
+			curr_line = (Dwarf_Line)
+			    _dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
+			if (curr_line == NULL) {
+			    dwarf_free_line_table_prefix(&prefix);
+			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+			    return (DW_DLV_ERROR);
+			}
+
+			curr_line->li_address = address;
+			curr_line->li_addr_line.li_l_data.li_file =
+			    (Dwarf_Sword) file;
+			curr_line->li_addr_line.li_l_data.li_line =
+			    (Dwarf_Sword) line;
+			curr_line->li_addr_line.li_l_data.li_column =
+			    (Dwarf_Half) column;
+			curr_line->li_addr_line.li_l_data.li_is_stmt =
+			    prefix.pf_default_is_stmt;
+			curr_line->li_addr_line.li_l_data.
+			    li_basic_block = basic_block;
+			curr_line->li_addr_line.li_l_data.
+			    li_end_sequence = end_sequence;
+			curr_line->li_context = line_context;
+			curr_line->li_addr_line.li_l_data.
+			    li_epilogue_begin = epilogue_begin;
+			curr_line->li_addr_line.li_l_data.
+			    li_prologue_end = prologue_end;
+			curr_line->li_addr_line.li_l_data.li_isa = isa;
+			line_count++;
+
+			chain_line = (Dwarf_Chain)
+			    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+			if (chain_line == NULL) {
+			    dwarf_free_line_table_prefix(&prefix);
+			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+			    return (DW_DLV_ERROR);
+			}
+			chain_line->ch_item = curr_line;
+
+			if (head_chain == NULL)
+			    head_chain = curr_chain = chain_line;
+			else {
+			    curr_chain->ch_next = chain_line;
+			    curr_chain = chain_line;
+			}
+		    }
+
+		    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:{
+		    if (instr_length - 1 == dbg->de_pointer_size) {
+			READ_UNALIGNED(dbg, address, Dwarf_Addr,
+				       line_ptr, dbg->de_pointer_size);
+			if (doaddrs) {
+			    curr_line =
+				(Dwarf_Line) _dwarf_get_alloc(dbg,
+							      DW_DLA_LINE,
+							      1);
+			    if (curr_line == NULL) {
+				dwarf_free_line_table_prefix(&prefix);
+				_dwarf_error(dbg, error,
+					     DW_DLE_ALLOC_FAIL);
+				return (DW_DLV_ERROR);
+			    }
+
+			    curr_line->li_address = address;
+			    curr_line->li_addr_line.li_offset =
+				line_ptr - dbg->de_debug_line;
+
+			    line_count++;
+
+			    chain_line = (Dwarf_Chain)
+				_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+			    if (chain_line == NULL) {
+				dwarf_free_line_table_prefix(&prefix);
+				_dwarf_error(dbg, error,
+					     DW_DLE_ALLOC_FAIL);
+				return (DW_DLV_ERROR);
+			    }
+			    chain_line->ch_item = curr_line;
+
+			    if (head_chain == NULL)
+				head_chain = curr_chain = chain_line;
+			    else {
+				curr_chain->ch_next = chain_line;
+				curr_chain = chain_line;
+			    }
+			}
+
+			line_ptr += dbg->de_pointer_size;
+		    } else {
+			dwarf_free_line_table_prefix(&prefix);
+			_dwarf_error(dbg, error,
+				     DW_DLE_LINE_SET_ADDR_ERROR);
+			return (DW_DLV_ERROR);
+		    }
+
+		    break;
+		}
+
+	    case DW_LNE_define_file:{
+
+		    if (dolines) {
+			cur_file_entry = (Dwarf_File_Entry)
+			    _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
+			if (cur_file_entry == NULL) {
+			    dwarf_free_line_table_prefix(&prefix);
+			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+			    return (DW_DLV_ERROR);
+			}
+
+			cur_file_entry->fi_file_name =
+			    (Dwarf_Small *) line_ptr;
+			line_ptr =
+			    line_ptr + strlen((char *) line_ptr) + 1;
+
+			cur_file_entry->fi_dir_index = (Dwarf_Sword)
+			    _dwarf_decode_u_leb128(line_ptr,
+						   &leb128_length);
+			line_ptr = line_ptr + leb128_length;
+
+			cur_file_entry->fi_time_last_mod =
+			    _dwarf_decode_u_leb128(line_ptr,
+						   &leb128_length);
+			line_ptr = line_ptr + leb128_length;
+
+			cur_file_entry->fi_file_length =
+			    _dwarf_decode_u_leb128(line_ptr,
+						   &leb128_length);
+			line_ptr = line_ptr + leb128_length;
+
+			if (file_entries == NULL)
+			    file_entries = cur_file_entry;
+			else
+			    prev_file_entry->fi_next = cur_file_entry;
+			prev_file_entry = cur_file_entry;
+
+			file_entry_count++;
+		    }
+		    break;
+		}
+
+	    default:{
+		    dwarf_free_line_table_prefix(&prefix);
+		    _dwarf_error(dbg, error,
+				 DW_DLE_LINE_EXT_OPCODE_BAD);
+		    return (DW_DLV_ERROR);
+		}
+	    }
+
+	}
+    }
+
+    block_line = (Dwarf_Line *)
+	_dwarf_get_alloc(dbg, DW_DLA_LIST, line_count);
+    if (block_line == NULL) {
+	dwarf_free_line_table_prefix(&prefix);
+	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+	return (DW_DLV_ERROR);
+    }
+
+    curr_chain = head_chain;
+    for (i = 0; i < line_count; i++) {
+	*(block_line + i) = curr_chain->ch_item;
+	head_chain = curr_chain;
+	curr_chain = curr_chain->ch_next;
+	dwarf_dealloc(dbg, head_chain, DW_DLA_CHAIN);
+    }
+
+    line_context->lc_file_entries = file_entries;
+    line_context->lc_file_entry_count = file_entry_count;
+    line_context->lc_include_directories_count =
+	prefix.pf_include_directories_count;
+    if (prefix.pf_include_directories_count > 0) {
+	/* This gets a pointer to the *first* include dir. The others
+	   follow directly with the standard DWARF2/3 NUL byte
+	   following the last. */
+	line_context->lc_include_directories =
+	    prefix.pf_include_directories[0];
+    }
+
+    line_context->lc_line_count = line_count;
+    line_context->lc_compilation_directory = comp_dir;
+    line_context->lc_version_number = prefix.pf_version;
+    line_context->lc_dbg = dbg;
+    *count = line_count;
+
+    *linebuf = block_line;
+    dwarf_free_line_table_prefix(&prefix);
+    return (DW_DLV_OK);
+}
+
+int
+dwarf_srclines(Dwarf_Die die,
+	       Dwarf_Line ** linebuf,
+	       Dwarf_Signed * linecount, Dwarf_Error * error)
+{
+    Dwarf_Signed count;
+    int res;
+
+    res = _dwarf_internal_srclines(die, linebuf, &count,	/* addrlist= 
+								 */ false,
+				   /* linelist= */ true, error);
+    if (res != DW_DLV_OK) {
+	return res;
+    }
+    *linecount = count;
+    return res;
+}
+
+
+
+/* Every line table entry (except DW_DLE_end_sequence,
+   which is returned using dwarf_lineendsequence())
+   potentially has the begin-statement
+   flag marked 'on'.   This returns thru *return_bool,
+   the begin-statement flag.
+*/
+
+int
+dwarf_linebeginstatement(Dwarf_Line line,
+			 Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+    if (line == NULL || return_bool == 0) {
+	_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+	return (DW_DLV_ERROR);
+    }
+
+    *return_bool = (line->li_addr_line.li_l_data.li_is_stmt);
+    return DW_DLV_OK;
+}
+
+/* At the end of any contiguous line-table there may be
+   a DW_LNE_end_sequence operator.
+   This returns non-zero thru *return_bool
+   if and only if this 'line' entry was a DW_LNE_end_sequence.
+
+   Within a compilation unit or function there may be multiple
+   line tables, each ending with a DW_LNE_end_sequence.
+   Each table describes a contiguous region.
+   Because compilers may split function code up in arbitrary ways
+   compilers may need to emit multiple contigous regions (ie
+   line tables) for a single function.
+   See the DWARF3 spec section 6.2.
+*/
+int
+dwarf_lineendsequence(Dwarf_Line line,
+		      Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+    if (line == NULL) {
+	_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+	return (DW_DLV_ERROR);
+    }
+
+    *return_bool = (line->li_addr_line.li_l_data.li_end_sequence);
+    return DW_DLV_OK;
+}
+
+
+/* Each 'line' entry has a line-number.
+   If the entry is a DW_LNE_end_sequence the line-number is
+   meaningless (see dwarf_lineendsequence(), just above).
+*/
+int
+dwarf_lineno(Dwarf_Line line,
+	     Dwarf_Unsigned * ret_lineno, Dwarf_Error * error)
+{
+    if (line == NULL || ret_lineno == 0) {
+	_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+	return (DW_DLV_ERROR);
+    }
+
+    *ret_lineno = (line->li_addr_line.li_l_data.li_line);
+    return DW_DLV_OK;
+}
+
+/* Each 'line' entry has a file-number, and index into the file table.
+   If the entry is a DW_LNE_end_sequence the index is
+   meaningless (see dwarf_lineendsequence(), just above).
+   The file number returned is an index into the file table
+   produced by dwarf_srcfiles(), but care is required: the
+   li_file begins with 1 for real files, so that the li_file returned here
+   is 1 greater than its index into the dwarf_srcfiles() output array.
+   And entries from DW_LNE_define_file don't appear in
+   the dwarf_srcfiles() output so file indexes from here may exceed
+   the size of the dwarf_srcfiles() output array size.
+*/
+int
+dwarf_line_srcfileno(Dwarf_Line line,
+		     Dwarf_Unsigned * ret_fileno, Dwarf_Error * error)
+{
+    if (line == NULL || ret_fileno == 0) {
+	_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+	return (DW_DLV_ERROR);
+    }
+    /* li_file must be <= line->li_context->lc_file_entry_count else it 
+       is trash. li_file 0 means not attributable to any source file
+       per dwarf2/3 spec. */
+
+    *ret_fileno = (line->li_addr_line.li_l_data.li_file);
+    return DW_DLV_OK;
+}
+
+
+/* Each 'line' entry has a line-address.
+   If the entry is a DW_LNE_end_sequence the adddress
+   is one-beyond the last address this contigous region
+   covers, so the address is not inside the region, 
+   but is just outside it.
+*/
+int
+dwarf_lineaddr(Dwarf_Line line,
+	       Dwarf_Addr * ret_lineaddr, Dwarf_Error * error)
+{
+    if (line == NULL || ret_lineaddr == 0) {
+	_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+	return (DW_DLV_ERROR);
+    }
+
+    *ret_lineaddr = (line->li_address);
+    return DW_DLV_OK;
+}
+
+
+/* Each 'line' entry has a column-within-line (offset
+   within the line) where the
+   source text begins.
+   If the entry is a DW_LNE_end_sequence the line-number is
+   meaningless (see dwarf_lineendsequence(), just above).
+   Lines of text begin at column 1.  The value 0
+   means the line begins at the left edge of the line.
+   (See the DWARF3 spec, section 6.2.2).
+*/
+int
+dwarf_lineoff(Dwarf_Line line,
+	      Dwarf_Signed * ret_lineoff, Dwarf_Error * error)
+{
+    if (line == NULL || ret_lineoff == 0) {
+	_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+	return (DW_DLV_ERROR);
+    }
+
+    *ret_lineoff =
+	(line->li_addr_line.li_l_data.li_column ==
+	 0 ? -1 : line->li_addr_line.li_l_data.li_column);
+    return DW_DLV_OK;
+}
+
+
+int
+dwarf_linesrc(Dwarf_Line line, char **ret_linesrc, Dwarf_Error * error)
+{
+    Dwarf_Signed i;
+    Dwarf_File_Entry file_entry;
+    Dwarf_Small *name_buffer;
+    Dwarf_Small *include_directories;
+    Dwarf_Debug dbg;
+    unsigned int comp_dir_len;
+
+    if (line == NULL) {
+	_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+	return (DW_DLV_ERROR);
+    }
+
+    if (line->li_context == NULL) {
+	_dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_NULL);
+	return (DW_DLV_ERROR);
+    }
+    dbg = line->li_context->lc_dbg;
+
+    if (line->li_addr_line.li_l_data.li_file >
+	line->li_context->lc_file_entry_count) {
+	_dwarf_error(dbg, error, DW_DLE_LINE_FILE_NUM_BAD);
+	return (DW_DLV_ERROR);
+    }
+
+    if (line->li_addr_line.li_l_data.li_file == 0) {
+	/* No file name known: see dwarf2/3 spec. */
+	_dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME);
+	return (DW_DLV_ERROR);
+    }
+    file_entry = line->li_context->lc_file_entries;
+    /* ASSERT: li_file > 0, dwarf correctness issue, see line table
+       definition of dwarf2/3 spec. */
+    /* Example: if li_file is 2 and lc_file_entry_count is 3,
+       file_entry is file 3 (1 based), aka 2( 0 based) file_entry->next 
+       is file 2 (1 based), aka 1( 0 based) file_entry->next->next is
+       file 1 (1 based), aka 0( 0 based) file_entry->next->next->next
+       is NULL.
+
+       and this loop finds the file_entry we need (2 (1 based) in this
+       case). Because lc_file_entries are in reverse order and
+       effectively zero based as a count whereas li_file is 1 based. */
+    for (i = line->li_addr_line.li_l_data.li_file - 1; i > 0; i--)
+	file_entry = file_entry->fi_next;
+
+    if (file_entry->fi_file_name == NULL) {
+	_dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME);
+	return (DW_DLV_ERROR);
+    }
+
+    if (*(char *) file_entry->fi_file_name == '/') {
+	*ret_linesrc = ((char *) file_entry->fi_file_name);
+	return DW_DLV_OK;
+    }
+
+    if (file_entry->fi_dir_index == 0) {
+
+	/* dir_index of 0 means that the compilation was in the
+	   'current directory of compilation' */
+	if (line->li_context->lc_compilation_directory == NULL) {
+	    /* we don't actually *have* a current directory of
+	       compilation: DW_AT_comp_dir was not present Rather than
+	       emitting DW_DLE_NO_COMP_DIR lets just make an empty name 
+	       here. In other words, do the best we can with what we do 
+	       have instead of reporting an error. _dwarf_error(dbg,
+	       error, DW_DLE_NO_COMP_DIR); return(DW_DLV_ERROR); */
+	    comp_dir_len = 0;
+	} else {
+	    comp_dir_len = strlen((char *)
+				  (line->li_context->
+				   lc_compilation_directory));
+	}
+
+	name_buffer =
+	    _dwarf_get_alloc(line->li_context->lc_dbg, DW_DLA_STRING,
+			     comp_dir_len + 1 +
+			     strlen((char *) file_entry->fi_file_name) +
+			     1);
+	if (name_buffer == NULL) {
+	    _dwarf_error(line->li_context->lc_dbg, error,
+			 DW_DLE_ALLOC_FAIL);
+	    return (DW_DLV_ERROR);
+	}
+
+	if (comp_dir_len > 0) {
+	    /* if comp_dir_len is 0 we do not want to put a / in front
+	       of the fi_file_name as we just don't know anything. */
+	    strcpy((char *) name_buffer,
+		   (char *) (line->li_context->
+			     lc_compilation_directory));
+	    strcat((char *) name_buffer, "/");
+	}
+	strcat((char *) name_buffer, (char *) file_entry->fi_file_name);
+	*ret_linesrc = ((char *) name_buffer);
+	return DW_DLV_OK;
+    }
+
+    if (file_entry->fi_dir_index >
+	line->li_context->lc_include_directories_count) {
+	_dwarf_error(dbg, error, DW_DLE_INCL_DIR_NUM_BAD);
+	return (DW_DLV_ERROR);
+    }
+
+    include_directories = line->li_context->lc_include_directories;
+    for (i = file_entry->fi_dir_index - 1; i > 0; i--)
+	include_directories += strlen((char *) include_directories) + 1;
+
+    if (line->li_context->lc_compilation_directory) {
+	comp_dir_len = strlen((char *)
+			      (line->li_context->
+			       lc_compilation_directory));
+    } else {
+	/* No DW_AT_comp_dir present. Do the best we can without it. */
+	comp_dir_len = 0;
+    }
+
+    name_buffer = _dwarf_get_alloc(dbg, DW_DLA_STRING,
+				   (*include_directories == '/' ?
+				    0 : comp_dir_len + 1) +
+				   strlen((char *) include_directories)
+				   + 1 +
+				   strlen((char *) file_entry->
+					  fi_file_name) + 1);
+    if (name_buffer == NULL) {
+	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+	return (DW_DLV_ERROR);
+    }
+
+    if (*include_directories != '/') {
+	if (comp_dir_len > 0) {
+	    strcpy((char *) name_buffer,
+		   (char *) line->li_context->lc_compilation_directory);
+	    /* Who provides the / needed after the compilation
+	       directory? */
+	    if (name_buffer[comp_dir_len - 1] != '/') {
+		/* Here we provide the / separator */
+		name_buffer[comp_dir_len] = '/';	/* overwrite
+							   previous nul 
+							   terminator
+							   with needed
+							   / */
+		name_buffer[comp_dir_len + 1] = 0;
+	    }
+	}
+    } else {
+	strcpy((char *) name_buffer, "");
+    }
+    strcat((char *) name_buffer, (char *) include_directories);
+    strcat((char *) name_buffer, "/");
+    strcat((char *) name_buffer, (char *) file_entry->fi_file_name);
+    *ret_linesrc = ((char *) name_buffer);
+    return DW_DLV_OK;
+}
+
+/* Every line table entry potentially has the basic-block-start
+   flag marked 'on'.   This returns thru *return_bool,
+   the basic-block-start flag.
+*/
+int
+dwarf_lineblock(Dwarf_Line line,
+		Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+    if (line == NULL) {
+	_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+	return (DW_DLV_ERROR);
+    }
+
+    *return_bool = (line->li_addr_line.li_l_data.li_basic_block);
+    return DW_DLV_OK;
+}
+
+
+#if 0				/* Ignore this.  This needs major
+				   re-work. */
+/* 
+    This routine works by looking for exact matches between 
+    the current line address and pc, and crossovers from
+    from less than pc value to greater than.  At each line
+    that satisfies the above, it records a pointer to the
+    line, and the difference between the address and pc.
+    It then scans these pointers and picks out those with
+    the smallest difference between pc and address.         
+*/
+int
+dwarf_pclines(Dwarf_Debug dbg,
+	      Dwarf_Addr pc,
+	      Dwarf_Line ** linebuf,
+	      Dwarf_Signed slide,
+	      Dwarf_Signed * linecount, Dwarf_Error * error)
+{
+    /* 
+       Scans the line matrix for the current cu to which a pointer
+       exists in dbg. */
+    Dwarf_Line line;
+    Dwarf_Line prev_line;
+
+    /* 
+       These flags are for efficiency reasons. Check_line is true
+       initially, but set false when the address of the current line is 
+       greater than pc.  It is set true only when the address of the
+       current line falls below pc.  This assumes that addresses within 
+       the same segment increase, and we are only interested in the
+       switch from a less than pc address to a greater than. First_line 
+       is set true initially, but set false after the first line is
+       scanned.  This is to prevent looking at the address of previous
+       line when slide is DW_DLS_BACKWARD, and the first line is being
+       scanned. */
+    Dwarf_Bool check_line, first_line;
+
+    /* 
+       Diff tracks the smallest difference a line address and the input 
+       pc value. */
+    Dwarf_Signed diff, i;
+
+    /* 
+       For the slide = DW_DLS_BACKWARD case, pc_less is the value of
+       the address of the line immediately preceding the first line
+       that has value greater than pc. For the slide = DW_DLS_FORWARD
+       case, pc_more is the values of address for the first line that
+       is greater than pc. Diff is the difference between either of the 
+       these values and pc. */
+    Dwarf_Addr pc_less, pc_more;
+
+    /* 
+       Pc_line_buf points to a chain of pointers to lines of which
+       those with a diff equal to the smallest difference will be
+       returned. */
+    Dwarf_Line *pc_line_buf, *pc_line;
+
+    /* 
+       Chain_count counts the number of lines in the above chain for
+       which the diff is equal to the smallest difference This is the
+       number returned by this routine. */
+    Dwarf_Signed chain_count;
+
+    chain_head = NULL;
+
+    check_line = true;
+    first_line = true;
+    diff = MAX_LINE_DIFF;
+
+    for (i = 0; i < dbg->de_cu_line_count; i++) {
+
+	line = *(dbg->de_cu_line_ptr + i);
+	prev_line = first_line ? NULL : *(dbg->de_cu_line_ptr + i - 1);
+
+	if (line->li_address == pc) {
+	    chain_ptr = (struct chain *)
+		_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+	    if (chain_ptr == NULL) {
+		_dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
+		return (DW_DLV_ERROR);
+	    }
+
+	    chain_ptr->line = line;
+	    chain_ptr->diff = diff = 0;
+	    chain_ptr->next = chain_head;
+	    chain_head = chain_ptr;
+	} else
+	    /* 
+	       Look for crossover from less than pc address to greater
+	       than. */
+	if (check_line && line->li_address > pc &&
+		(first_line ? 0 : prev_line->li_address) < pc)
+
+	    if (slide == DW_DLS_BACKWARD && !first_line) {
+		pc_less = prev_line->li_address;
+		if (pc - pc_less <= diff) {
+		    chain_ptr = (struct chain *)
+			_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+		    if (chain_ptr == NULL) {
+			_dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
+			return (DW_DLV_ERROR);
+		    }
+
+		    chain_ptr->line = prev_line;
+		    chain_ptr->diff = diff = pc - pc_less;
+		    chain_ptr->next = chain_head;
+		    chain_head = chain_ptr;
+		}
+		check_line = false;
+	    } else if (slide == DW_DLS_FORWARD) {
+		pc_more = line->li_address;
+		if (pc_more - pc <= diff) {
+		    chain_ptr = (struct chain *)
+			_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+		    if (chain_ptr == NULL) {
+			_dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
+			return (DW_DLV_ERROR);
+		    }
+
+		    chain_ptr->line = line;
+		    chain_ptr->diff = diff = pc_more - pc;
+		    chain_ptr->next = chain_head;
+		    chain_head = chain_ptr;
+		}
+		check_line = false;
+	    } else
+		/* Check addresses only when they go */
+		/* below pc.  */
+	    if (line->li_address < pc)
+		check_line = true;
+
+	first_line = false;
+    }
+
+    chain_count = 0;
+    for (chain_ptr = chain_head; chain_ptr != NULL;
+	 chain_ptr = chain_ptr->next)
+	if (chain_ptr->diff == diff)
+	    chain_count++;
+
+    pc_line_buf = pc_line = (Dwarf_Line)
+	_dwarf_get_alloc(dbg, DW_DLA_LIST, chain_count);
+    for (chain_ptr = chain_head; chain_ptr != NULL;
+	 chain_ptr = chain_ptr->next)
+	if (chain_ptr->diff == diff) {
+	    *pc_line = chain_ptr->line;
+	    pc_line++;
+	}
+
+    for (chain_ptr = chain_head; chain_ptr != NULL;) {
+	chain_head = chain_ptr;
+	chain_ptr = chain_ptr->next;
+	dwarf_dealloc(dbg, chain_head, DW_DLA_CHAIN);
+    }
+
+    *linebuf = pc_line_buf;
+    return (chain_count);
+}
+#endif
+
+
+
+/*
+   It's impossible for callers of dwarf_srclines() to get to and
+   free all the resources (in particular, the li_context and its
+   lc_file_entries). 
+   So this function, new July 2005, does it.  
+*/
+
+void
+dwarf_srclines_dealloc(Dwarf_Debug dbg, Dwarf_Line * linebuf,
+		       Dwarf_Signed count)
+{
+
+    Dwarf_Signed i = 0;
+    struct Dwarf_Line_Context_s *context = 0;
+
+    if (count > 0) {
+	/* All these entries share a single context */
+	context = linebuf[0]->li_context;
+    }
+    for (i = 0; i < count; ++i) {
+	dwarf_dealloc(dbg, linebuf[i], DW_DLA_LINE);
+    }
+    dwarf_dealloc(dbg, linebuf, DW_DLA_LIST);
+
+    if (context) {
+	Dwarf_File_Entry fe = context->lc_file_entries;
+
+	while (fe) {
+	    Dwarf_File_Entry fenext = fe->fi_next;
+
+	    dwarf_dealloc(dbg, fe, DW_DLA_FILE_ENTRY);
+	    fe = fenext;
+	}
+	dwarf_dealloc(dbg, context, DW_DLA_LINE_CONTEXT);
+    }
+
+    return;
+}
+
+/* Operand counts per standard operand.
+   The initial zero is for DW_LNS_copy. 
+   This is an economical way to verify we understand the table
+   of standard-opcode-lengths in the line table prologue.  */
+#define STANDARD_OPERAND_COUNT_DWARF2 9
+#define STANDARD_OPERAND_COUNT_DWARF3 12
+static unsigned char
+  dwarf_standard_opcode_operand_count[STANDARD_OPERAND_COUNT_DWARF3] = {
+    /* DWARF2 */
+    0,
+    1, 1, 1, 1,
+    0, 0, 0,
+    1,
+    /* Following are new for DWARF3. */
+    0, 0, 1
+};
+
+/* Common line table prefix reading code. 
+   Returns DW_DLV_OK, DW_DLV_ERROR.
+   DW_DLV_NO_ENTRY cannot be returned, but callers should
+   assume it is possible.
+
+   The prefix_out area must be initialized properly before calling this.
+
+   Has the side effect of allocating arrays which
+   must be freed (see the Line_Table_Prefix_s struct which
+   holds the pointers to space we allocate here).
+*/
+int
+dwarf_read_line_table_prefix(Dwarf_Debug dbg,
+			     Dwarf_Small * data_start,
+			     Dwarf_Unsigned data_length,
+			     Dwarf_Small ** updated_data_start_out,
+			     struct Line_Table_Prefix_s *prefix_out,
+			     Dwarf_Error * err)
+{
+    Dwarf_Small *line_ptr = data_start;
+    Dwarf_Unsigned total_length = 0;
+    int local_length_size = 0;
+    int local_extension_size = 0;
+    Dwarf_Unsigned prologue_length = 0;
+    Dwarf_Half version = 0;
+    Dwarf_Unsigned directories_count = 0;
+    Dwarf_Unsigned directories_malloc = 0;
+    Dwarf_Unsigned files_count = 0;
+    Dwarf_Unsigned files_malloc = 0;
+    Dwarf_Small *line_ptr_end = 0;
+
+    prefix_out->pf_line_ptr_start = line_ptr;
+    /* 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;
+    prefix_out->pf_line_ptr_end = line_ptr_end;
+    prefix_out->pf_length_field_length = local_length_size +
+	local_extension_size;
+    /* ASSERT: prefix_out->pf_length_field_length == line_ptr
+       -prefix_out->pf_line_ptr_start; */
+    if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) {
+	_dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
+	return (DW_DLV_ERROR);
+    }
+    if (line_ptr_end > data_start + data_length) {
+	_dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
+	return (DW_DLV_ERROR);
+    }
+    prefix_out->pf_total_length = total_length;
+
+    READ_UNALIGNED(dbg, version, Dwarf_Half,
+		   line_ptr, sizeof(Dwarf_Half));
+    prefix_out->pf_version = version;
+    line_ptr += sizeof(Dwarf_Half);
+    if (version != CURRENT_VERSION_STAMP &&
+	version != CURRENT_VERSION_STAMP3) {
+	_dwarf_error(dbg, err, DW_DLE_VERSION_STAMP_ERROR);
+	return (DW_DLV_ERROR);
+    }
+
+    READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned,
+		   line_ptr, local_length_size);
+    prefix_out->pf_prologue_length = prologue_length;
+    line_ptr += local_length_size;
+    prefix_out->pf_line_prologue_start = line_ptr;
+
+
+    prefix_out->pf_minimum_instruction_length =
+	*(unsigned char *) line_ptr;
+    line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+    prefix_out->pf_default_is_stmt = *(unsigned char *) line_ptr;
+    line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+    prefix_out->pf_line_base = *(signed char *) line_ptr;
+    line_ptr = line_ptr + sizeof(Dwarf_Sbyte);
+
+    prefix_out->pf_line_range = *(unsigned char *) line_ptr;
+    line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+    prefix_out->pf_opcode_base = *(unsigned char *) line_ptr;
+    line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+    /* Set up the array of standard opcode lengths. */
+    /* We think this works ok even for cross-endian processing of
+       objects.  It might be wrong, we might need to specially process
+       the array of ubyte into host order.  */
+    prefix_out->pf_opcode_length_table = line_ptr;
+
+    /* pf_opcode_base is one greater than the size of the array. */
+    line_ptr += prefix_out->pf_opcode_base - 1;
+
+    {
+	/* Determine (as best we can) whether the
+	   pf_opcode_length_table holds 9 or 12 standard-conforming
+	   entries.  gcc4 upped to DWARF3's 12 without updating the
+	   version number.  */
+	int operand_ck_fail = true;
+
+	if (prefix_out->pf_opcode_base >= STANDARD_OPERAND_COUNT_DWARF3) {
+	    int mismatch = memcmp(dwarf_standard_opcode_operand_count,
+				  prefix_out->pf_opcode_length_table,
+				  STANDARD_OPERAND_COUNT_DWARF3);
+
+	    if (!mismatch) {
+		operand_ck_fail = false;
+		prefix_out->pf_std_op_count =
+		    STANDARD_OPERAND_COUNT_DWARF3;
+	    }
+
+	}
+	if (operand_ck_fail) {
+	    if (prefix_out->pf_opcode_base >=
+		STANDARD_OPERAND_COUNT_DWARF2) {
+
+		int mismatch =
+		    memcmp(dwarf_standard_opcode_operand_count,
+			   prefix_out->pf_opcode_length_table,
+			   STANDARD_OPERAND_COUNT_DWARF2);
+
+		if (!mismatch) {
+		    operand_ck_fail = false;
+		    prefix_out->pf_std_op_count =
+			STANDARD_OPERAND_COUNT_DWARF2;
+		}
+	    }
+	}
+	if (operand_ck_fail) {
+	    _dwarf_error(dbg, err, DW_DLE_LINE_NUM_OPERANDS_BAD);
+	    return (DW_DLV_ERROR);
+	}
+    }
+    /* At this point we no longer need to check operand counts. */
+
+
+    directories_count = 0;
+    directories_malloc = 5;
+    prefix_out->pf_include_directories = malloc(sizeof(Dwarf_Small *) *
+						directories_malloc);
+    if (prefix_out->pf_include_directories == NULL) {
+	_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+	return (DW_DLV_ERROR);
+    }
+    memset(prefix_out->pf_include_directories, 0,
+	   sizeof(Dwarf_Small *) * directories_malloc);
+
+    while ((*(char *) line_ptr) != '\0') {
+	if (directories_count >= directories_malloc) {
+	    Dwarf_Unsigned expand = 2 * directories_malloc;
+	    Dwarf_Unsigned bytesalloc = sizeof(Dwarf_Small *) * expand;
+	    Dwarf_Small **newdirs =
+		realloc(prefix_out->pf_include_directories,
+			bytesalloc);
+
+	    if (!newdirs) {
+		_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+		return (DW_DLV_ERROR);
+	    }
+	    /* Doubled size, zero out second half. */
+	    memset(newdirs + directories_malloc, 0,
+		   sizeof(Dwarf_Small *) * directories_malloc);
+	    directories_malloc = expand;
+	    prefix_out->pf_include_directories = newdirs;
+	}
+	prefix_out->pf_include_directories[directories_count] =
+	    line_ptr;
+	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
+	directories_count++;
+    }
+    prefix_out->pf_include_directories_count = directories_count;
+    line_ptr++;
+
+    files_count = 0;
+    files_malloc = 5;
+    prefix_out->pf_line_table_file_entries =
+	malloc(sizeof(struct Line_Table_File_Entry_s) * files_malloc);
+    if (prefix_out->pf_line_table_file_entries == NULL) {
+	_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+	return (DW_DLV_ERROR);
+    }
+    memset(prefix_out->pf_line_table_file_entries, 0,
+	   sizeof(struct Line_Table_File_Entry_s) * files_malloc);
+
+    while (*(char *) line_ptr != '\0') {
+	Dwarf_Unsigned utmp;
+	Dwarf_Unsigned dir_index = 0;
+	Dwarf_Unsigned lastmod = 0;
+	Dwarf_Unsigned file_length = 0;
+	struct Line_Table_File_Entry_s *curline;
+	Dwarf_Word leb128_length = 0;
+
+
+	if (files_count >= files_malloc) {
+	    Dwarf_Unsigned expand = 2 * files_malloc;
+	    struct Line_Table_File_Entry_s *newfiles =
+		realloc(prefix_out->pf_line_table_file_entries,
+			sizeof(struct Line_Table_File_Entry_s) *
+			expand);
+	    if (!newfiles) {
+		_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+		return (DW_DLV_ERROR);
+	    }
+	    memset(newfiles + files_malloc, 0,
+		   sizeof(struct Line_Table_File_Entry_s) *
+		   files_malloc);
+	    files_malloc = expand;
+	    prefix_out->pf_line_table_file_entries = newfiles;
+	}
+	curline = prefix_out->pf_line_table_file_entries + files_count;
+
+	curline->lte_filename = line_ptr;
+	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
+
+	DECODE_LEB128_UWORD(line_ptr, utmp);
+	dir_index = (Dwarf_Sword) utmp;
+	if (dir_index > directories_count) {
+	    _dwarf_error(dbg, err, DW_DLE_DIR_INDEX_BAD);
+	    return (DW_DLV_ERROR);
+	}
+	curline->lte_directory_index = dir_index;
+
+	lastmod = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
+	line_ptr = line_ptr + leb128_length;
+	curline->lte_last_modification_time = lastmod;
+
+	/* Skip over file length. */
+	file_length = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
+	line_ptr = line_ptr + leb128_length;
+	curline->lte_length_of_file = file_length;
+
+	++files_count;
+
+    }
+    prefix_out->pf_files_count = files_count;
+    /* Skip trailing nul byte */
+    ++line_ptr;
+
+
+    if (line_ptr != (prefix_out->pf_line_prologue_start +
+		     prefix_out->pf_prologue_length)) {
+	_dwarf_error(dbg, err, DW_DLE_LINE_PROLOG_LENGTH_BAD);
+	return (DW_DLV_ERROR);
+    }
+
+
+    *updated_data_start_out = line_ptr;
+    return DW_DLV_OK;
+}
+
+
+/* Initialize the Line_Table_Prefix_s struct. 
+   memset is not guaranteed a portable initializer, but works
+   fine for current architectures.   AFAIK.
+*/
+void
+dwarf_init_line_table_prefix(struct Line_Table_Prefix_s *pf)
+{
+    memset(pf, 0, sizeof(*pf));
+}
+
+/* Free any malloc'd area.  of the Line_Table_Prefix_s struct. */
+void
+dwarf_free_line_table_prefix(struct Line_Table_Prefix_s *pf)
+{
+    if (pf->pf_include_directories) {
+	free(pf->pf_include_directories);
+	pf->pf_include_directories = 0;
+    }
+    if (pf->pf_line_table_file_entries) {
+	free(pf->pf_line_table_file_entries);
+	pf->pf_line_table_file_entries = 0;
+    }
+    return;
+}