summaryrefslogtreecommitdiffstats
path: root/rtemstoolkit/elftoolchain/libdwarf/libdwarf_lineno.c
diff options
context:
space:
mode:
Diffstat (limited to 'rtemstoolkit/elftoolchain/libdwarf/libdwarf_lineno.c')
-rw-r--r--rtemstoolkit/elftoolchain/libdwarf/libdwarf_lineno.c777
1 files changed, 777 insertions, 0 deletions
diff --git a/rtemstoolkit/elftoolchain/libdwarf/libdwarf_lineno.c b/rtemstoolkit/elftoolchain/libdwarf/libdwarf_lineno.c
new file mode 100644
index 0000000..d0ff5f8
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libdwarf/libdwarf_lineno.c
@@ -0,0 +1,777 @@
+/*-
+ * Copyright (c) 2009,2010 Kai Wang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "_libdwarf.h"
+
+ELFTC_VCSID("$Id: libdwarf_lineno.c 3164 2015-02-19 01:20:12Z kaiwang27 $");
+
+static int
+_dwarf_lineno_add_file(Dwarf_LineInfo li, uint8_t **p, const char *compdir,
+ Dwarf_Error *error, Dwarf_Debug dbg)
+{
+ Dwarf_LineFile lf;
+ const char *dirname;
+ uint8_t *src;
+ int slen;
+
+ src = *p;
+
+ if ((lf = malloc(sizeof(struct _Dwarf_LineFile))) == NULL) {
+ DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
+ return (DW_DLE_MEMORY);
+ }
+
+ lf->lf_fullpath = NULL;
+ lf->lf_fname = (char *) src;
+ src += strlen(lf->lf_fname) + 1;
+ lf->lf_dirndx = _dwarf_decode_uleb128(&src);
+ if (lf->lf_dirndx > li->li_inclen) {
+ free(lf);
+ DWARF_SET_ERROR(dbg, error, DW_DLE_DIR_INDEX_BAD);
+ return (DW_DLE_DIR_INDEX_BAD);
+ }
+
+ /* Make full pathname if need. */
+ if (*lf->lf_fname != '/') {
+ dirname = compdir;
+ if (lf->lf_dirndx > 0)
+ dirname = li->li_incdirs[lf->lf_dirndx - 1];
+ if (dirname != NULL) {
+ slen = strlen(dirname) + strlen(lf->lf_fname) + 2;
+ if ((lf->lf_fullpath = malloc(slen)) == NULL) {
+ free(lf);
+ DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
+ return (DW_DLE_MEMORY);
+ }
+ snprintf(lf->lf_fullpath, slen, "%s/%s", dirname,
+ lf->lf_fname);
+ }
+ }
+
+ lf->lf_mtime = _dwarf_decode_uleb128(&src);
+ lf->lf_size = _dwarf_decode_uleb128(&src);
+ STAILQ_INSERT_TAIL(&li->li_lflist, lf, lf_next);
+ li->li_lflen++;
+
+ *p = src;
+
+ return (DW_DLE_NONE);
+}
+
+static int
+_dwarf_lineno_run_program(Dwarf_CU cu, Dwarf_LineInfo li, uint8_t *p,
+ uint8_t *pe, const char *compdir, Dwarf_Error *error)
+{
+ Dwarf_Debug dbg;
+ Dwarf_Line ln, tln;
+ uint64_t address, file, line, column, opsize;
+ int is_stmt, basic_block, end_sequence;
+ int ret;
+
+#define RESET_REGISTERS \
+ do { \
+ address = 0; \
+ file = 1; \
+ line = 1; \
+ column = 0; \
+ is_stmt = li->li_defstmt; \
+ basic_block = 0; \
+ end_sequence = 0; \
+ } while(0)
+
+#define APPEND_ROW \
+ do { \
+ ln = malloc(sizeof(struct _Dwarf_Line)); \
+ if (ln == NULL) { \
+ ret = DW_DLE_MEMORY; \
+ DWARF_SET_ERROR(dbg, error, ret); \
+ goto prog_fail; \
+ } \
+ ln->ln_li = li; \
+ ln->ln_addr = address; \
+ ln->ln_symndx = 0; \
+ ln->ln_fileno = file; \
+ ln->ln_lineno = line; \
+ ln->ln_column = column; \
+ ln->ln_bblock = basic_block; \
+ ln->ln_stmt = is_stmt; \
+ ln->ln_endseq = end_sequence; \
+ STAILQ_INSERT_TAIL(&li->li_lnlist, ln, ln_next);\
+ li->li_lnlen++; \
+ } while(0)
+
+#define LINE(x) (li->li_lbase + (((x) - li->li_opbase) % li->li_lrange))
+#define ADDRESS(x) ((((x) - li->li_opbase) / li->li_lrange) * li->li_minlen)
+
+ dbg = cu->cu_dbg;
+
+ /*
+ * Set registers to their default values.
+ */
+ RESET_REGISTERS;
+
+ /*
+ * Start line number program.
+ */
+ while (p < pe) {
+ if (*p == 0) {
+
+ /*
+ * Extended Opcodes.
+ */
+
+ p++;
+ opsize = _dwarf_decode_uleb128(&p);
+ switch (*p) {
+ case DW_LNE_end_sequence:
+ p++;
+ end_sequence = 1;
+ APPEND_ROW;
+ RESET_REGISTERS;
+ break;
+ case DW_LNE_set_address:
+ p++;
+ address = dbg->decode(&p, cu->cu_pointer_size);
+ break;
+ case DW_LNE_define_file:
+ p++;
+ ret = _dwarf_lineno_add_file(li, &p, compdir,
+ error, dbg);
+ if (ret != DW_DLE_NONE)
+ goto prog_fail;
+ break;
+ default:
+ /* Unrecognized extened opcodes. */
+ p += opsize;
+ }
+
+ } else if (*p > 0 && *p < li->li_opbase) {
+
+ /*
+ * Standard Opcodes.
+ */
+
+ switch (*p++) {
+ case DW_LNS_copy:
+ APPEND_ROW;
+ basic_block = 0;
+ break;
+ case DW_LNS_advance_pc:
+ address += _dwarf_decode_uleb128(&p) *
+ li->li_minlen;
+ break;
+ case DW_LNS_advance_line:
+ line += _dwarf_decode_sleb128(&p);
+ break;
+ case DW_LNS_set_file:
+ file = _dwarf_decode_uleb128(&p);
+ break;
+ case DW_LNS_set_column:
+ column = _dwarf_decode_uleb128(&p);
+ break;
+ case DW_LNS_negate_stmt:
+ is_stmt = !is_stmt;
+ break;
+ case DW_LNS_set_basic_block:
+ basic_block = 1;
+ break;
+ case DW_LNS_const_add_pc:
+ address += ADDRESS(255);
+ break;
+ case DW_LNS_fixed_advance_pc:
+ address += dbg->decode(&p, 2);
+ break;
+ case DW_LNS_set_prologue_end:
+ break;
+ case DW_LNS_set_epilogue_begin:
+ break;
+ case DW_LNS_set_isa:
+ (void) _dwarf_decode_uleb128(&p);
+ break;
+ default:
+ /* Unrecognized extened opcodes. What to do? */
+ break;
+ }
+
+ } else {
+
+ /*
+ * Special Opcodes.
+ */
+
+ line += LINE(*p);
+ address += ADDRESS(*p);
+ APPEND_ROW;
+ basic_block = 0;
+ p++;
+ }
+ }
+
+ return (DW_DLE_NONE);
+
+prog_fail:
+
+ STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
+ STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next);
+ free(ln);
+ }
+
+ return (ret);
+
+#undef RESET_REGISTERS
+#undef APPEND_ROW
+#undef LINE
+#undef ADDRESS
+}
+
+int
+_dwarf_lineno_init(Dwarf_Die die, uint64_t offset, Dwarf_Error *error)
+{
+ Dwarf_Debug dbg;
+ Dwarf_Section *ds;
+ Dwarf_CU cu;
+ Dwarf_Attribute at;
+ Dwarf_LineInfo li;
+ Dwarf_LineFile lf, tlf;
+ const char *compdir;
+ uint64_t length, hdroff, endoff;
+ uint8_t *p;
+ int dwarf_size, i, ret;
+
+ cu = die->die_cu;
+ assert(cu != NULL);
+
+ dbg = cu->cu_dbg;
+ assert(dbg != NULL);
+
+ if ((ds = _dwarf_find_section(dbg, ".debug_line")) == NULL)
+ return (DW_DLE_NONE);
+
+ /*
+ * Try to find out the dir where the CU was compiled. Later we
+ * will use the dir to create full pathnames, if need.
+ */
+ compdir = NULL;
+ at = _dwarf_attr_find(die, DW_AT_comp_dir);
+ if (at != NULL) {
+ switch (at->at_form) {
+ case DW_FORM_strp:
+ compdir = at->u[1].s;
+ break;
+ case DW_FORM_string:
+ compdir = at->u[0].s;
+ break;
+ default:
+ break;
+ }
+ }
+
+ length = dbg->read(ds->ds_data, &offset, 4);
+ if (length == 0xffffffff) {
+ dwarf_size = 8;
+ length = dbg->read(ds->ds_data, &offset, 8);
+ } else
+ dwarf_size = 4;
+
+ if (length > ds->ds_size - offset) {
+ DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD);
+ return (DW_DLE_DEBUG_LINE_LENGTH_BAD);
+ }
+
+ if ((li = calloc(1, sizeof(struct _Dwarf_LineInfo))) == NULL) {
+ DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
+ return (DW_DLE_MEMORY);
+ }
+
+ /*
+ * Read in line number program header.
+ */
+ li->li_length = length;
+ endoff = offset + length;
+ li->li_version = dbg->read(ds->ds_data, &offset, 2); /* FIXME: verify version */
+ li->li_hdrlen = dbg->read(ds->ds_data, &offset, dwarf_size);
+ hdroff = offset;
+ li->li_minlen = dbg->read(ds->ds_data, &offset, 1);
+ if (li->li_version == 4)
+ li->li_maxop = dbg->read(ds->ds_data, &offset, 1);
+ li->li_defstmt = dbg->read(ds->ds_data, &offset, 1);
+ li->li_lbase = dbg->read(ds->ds_data, &offset, 1);
+ li->li_lrange = dbg->read(ds->ds_data, &offset, 1);
+ li->li_opbase = dbg->read(ds->ds_data, &offset, 1);
+ STAILQ_INIT(&li->li_lflist);
+ STAILQ_INIT(&li->li_lnlist);
+
+ if ((int)li->li_hdrlen - 5 < li->li_opbase - 1) {
+ ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
+ DWARF_SET_ERROR(dbg, error, ret);
+ goto fail_cleanup;
+ }
+
+ if ((li->li_oplen = malloc(li->li_opbase)) == NULL) {
+ ret = DW_DLE_MEMORY;
+ DWARF_SET_ERROR(dbg, error, ret);
+ goto fail_cleanup;
+ }
+
+ /*
+ * Read in std opcode arg length list. Note that the first
+ * element is not used.
+ */
+ for (i = 1; i < li->li_opbase; i++)
+ li->li_oplen[i] = dbg->read(ds->ds_data, &offset, 1);
+
+ /*
+ * Check how many strings in the include dir string array.
+ */
+ length = 0;
+ p = ds->ds_data + offset;
+ while (*p != '\0') {
+ while (*p++ != '\0')
+ ;
+ length++;
+ }
+ li->li_inclen = length;
+
+ /* Sanity check. */
+ if (p - ds->ds_data > (int) ds->ds_size) {
+ ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
+ DWARF_SET_ERROR(dbg, error, ret);
+ goto fail_cleanup;
+ }
+
+ if (length != 0) {
+ if ((li->li_incdirs = malloc(length * sizeof(char *))) ==
+ NULL) {
+ ret = DW_DLE_MEMORY;
+ DWARF_SET_ERROR(dbg, error, ret);
+ goto fail_cleanup;
+ }
+ }
+
+ /* Fill in include dir array. */
+ i = 0;
+ p = ds->ds_data + offset;
+ while (*p != '\0') {
+ li->li_incdirs[i++] = (char *) p;
+ while (*p++ != '\0')
+ ;
+ }
+
+ p++;
+
+ /*
+ * Process file list.
+ */
+ while (*p != '\0') {
+ ret = _dwarf_lineno_add_file(li, &p, compdir, error, dbg);
+ if (ret != DW_DLE_NONE)
+ goto fail_cleanup;
+ if (p - ds->ds_data > (int) ds->ds_size) {
+ ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
+ DWARF_SET_ERROR(dbg, error, ret);
+ goto fail_cleanup;
+ }
+ }
+
+ p++;
+
+ /* Sanity check. */
+ if (p - ds->ds_data - hdroff != li->li_hdrlen) {
+ ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
+ DWARF_SET_ERROR(dbg, error, ret);
+ goto fail_cleanup;
+ }
+
+ /*
+ * Process line number program.
+ */
+ ret = _dwarf_lineno_run_program(cu, li, p, ds->ds_data + endoff, compdir,
+ error);
+ if (ret != DW_DLE_NONE)
+ goto fail_cleanup;
+
+ cu->cu_lineinfo = li;
+
+ return (DW_DLE_NONE);
+
+fail_cleanup:
+
+ STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
+ STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile, lf_next);
+ if (lf->lf_fullpath)
+ free(lf->lf_fullpath);
+ free(lf);
+ }
+
+ if (li->li_oplen)
+ free(li->li_oplen);
+ if (li->li_incdirs)
+ free(li->li_incdirs);
+ free(li);
+
+ return (ret);
+}
+
+void
+_dwarf_lineno_cleanup(Dwarf_LineInfo li)
+{
+ Dwarf_LineFile lf, tlf;
+ Dwarf_Line ln, tln;
+
+ if (li == NULL)
+ return;
+ STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
+ STAILQ_REMOVE(&li->li_lflist, lf,
+ _Dwarf_LineFile, lf_next);
+ if (lf->lf_fullpath)
+ free(lf->lf_fullpath);
+ free(lf);
+ }
+ STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
+ STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line,
+ ln_next);
+ free(ln);
+ }
+ if (li->li_oplen)
+ free(li->li_oplen);
+ if (li->li_incdirs)
+ free(li->li_incdirs);
+ if (li->li_lnarray)
+ free(li->li_lnarray);
+ if (li->li_lfnarray)
+ free(li->li_lfnarray);
+ free(li);
+}
+
+static int
+_dwarf_lineno_gen_program(Dwarf_P_Debug dbg, Dwarf_P_Section ds,
+ Dwarf_Rel_Section drs, Dwarf_Error * error)
+{
+ Dwarf_LineInfo li;
+ Dwarf_Line ln;
+ Dwarf_Unsigned address, file, line, spc;
+ Dwarf_Unsigned addr0, maddr;
+ Dwarf_Signed line0, column;
+ int is_stmt, basic_block;
+ int need_copy;
+ int ret;
+
+#define RESET_REGISTERS \
+ do { \
+ address = 0; \
+ file = 1; \
+ line = 1; \
+ column = 0; \
+ is_stmt = li->li_defstmt; \
+ basic_block = 0; \
+ } while(0)
+
+ li = dbg->dbgp_lineinfo;
+ maddr = (255 - li->li_opbase) / li->li_lrange;
+
+ RESET_REGISTERS;
+
+ STAILQ_FOREACH(ln, &li->li_lnlist, ln_next) {
+ if (ln->ln_symndx > 0) {
+ /*
+ * Generate DW_LNE_set_address extended op.
+ */
+ RCHECK(WRITE_VALUE(0, 1));
+ RCHECK(WRITE_ULEB128(dbg->dbg_pointer_size + 1));
+ RCHECK(WRITE_VALUE(DW_LNE_set_address, 1));
+ RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds,
+ dwarf_drt_data_reloc, dbg->dbg_pointer_size,
+ ds->ds_size, ln->ln_symndx, ln->ln_addr,
+ NULL, error));
+ address = ln->ln_addr;
+ continue;
+ } else if (ln->ln_endseq) {
+ addr0 = (ln->ln_addr - address) / li->li_minlen;
+ if (addr0 != 0) {
+ RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1));
+ RCHECK(WRITE_ULEB128(addr0));
+ }
+
+ /*
+ * Generate DW_LNE_end_sequence.
+ */
+ RCHECK(WRITE_VALUE(0, 1));
+ RCHECK(WRITE_ULEB128(1));
+ RCHECK(WRITE_VALUE(DW_LNE_end_sequence, 1));
+ RESET_REGISTERS;
+ continue;
+ }
+
+ /*
+ * Generate standard opcodes for file, column, is_stmt or
+ * basic_block changes.
+ */
+ if (ln->ln_fileno != file) {
+ RCHECK(WRITE_VALUE(DW_LNS_set_file, 1));
+ RCHECK(WRITE_ULEB128(ln->ln_fileno));
+ file = ln->ln_fileno;
+ }
+ if (ln->ln_column != column) {
+ RCHECK(WRITE_VALUE(DW_LNS_set_column, 1));
+ RCHECK(WRITE_ULEB128(ln->ln_column));
+ column = ln->ln_column;
+ }
+ if (ln->ln_stmt != is_stmt) {
+ RCHECK(WRITE_VALUE(DW_LNS_negate_stmt, 1));
+ is_stmt = ln->ln_stmt;
+ }
+ if (ln->ln_bblock && !basic_block) {
+ RCHECK(WRITE_VALUE(DW_LNS_set_basic_block, 1));
+ basic_block = 1;
+ }
+
+ /*
+ * Calculate address and line number change.
+ */
+ addr0 = (ln->ln_addr - address) / li->li_minlen;
+ line0 = ln->ln_lineno - line;
+
+ if (addr0 == 0 && line0 == 0)
+ continue;
+
+ /*
+ * Check if line delta is with the range and if the special
+ * opcode can be used.
+ */
+ assert(li->li_lbase <= 0);
+ if (line0 >= li->li_lbase &&
+ line0 <= li->li_lbase + li->li_lrange - 1) {
+ spc = (line0 - li->li_lbase) +
+ (li->li_lrange * addr0) + li->li_opbase;
+ if (spc <= 255) {
+ RCHECK(WRITE_VALUE(spc, 1));
+ basic_block = 0;
+ goto next_line;
+ }
+ }
+
+ /* Generate DW_LNS_advance_line for line number change. */
+ if (line0 != 0) {
+ RCHECK(WRITE_VALUE(DW_LNS_advance_line, 1));
+ RCHECK(WRITE_SLEB128(line0));
+ line0 = 0;
+ need_copy = 1;
+ } else
+ need_copy = basic_block;
+
+ if (addr0 != 0) {
+ /* See if it can be handled by DW_LNS_const_add_pc. */
+ spc = (line0 - li->li_lbase) +
+ (li->li_lrange * (addr0 - maddr)) + li->li_opbase;
+ if (addr0 >= maddr && spc <= 255) {
+ RCHECK(WRITE_VALUE(DW_LNS_const_add_pc, 1));
+ RCHECK(WRITE_VALUE(spc, 1));
+ } else {
+ /* Otherwise we use DW_LNS_advance_pc. */
+ RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1));
+ RCHECK(WRITE_ULEB128(addr0));
+ }
+ }
+
+ if (need_copy) {
+ RCHECK(WRITE_VALUE(DW_LNS_copy, 1));
+ basic_block = 0;
+ }
+
+ next_line:
+ address = ln->ln_addr;
+ line = ln->ln_lineno;
+ }
+
+ return (DW_DLE_NONE);
+
+gen_fail:
+ return (ret);
+
+#undef RESET_REGISTERS
+}
+
+static uint8_t
+_dwarf_get_minlen(Dwarf_P_Debug dbg)
+{
+
+ assert(dbg != NULL);
+
+ switch (dbg->dbgp_isa) {
+ case DW_ISA_ARM:
+ return (2);
+ case DW_ISA_X86:
+ case DW_ISA_X86_64:
+ return (1);
+ default:
+ return (4);
+ }
+}
+
+static uint8_t oplen[] = {0, 1, 1, 1, 1, 0, 0, 0, 1};
+
+int
+_dwarf_lineno_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
+{
+ Dwarf_LineInfo li;
+ Dwarf_LineFile lf;
+ Dwarf_P_Section ds;
+ Dwarf_Rel_Section drs;
+ Dwarf_Unsigned offset;
+ int i, ret;
+
+ assert(dbg != NULL && dbg->dbgp_lineinfo != NULL);
+
+ li = dbg->dbgp_lineinfo;
+ if (STAILQ_EMPTY(&li->li_lnlist))
+ return (DW_DLE_NONE);
+
+ li->li_length = 0;
+ li->li_version = 2;
+ li->li_hdrlen = 0;
+ li->li_minlen = _dwarf_get_minlen(dbg);
+ li->li_defstmt = 1;
+ li->li_lbase = -5;
+ li->li_lrange = 14;
+ li->li_opbase = 10;
+
+ /* Create .debug_line section. */
+ if ((ret = _dwarf_section_init(dbg, &ds, ".debug_line", 0, error)) !=
+ DW_DLE_NONE)
+ return (ret);
+
+ /* Create relocation section for .debug_line */
+ if ((ret = _dwarf_reloc_section_init(dbg, &drs, ds, error)) !=
+ DW_DLE_NONE)
+ goto gen_fail1;
+
+ /* Length placeholder. (We only use 32-bit DWARF format) */
+ RCHECK(WRITE_VALUE(0, 4));
+
+ /* Write line number dwarf version. (DWARF2) */
+ RCHECK(WRITE_VALUE(li->li_version, 2));
+
+ /* Header length placeholder. */
+ offset = ds->ds_size;
+ RCHECK(WRITE_VALUE(li->li_hdrlen, 4));
+
+ /* Write minimum instruction length. */
+ RCHECK(WRITE_VALUE(li->li_minlen, 1));
+
+ /*
+ * Write initial value for is_stmt. XXX Which default value we
+ * should use?
+ */
+ RCHECK(WRITE_VALUE(li->li_defstmt, 1));
+
+ /*
+ * Write line_base and line_range. FIXME These value needs to be
+ * fine tuned.
+ */
+ RCHECK(WRITE_VALUE(li->li_lbase, 1));
+ RCHECK(WRITE_VALUE(li->li_lrange, 1));
+
+ /* Write opcode_base. (DWARF2) */
+ RCHECK(WRITE_VALUE(li->li_opbase, 1));
+
+ /* Write standard op length array. */
+ RCHECK(WRITE_BLOCK(oplen, sizeof(oplen) / sizeof(oplen[0])));
+
+ /* Write the list of include directories. */
+ for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++)
+ RCHECK(WRITE_STRING(li->li_incdirs[i]));
+ RCHECK(WRITE_VALUE(0, 1));
+
+ /* Write the list of filenames. */
+ STAILQ_FOREACH(lf, &li->li_lflist, lf_next) {
+ RCHECK(WRITE_STRING(lf->lf_fname));
+ RCHECK(WRITE_ULEB128(lf->lf_dirndx));
+ RCHECK(WRITE_ULEB128(lf->lf_mtime));
+ RCHECK(WRITE_ULEB128(lf->lf_size));
+ }
+ RCHECK(WRITE_VALUE(0, 1));
+
+ /* Fill in the header length. */
+ li->li_hdrlen = ds->ds_size - offset - 4;
+ dbg->write(ds->ds_data, &offset, li->li_hdrlen, 4);
+
+ /* Generate the line number program. */
+ RCHECK(_dwarf_lineno_gen_program(dbg, ds, drs, error));
+
+ /* Fill in the length of this line info. */
+ li->li_length = ds->ds_size - 4;
+ offset = 0;
+ dbg->write(ds->ds_data, &offset, li->li_length, 4);
+
+ /* Notify the creation of .debug_line ELF section. */
+ RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
+
+ /* Finalize relocation section for .debug_line. */
+ RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error));
+
+ return (DW_DLE_NONE);
+
+gen_fail:
+ _dwarf_reloc_section_free(dbg, &drs);
+
+gen_fail1:
+ _dwarf_section_free(dbg, &ds);
+
+ return (ret);
+}
+
+void
+_dwarf_lineno_pro_cleanup(Dwarf_P_Debug dbg)
+{
+ Dwarf_LineInfo li;
+ Dwarf_LineFile lf, tlf;
+ Dwarf_Line ln, tln;
+ int i;
+
+ assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
+ if (dbg->dbgp_lineinfo == NULL)
+ return;
+
+ li = dbg->dbgp_lineinfo;
+ STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
+ STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile,
+ lf_next);
+ if (lf->lf_fname)
+ free(lf->lf_fname);
+ free(lf);
+ }
+ STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
+ STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next);
+ free(ln);
+ }
+ if (li->li_incdirs) {
+ for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++)
+ free(li->li_incdirs[i]);
+ free(li->li_incdirs);
+ }
+ free(li);
+ dbg->dbgp_lineinfo = NULL;
+}