2858 lines
112 KiB
C
Vendored
2858 lines
112 KiB
C
Vendored
/*
|
|
Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
|
|
Portions Copyright (C) 2007-2023 David Anderson. All Rights Reserved.
|
|
Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved.
|
|
Portions Copyright (C) 2015-2015 Google, Inc. 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.
|
|
|
|
*/
|
|
#include <stdio.h>
|
|
|
|
/* This is #included twice. Once for
|
|
libdwarf callers and one for dwarfdump which prints
|
|
the internals.
|
|
|
|
This way we have just one blob of code that reads
|
|
the table operations. */
|
|
|
|
static unsigned char
|
|
dwarf_standard_opcode_operand_count[
|
|
STANDARD_OPERAND_COUNT_TWO_LEVEL] = {
|
|
/* DWARF2 */
|
|
0,
|
|
1, 1, 1, 1,
|
|
0, 0, 0,
|
|
1,
|
|
/* Following are new for DWARF3. */
|
|
0, 0, 1,
|
|
/* Experimental opcodes. */
|
|
1, 2, 0,
|
|
};
|
|
|
|
/* We have a normal standard opcode base, but
|
|
an arm compiler emitted a non-standard table!
|
|
This could lead to problems...
|
|
ARM C/C++ Compiler, RVCT4.0 [Build 4
|
|
00] seems to get the table wrong . */
|
|
static unsigned char
|
|
dwarf_arm_standard_opcode_operand_count[
|
|
STANDARD_OPERAND_COUNT_DWARF3] = {
|
|
/* DWARF2 */
|
|
0,
|
|
1, 1, 1, 1,
|
|
0, 0, 0,
|
|
0, /* <<< --- this is wrong */
|
|
/* Following are new for DWARF3. */
|
|
0, 0, 1
|
|
};
|
|
|
|
/* Rather like memcmp but identifies which value pair
|
|
mismatches (the return value is non-zero if mismatch,
|
|
zero if match)..
|
|
This is used only in determining which kind of
|
|
standard-opcode-table we have in the DWARF: std-original,
|
|
or std-later.
|
|
mismatch_entry returns the table index that mismatches.
|
|
tabval returns the table byte value.
|
|
lineval returns the value from the line table header. */
|
|
static int
|
|
operandmismatch(unsigned char * table,unsigned table_length,
|
|
unsigned char *linetable,
|
|
unsigned check_count,
|
|
unsigned * mismatch_entry, unsigned * tabval,unsigned *lineval)
|
|
{
|
|
unsigned i = 0;
|
|
|
|
/* ASSERT: check_count is <= table_length, which
|
|
is guaranteed by the caller. */
|
|
for (i = 0; i<check_count; ++i) {
|
|
if (i >= table_length) {
|
|
*mismatch_entry = i;
|
|
*lineval = linetable[i];
|
|
*tabval = 0; /* No entry present. */
|
|
/* A kind of mismatch */
|
|
return TRUE;
|
|
}
|
|
if (table[i] == linetable[i]) {
|
|
continue;
|
|
}
|
|
*mismatch_entry = i;
|
|
*tabval = table[i];
|
|
*lineval = linetable[i];
|
|
return TRUE;
|
|
}
|
|
/* Matches. */
|
|
return FALSE;
|
|
}
|
|
|
|
/* Encapsulates DECODE_LEB128_UWORD_CK
|
|
so the caller can free resources
|
|
in case of problems. */
|
|
static int
|
|
read_uword_de(Dwarf_Small **lp,
|
|
Dwarf_Unsigned *out_p,
|
|
Dwarf_Debug dbg,
|
|
Dwarf_Error *err,
|
|
Dwarf_Small *lpend)
|
|
{
|
|
Dwarf_Small *inptr = *lp;
|
|
Dwarf_Unsigned out = 0;
|
|
DECODE_LEB128_UWORD_CK(inptr,
|
|
out,
|
|
dbg,err,lpend);
|
|
*lp = inptr;
|
|
*out_p = out;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* A bogus value read from a line table */
|
|
static void
|
|
IssueExpError(Dwarf_Debug dbg,
|
|
Dwarf_Error *err,
|
|
const char * msg,
|
|
Dwarf_Unsigned val)
|
|
{
|
|
dwarfstring m;
|
|
char buf[200];
|
|
|
|
dwarfstring_constructor_static(&m, buf,sizeof(buf));
|
|
dwarfstring_append(&m , "ERROR: ");
|
|
dwarfstring_append(&m ,(char *)msg);
|
|
dwarfstring_append_printf_u(&m , " Bad value: 0x%x", val);
|
|
_dwarf_error_string(dbg, err, DW_DLE_LINE_TABLE_BAD,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
}
|
|
|
|
static int
|
|
read_sword_de(Dwarf_Small **lp,
|
|
Dwarf_Signed *out_p,
|
|
Dwarf_Debug dbg,
|
|
Dwarf_Error *err,
|
|
Dwarf_Small *lpend)
|
|
{
|
|
Dwarf_Small *inptr = *lp;
|
|
Dwarf_Signed out = 0;
|
|
DECODE_LEB128_SWORD_CK(inptr,
|
|
out,
|
|
dbg,err,lpend);
|
|
*lp = inptr;
|
|
*out_p = out;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* Common line table header reading code.
|
|
Returns DW_DLV_OK, DW_DLV_ERROR.
|
|
DW_DLV_NO_ENTRY cannot be returned, but callers should
|
|
assume it is possible.
|
|
|
|
The line_context area must be initialized properly before
|
|
calling this.
|
|
|
|
Has the side effect of allocating arrays which
|
|
must be freed (see the Line_Table_Context which
|
|
holds the pointers to space we allocate here).
|
|
|
|
bogus_bytes_ptr and bogus_bytes are output values which
|
|
let a print-program notify the user of some surprising bytes
|
|
after a line table header and before the line table instructions.
|
|
These can be ignored unless one is printing.
|
|
And are ignored if NULL passed as the pointer.
|
|
|
|
err_count_out may be NULL, in which case we
|
|
make no attempt to count checking-type errors.
|
|
Checking-type errors do not stop us, we just report them.
|
|
|
|
See dw-linetableheader.txt for the ordering of text fields
|
|
across the various dwarf versions. The code
|
|
follows this ordering closely.
|
|
|
|
Some of the arguments remaining are in line_context
|
|
so can be deleted from the
|
|
argument list (after a close look for correctness). */
|
|
static int
|
|
_dwarf_read_line_table_header(Dwarf_Debug dbg,
|
|
Dwarf_CU_Context cu_context,
|
|
Dwarf_Small * section_start,
|
|
Dwarf_Small * data_start,
|
|
Dwarf_Unsigned section_length,
|
|
Dwarf_Small ** updated_data_start_out,
|
|
Dwarf_Line_Context line_context,
|
|
Dwarf_Small ** bogus_bytes_ptr,
|
|
Dwarf_Unsigned *bogus_bytes,
|
|
Dwarf_Error * err,
|
|
int *err_count_out)
|
|
{
|
|
Dwarf_Small *line_ptr = data_start;
|
|
Dwarf_Small *starting_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;
|
|
/* Both of the next two should point *one past*
|
|
the end of actual data of interest. */
|
|
Dwarf_Small *section_end = section_start + section_length;
|
|
Dwarf_Small *line_ptr_end = 0;
|
|
Dwarf_Small *lp_begin = 0;
|
|
int res = 0;
|
|
Dwarf_Unsigned htmp = 0;
|
|
|
|
if (bogus_bytes_ptr) *bogus_bytes_ptr = 0;
|
|
if (bogus_bytes) *bogus_bytes= 0;
|
|
|
|
line_context->lc_line_ptr_start = starting_line_ptr;
|
|
/* READ_AREA_LENGTH updates line_ptr for consumed bytes */
|
|
READ_AREA_LENGTH_CK(dbg, total_length, Dwarf_Unsigned,
|
|
line_ptr, local_length_size, local_extension_size,
|
|
err, section_length,section_end);
|
|
line_ptr_end = line_ptr + total_length;
|
|
line_context->lc_line_ptr_end = line_ptr_end;
|
|
line_context->lc_length_field_length = local_length_size +
|
|
local_extension_size;
|
|
line_context->lc_section_offset = starting_line_ptr -
|
|
dbg->de_debug_line.dss_data;
|
|
/* ASSERT: line_context->lc_length_field_length == line_ptr
|
|
-line_context->lc_line_ptr_start;
|
|
The following test allows the == case too
|
|
as that is normal for the last CUs line table. */
|
|
if (line_ptr_end > section_end) {
|
|
dwarfstring m;
|
|
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_u(&m,"DW_DLE_DEBUG_LINE_LENGTH_BAD "
|
|
" the total length of this line table is too large at"
|
|
" %" DW_PR_DUu " bytes",total_length);
|
|
_dwarf_error_string(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_total_length = total_length;
|
|
|
|
/* READ_UNALIGNED_CK(dbg, version, Dwarf_Half,
|
|
line_ptr, DWARF_HALF_SIZE,
|
|
err,line_ptr_end); */
|
|
res = _dwarf_read_unaligned_ck_wrapper(dbg,
|
|
&htmp,line_ptr,DWARF_HALF_SIZE,line_ptr_end,err);
|
|
if (res == DW_DLV_ERROR) {
|
|
return res;
|
|
}
|
|
version = htmp;
|
|
|
|
line_context->lc_version_number = version;
|
|
line_ptr += DWARF_HALF_SIZE;
|
|
if (version != DW_LINE_VERSION2 &&
|
|
version != DW_LINE_VERSION3 &&
|
|
version != DW_LINE_VERSION4 &&
|
|
version != DW_LINE_VERSION5 &&
|
|
version != EXPERIMENTAL_LINE_TABLES_VERSION) {
|
|
_dwarf_error(dbg, err, DW_DLE_VERSION_STAMP_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (version == DW_LINE_VERSION5) {
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_address_size = *(unsigned char *) line_ptr;
|
|
line_ptr = line_ptr + sizeof(Dwarf_Small);
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_segment_selector_size =
|
|
*(unsigned char *) line_ptr;
|
|
line_ptr = line_ptr + sizeof(Dwarf_Small);
|
|
} else {
|
|
line_context->lc_address_size = cu_context->cc_address_size;
|
|
line_context->lc_segment_selector_size =
|
|
cu_context->cc_segment_selector_size;
|
|
}
|
|
|
|
READ_UNALIGNED_CK(dbg, prologue_length, Dwarf_Unsigned,
|
|
line_ptr, local_length_size,
|
|
err,line_ptr_end);
|
|
if (prologue_length > total_length) {
|
|
dwarfstring m;
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_u(&m,
|
|
"DW_DLE_DEBUG_LINE_LENGTH_BAD "
|
|
" the prologue length of "
|
|
" this line table is too large at"
|
|
" %" DW_PR_DUu " bytes",prologue_length);
|
|
_dwarf_error_string(dbg, err,
|
|
DW_DLE_DEBUG_LINE_LENGTH_BAD,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_prologue_length = prologue_length;
|
|
line_ptr += local_length_size;
|
|
line_context->lc_line_prologue_start = line_ptr;
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_minimum_instruction_length =
|
|
*(unsigned char *) line_ptr;
|
|
line_ptr = line_ptr + sizeof(Dwarf_Small);
|
|
|
|
if (version == DW_LINE_VERSION4 ||
|
|
version == DW_LINE_VERSION5 ||
|
|
version == EXPERIMENTAL_LINE_TABLES_VERSION) {
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_maximum_ops_per_instruction =
|
|
*(unsigned char *) line_ptr;
|
|
line_ptr = line_ptr + sizeof(Dwarf_Small);
|
|
}
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_default_is_stmt = *(unsigned char *) line_ptr;
|
|
line_ptr = line_ptr + sizeof(Dwarf_Small);
|
|
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_line_base = *(signed char *) line_ptr;
|
|
line_ptr = line_ptr + sizeof(Dwarf_Sbyte);
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_line_range = *(unsigned char *) line_ptr;
|
|
if (!line_context->lc_line_range) {
|
|
_dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_RANGE_ZERO);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_ptr = line_ptr + sizeof(Dwarf_Small);
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_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. */
|
|
line_context->lc_opcode_length_table = line_ptr;
|
|
|
|
/* lc_opcode_base is one greater than the size of the array. */
|
|
line_ptr += line_context->lc_opcode_base - 1;
|
|
line_context->lc_std_op_count = line_context->lc_opcode_base -1;
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
{
|
|
/* Determine (as best we can) whether the
|
|
lc_opcode_length_table holds 9 or 12 standard-conforming
|
|
entries. gcc4 upped to DWARF3's 12 without updating the
|
|
version number.
|
|
EXPERIMENTAL_LINE_TABLES_VERSION upped to 15. */
|
|
unsigned check_count = line_context->lc_std_op_count;
|
|
unsigned tab_count =
|
|
sizeof(dwarf_standard_opcode_operand_count);
|
|
|
|
int operand_ck_fail = true;
|
|
if (line_context->lc_std_op_count > tab_count) {
|
|
_dwarf_print_header_issue(dbg,
|
|
"Too many standard operands in linetable header: ",
|
|
data_start,
|
|
line_context->lc_std_op_count,
|
|
0,0,0,
|
|
err_count_out);
|
|
check_count = tab_count;
|
|
}
|
|
if ((line_context->lc_opcode_length_table + check_count) >=
|
|
section_end) {
|
|
_dwarf_error_string(dbg, err,
|
|
DW_DLE_LINE_NUM_OPERANDS_BAD,
|
|
"DW_DLE_LINE_NUM_OPERANDS_BAD: "
|
|
"The .debug_line section is too short to be real "
|
|
"as a standard opcode table does not fit");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
{
|
|
unsigned entrynum = 0;
|
|
unsigned tabv = 0;
|
|
unsigned linetabv = 0;
|
|
|
|
int mismatch = operandmismatch(
|
|
dwarf_standard_opcode_operand_count,
|
|
tab_count,
|
|
line_context->lc_opcode_length_table,
|
|
check_count,&entrynum,&tabv,&linetabv);
|
|
if (mismatch) {
|
|
if (err_count_out) {
|
|
_dwarf_print_header_issue(dbg,
|
|
"standard-operands did not match, checked",
|
|
data_start,
|
|
check_count,
|
|
entrynum,tabv,linetabv,err_count_out);
|
|
}
|
|
if (check_count >
|
|
sizeof(dwarf_arm_standard_opcode_operand_count)) {
|
|
check_count =
|
|
sizeof(
|
|
dwarf_arm_standard_opcode_operand_count);
|
|
}
|
|
mismatch = operandmismatch(
|
|
dwarf_arm_standard_opcode_operand_count,
|
|
sizeof(dwarf_arm_standard_opcode_operand_count),
|
|
line_context->lc_opcode_length_table,
|
|
check_count,&entrynum,&tabv,&linetabv);
|
|
if (!mismatch && err_count_out) {
|
|
_dwarf_print_header_issue(dbg,
|
|
"arm (incorrect) operands in use: ",
|
|
data_start,
|
|
check_count,
|
|
entrynum,tabv,linetabv,err_count_out);
|
|
}
|
|
}
|
|
if (!mismatch) {
|
|
if (version == 2) {
|
|
if (line_context->lc_std_op_count ==
|
|
STANDARD_OPERAND_COUNT_DWARF3) {
|
|
_dwarf_print_header_issue(dbg,
|
|
"standard DWARF3 operands matched,"
|
|
" but is DWARF2 linetable: count",
|
|
data_start,
|
|
check_count,
|
|
0,0,0, err_count_out);
|
|
}
|
|
}
|
|
operand_ck_fail = false;
|
|
}
|
|
}
|
|
if (operand_ck_fail) {
|
|
/* Here we are not sure what the lc_std_op_count is. */
|
|
_dwarf_error_string(dbg, err,
|
|
DW_DLE_LINE_NUM_OPERANDS_BAD,
|
|
"DW_DLE_LINE_NUM_OPERANDS_BAD "
|
|
"we cannot determine the size of the standard opcode"
|
|
" table in the line table header");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
/* At this point we no longer need to check operand counts. */
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error_string(dbg, err, DW_DLE_LINE_OFFSET_BAD,
|
|
"DW_DLE_LINE_OFFSET_BAD "
|
|
"we run off the end of the .debug_line section "
|
|
"reading a line table header");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
if (version < DW_LINE_VERSION5){
|
|
Dwarf_Unsigned directories_count = 0;
|
|
Dwarf_Unsigned directories_malloc = 5;
|
|
line_context->lc_include_directories =
|
|
malloc(sizeof(Dwarf_Small *) * directories_malloc);
|
|
if (line_context->lc_include_directories == NULL) {
|
|
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
memset(line_context->lc_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(line_context->lc_include_directories,
|
|
bytesalloc);
|
|
|
|
if (!newdirs) {
|
|
_dwarf_error_string(dbg, err, DW_DLE_ALLOC_FAIL,
|
|
"DW_DLE_ALLOC_FAIL "
|
|
"reallocating an array of include directories"
|
|
" in a line table");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* Doubled size, zero out second half. */
|
|
memset(newdirs + directories_malloc, 0,
|
|
sizeof(Dwarf_Small *) * directories_malloc);
|
|
directories_malloc = expand;
|
|
line_context->lc_include_directories = newdirs;
|
|
}
|
|
line_context->lc_include_directories[directories_count] =
|
|
line_ptr;
|
|
res = _dwarf_check_string_valid(dbg,
|
|
data_start,line_ptr,line_ptr_end,
|
|
DW_DLE_LINE_STRING_BAD,err);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
|
|
directories_count++;
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err,
|
|
DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
line_ptr++;
|
|
line_context->lc_include_directories_count =
|
|
directories_count;
|
|
} else if (version == EXPERIMENTAL_LINE_TABLES_VERSION) {
|
|
/* Empty old style dir entry list. */
|
|
line_ptr++;
|
|
} else if (version == DW_LINE_VERSION5) {
|
|
/* handled below */
|
|
} else {
|
|
/* No old style directory entries. */
|
|
}
|
|
/* Later tests will deal with the == case as required. */
|
|
if (line_ptr > line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (version < DW_LINE_VERSION5) {
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
while (*(char *) line_ptr != '\0') {
|
|
Dwarf_Unsigned utmp;
|
|
Dwarf_Unsigned dir_index = 0;
|
|
Dwarf_Unsigned lastmod = 0;
|
|
Dwarf_Unsigned file_length = 0;
|
|
int resl = 0;
|
|
Dwarf_File_Entry currfile = 0;
|
|
|
|
currfile = (Dwarf_File_Entry)
|
|
malloc(sizeof(struct Dwarf_File_Entry_s));
|
|
if (currfile == NULL) {
|
|
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
memset(currfile,0,sizeof(struct Dwarf_File_Entry_s));
|
|
/* Insert early so in case of error we can find
|
|
and free the record. */
|
|
_dwarf_add_to_files_list(line_context,currfile);
|
|
|
|
currfile->fi_file_name = line_ptr;
|
|
resl = _dwarf_check_string_valid(dbg,
|
|
data_start,line_ptr,line_ptr_end,
|
|
DW_DLE_LINE_STRING_BAD,err);
|
|
if (resl != DW_DLV_OK) {
|
|
return resl;
|
|
}
|
|
line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
|
|
/* DECODE_LEB128_UWORD_CK(line_ptr, utmp,dbg,
|
|
err,line_ptr_end); */
|
|
res = read_uword_de(&line_ptr,&utmp,
|
|
dbg,err,line_ptr_end);
|
|
if (res == DW_DLV_ERROR) {
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dir_index = (Dwarf_Unsigned) utmp;
|
|
if (dir_index >
|
|
line_context->lc_include_directories_count) {
|
|
_dwarf_error(dbg, err, DW_DLE_DIR_INDEX_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
currfile->fi_dir_index = dir_index;
|
|
currfile->fi_dir_index_present = TRUE;
|
|
|
|
/*DECODE_LEB128_UWORD_CK(line_ptr,lastmod,
|
|
dbg,err, line_ptr_end); */
|
|
res = read_uword_de( &line_ptr,&lastmod,
|
|
dbg,err,line_ptr_end);
|
|
if (res == DW_DLV_ERROR) {
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
currfile->fi_time_last_mod = lastmod;
|
|
currfile->fi_time_last_mod_present = TRUE;
|
|
|
|
DECODE_LEB128_UWORD_CK(line_ptr,file_length,
|
|
dbg,err, line_ptr_end);
|
|
currfile->fi_file_length = file_length;
|
|
currfile->fi_file_length_present = TRUE;
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err,
|
|
DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
/* Skip trailing nul byte */
|
|
++line_ptr;
|
|
} else if (version == EXPERIMENTAL_LINE_TABLES_VERSION) {
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (*line_ptr != 0) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_ptr++;
|
|
} else if (version == 5) {
|
|
/* handled below */
|
|
} else {
|
|
/* No old style filenames entries. */
|
|
}
|
|
/* Later tests will deal with the == case as required. */
|
|
if (line_ptr > line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
if (version == EXPERIMENTAL_LINE_TABLES_VERSION) {
|
|
static unsigned char expbytes[5] = {0,0xff,0xff,0x7f, 0x7f };
|
|
Dwarf_Unsigned logicals_table_offset = 0;
|
|
Dwarf_Unsigned actuals_table_offset = 0;
|
|
unsigned i = 0;
|
|
|
|
for ( ; i < 5; ++i) {
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err,
|
|
DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (*line_ptr != expbytes[i]) {
|
|
_dwarf_error(dbg, err,
|
|
DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_ptr++;
|
|
}
|
|
READ_UNALIGNED_CK(dbg, logicals_table_offset, Dwarf_Unsigned,
|
|
line_ptr, local_length_size,err,line_ptr_end);
|
|
line_context->lc_logicals_table_offset =
|
|
logicals_table_offset;
|
|
line_ptr += local_length_size;
|
|
READ_UNALIGNED_CK(dbg, actuals_table_offset, Dwarf_Unsigned,
|
|
line_ptr, local_length_size,err,line_ptr_end);
|
|
line_context->lc_actuals_table_offset = actuals_table_offset;
|
|
line_ptr += local_length_size;
|
|
/* Later tests will deal with the == case as required. */
|
|
if (line_ptr > line_ptr_end) {
|
|
_dwarf_error_string(dbg, err, DW_DLE_LINE_OFFSET_BAD,
|
|
"DW_DLE_LINE_OFFSET_BAD "
|
|
"The line table pointer points past end "
|
|
"of line table.");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (actuals_table_offset > dbg->de_filesize) {
|
|
_dwarf_error_string(dbg, err, DW_DLE_LINE_OFFSET_BAD,
|
|
"DW_DLE_LINE_OFFSET_BAD "
|
|
"The line table actuals offset is larger than "
|
|
" the size of the object file. Corrupt DWARF");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if ((line_ptr+actuals_table_offset) > line_ptr_end) {
|
|
_dwarf_error_string(dbg, err, DW_DLE_LINE_OFFSET_BAD,
|
|
"DW_DLE_LINE_OFFSET_BAD "
|
|
"The line table actuals offset is too large "
|
|
"to be real.");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
|
|
if (version == DW_LINE_VERSION5 ||
|
|
version == EXPERIMENTAL_LINE_TABLES_VERSION) {
|
|
/* DWARF 5. directory names.*/
|
|
Dwarf_Unsigned directory_format_count = 0;
|
|
struct Dwarf_Unsigned_Pair_s * format_values = 0;
|
|
Dwarf_Unsigned directories_count = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
Dwarf_Unsigned j = 0;
|
|
int dres = 0;
|
|
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
directory_format_count = *(unsigned char *) line_ptr;
|
|
line_context->lc_directory_entry_format_count =
|
|
directory_format_count;
|
|
line_ptr = line_ptr + sizeof(Dwarf_Small);
|
|
if (directory_format_count > 0) {
|
|
format_values = malloc(
|
|
sizeof(struct Dwarf_Unsigned_Pair_s) *
|
|
directory_format_count);
|
|
if (format_values == NULL) {
|
|
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
for (i = 0; i < directory_format_count; i++) {
|
|
dres=read_uword_de(&line_ptr,
|
|
&format_values[i].up_first,
|
|
dbg,err,line_ptr_end);
|
|
if (dres != DW_DLV_OK) {
|
|
free(format_values);
|
|
format_values = 0;
|
|
return dres;
|
|
}
|
|
dres=read_uword_de(&line_ptr,
|
|
&format_values[i].up_second,
|
|
dbg,err,line_ptr_end);
|
|
if (dres != DW_DLV_OK) {
|
|
free(format_values);
|
|
format_values = 0;
|
|
return dres;
|
|
}
|
|
/* FIXME: what would be appropriate tests
|
|
of this pair of values? */
|
|
}
|
|
}
|
|
dres = read_uword_de(&line_ptr,&directories_count,
|
|
dbg,err,line_ptr_end);
|
|
if (dres != DW_DLV_OK) {
|
|
free(format_values);
|
|
format_values = 0;
|
|
return dres;
|
|
}
|
|
if (directories_count > total_length) {
|
|
dwarfstring m;
|
|
|
|
free(format_values);
|
|
format_values = 0;
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_u(&m,
|
|
"DW_DLE_DEBUG_LINE_LENGTH_BAD "
|
|
" the directories count of "
|
|
" this line table is too large at"
|
|
" %" DW_PR_DUu ,directories_count);
|
|
_dwarf_error_string(dbg, err,
|
|
DW_DLE_DEBUG_LINE_LENGTH_BAD,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_include_directories =
|
|
malloc(sizeof(Dwarf_Small *) * directories_count);
|
|
if (line_context->lc_include_directories == NULL) {
|
|
free(format_values);
|
|
format_values = 0;
|
|
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (directory_format_count == 0 &&
|
|
directories_count > 0) {
|
|
free(format_values);
|
|
format_values = 0;
|
|
_dwarf_error_string(dbg, err,
|
|
DW_DLE_DIRECTORY_FORMAT_COUNT_VS_DIRECTORIES_MISMATCH,
|
|
"DW_DLE_DIRECTORY_FORMAT_COUNT_"
|
|
"VS_DIRECTORIES_MISMATCH"
|
|
": format count is zero yet directories count > 0");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
memset(line_context->lc_include_directories, 0,
|
|
sizeof(Dwarf_Small *) * directories_count);
|
|
|
|
for (i = 0; i < directories_count; i++) {
|
|
for (j = 0; j < directory_format_count; j++) {
|
|
Dwarf_Unsigned lntype =
|
|
format_values[j].up_first;
|
|
Dwarf_Unsigned lnform =
|
|
format_values[j].up_second;
|
|
switch (lntype) {
|
|
case DW_LNCT_path: {
|
|
char *inc_dir_ptr = 0;
|
|
res = _dwarf_decode_line_string_form(dbg,
|
|
lntype,lnform,
|
|
local_length_size,
|
|
&line_ptr,
|
|
line_ptr_end,
|
|
&inc_dir_ptr,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(format_values);
|
|
format_values = 0;
|
|
return res;
|
|
}
|
|
line_context->lc_include_directories[i] =
|
|
(unsigned char *)inc_dir_ptr;
|
|
break;
|
|
}
|
|
default:
|
|
free(format_values);
|
|
format_values = 0;
|
|
_dwarf_error(dbg, err,
|
|
DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
/* Later tests will deal with the == case as required. */
|
|
if (line_ptr > line_ptr_end) {
|
|
free(format_values);
|
|
format_values = 0;
|
|
_dwarf_error(dbg, err,
|
|
DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
line_context->lc_directory_format_values =
|
|
format_values;
|
|
format_values = 0;
|
|
line_context->lc_include_directories_count =
|
|
directories_count;
|
|
}
|
|
if (version == DW_LINE_VERSION5 ||
|
|
version == EXPERIMENTAL_LINE_TABLES_VERSION) {
|
|
/* DWARF 5. file names.*/
|
|
struct Dwarf_Unsigned_Pair_s *
|
|
filename_entry_pairs = 0;
|
|
Dwarf_Unsigned filename_format_count = 0;
|
|
Dwarf_Unsigned files_count = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
Dwarf_Unsigned j = 0;
|
|
int dres = 0;
|
|
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err,
|
|
DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
filename_format_count = *(unsigned char *) line_ptr;
|
|
line_context->lc_file_name_format_count =
|
|
filename_format_count;
|
|
line_ptr = line_ptr + sizeof(Dwarf_Small);
|
|
filename_entry_pairs = malloc(
|
|
sizeof(struct Dwarf_Unsigned_Pair_s) *
|
|
filename_format_count);
|
|
if (!filename_entry_pairs) {
|
|
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
for (i = 0; i < filename_format_count; i++) {
|
|
dres=read_uword_de(&line_ptr,
|
|
&filename_entry_pairs[i].up_first,
|
|
dbg,err,line_ptr_end);
|
|
if (dres != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return dres;
|
|
}
|
|
dres=read_uword_de(&line_ptr,
|
|
&filename_entry_pairs[i].
|
|
up_second, dbg,err,line_ptr_end);
|
|
if (dres != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return dres;
|
|
}
|
|
/* FIXME: what would be appropriate tests
|
|
of this pair of values? */
|
|
}
|
|
/* DECODE_LEB128_UWORD_CK(line_ptr, files_count,
|
|
dbg,err,line_ptr_end); */
|
|
dres=read_uword_de(&line_ptr,&files_count,
|
|
dbg,err,line_ptr_end);
|
|
if (dres != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return dres;
|
|
}
|
|
if (files_count > total_length) {
|
|
dwarfstring m;
|
|
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_u(&m,
|
|
"DW_DLE_DEBUG_LINE_LENGTH_BAD "
|
|
" the files count of "
|
|
" this line table is too large at"
|
|
" %" DW_PR_DUu " files",files_count);
|
|
_dwarf_error_string(dbg, err,
|
|
DW_DLE_DEBUG_LINE_LENGTH_BAD,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
free(filename_entry_pairs);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
for (i = 0; i < files_count; i++) {
|
|
Dwarf_File_Entry curline = 0;
|
|
curline = (Dwarf_File_Entry)
|
|
malloc(sizeof(struct Dwarf_File_Entry_s));
|
|
if (curline == NULL) {
|
|
free(filename_entry_pairs);
|
|
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
memset(curline,0,sizeof(*curline));
|
|
_dwarf_add_to_files_list(line_context,curline);
|
|
for (j = 0; j < filename_format_count; j++) {
|
|
Dwarf_Unsigned dirindex = 0;
|
|
Dwarf_Unsigned lntype =
|
|
filename_entry_pairs[j].up_first;
|
|
Dwarf_Unsigned lnform =
|
|
filename_entry_pairs[j].up_second;
|
|
switch (lntype) {
|
|
/* The LLVM LNCT is documented in
|
|
https://releases.llvm.org/9.0.0/docs
|
|
/AMDGPUUsage.html
|
|
*/
|
|
|
|
/* Cannot find the GNU items documented.? */
|
|
case DW_LNCT_GNU_decl_file: /* FORM udata*/
|
|
res = _dwarf_decode_line_udata_form(dbg,
|
|
lntype,lnform,
|
|
&line_ptr,
|
|
&dirindex,
|
|
line_ptr_end,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return res;
|
|
}
|
|
curline->fi_gnu_decl_file = dirindex;
|
|
curline->fi_gnu_decl_file_present = TRUE;
|
|
break;
|
|
case DW_LNCT_GNU_decl_line: /* FORM udata */
|
|
res = _dwarf_decode_line_udata_form(dbg,
|
|
lntype,lnform,
|
|
&line_ptr,
|
|
&dirindex,
|
|
line_ptr_end,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return res;
|
|
}
|
|
curline->fi_gnu_decl_line = dirindex;
|
|
curline->fi_gnu_decl_line_present = TRUE;
|
|
break;
|
|
|
|
case DW_LNCT_path: {
|
|
res = _dwarf_decode_line_string_form(dbg,
|
|
lntype, lnform,
|
|
local_length_size,
|
|
&line_ptr,
|
|
line_ptr_end,
|
|
(char **)&curline->fi_file_name,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return res;
|
|
}
|
|
}
|
|
break;
|
|
case DW_LNCT_GNU_subprogram_name: {
|
|
res = _dwarf_decode_line_string_form(dbg,
|
|
lntype, lnform,
|
|
local_length_size,
|
|
&line_ptr,
|
|
line_ptr_end,
|
|
(char **)&curline->fi_gnu_subprogram_name,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return res;
|
|
}
|
|
}
|
|
break;
|
|
case DW_LNCT_LLVM_source: {
|
|
res = _dwarf_decode_line_string_form(dbg,
|
|
lntype, lnform,
|
|
local_length_size,
|
|
&line_ptr,
|
|
line_ptr_end,
|
|
(char **)&curline->fi_llvm_source,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return res;
|
|
}
|
|
}
|
|
break;
|
|
case DW_LNCT_directory_index:
|
|
res = _dwarf_decode_line_udata_form(dbg,
|
|
lntype,lnform,
|
|
&line_ptr,
|
|
&dirindex,
|
|
line_ptr_end,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return res;
|
|
}
|
|
curline->fi_dir_index = dirindex;
|
|
curline->fi_dir_index_present = TRUE;
|
|
break;
|
|
case DW_LNCT_timestamp:
|
|
res = _dwarf_decode_line_udata_form(dbg,
|
|
lntype, lnform,
|
|
&line_ptr,
|
|
&curline->fi_time_last_mod,
|
|
line_ptr_end,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return res;
|
|
}
|
|
curline->fi_time_last_mod_present = TRUE;
|
|
break;
|
|
case DW_LNCT_size:
|
|
res = _dwarf_decode_line_udata_form(dbg,
|
|
lntype, lnform,
|
|
&line_ptr,
|
|
&curline->fi_file_length,
|
|
line_ptr_end,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return res;
|
|
}
|
|
curline->fi_file_length_present = TRUE;
|
|
break;
|
|
case DW_LNCT_MD5: { /* form DW_FORM_data16 */
|
|
if (filename_entry_pairs[j].up_second !=
|
|
DW_FORM_data16) {
|
|
free(filename_entry_pairs);
|
|
_dwarf_error(dbg, err,
|
|
DW_DLE_LNCT_MD5_WRONG_FORM);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = _dwarf_extract_data16(dbg,
|
|
line_ptr,
|
|
line_ptr,
|
|
line_ptr_end,
|
|
&curline->fi_md5_value,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(filename_entry_pairs);
|
|
return res;
|
|
}
|
|
curline->fi_md5_present = TRUE;
|
|
line_ptr = line_ptr +
|
|
sizeof(curline->fi_md5_value);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
_dwarf_report_bad_lnct(dbg,
|
|
lntype,
|
|
DW_DLE_LINE_NUMBER_HEADER_ERROR,
|
|
"DW_DLE_LINE_NUMBER_HEADER_ERROR",
|
|
err);
|
|
free(filename_entry_pairs);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (line_ptr > line_ptr_end) {
|
|
free(filename_entry_pairs);
|
|
_dwarf_error(dbg, err,
|
|
DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
}
|
|
line_context->lc_file_format_values = filename_entry_pairs;
|
|
filename_entry_pairs = 0;
|
|
}
|
|
/* For two-level line tables, read the
|
|
subprograms table. */
|
|
if (version == EXPERIMENTAL_LINE_TABLES_VERSION) {
|
|
Dwarf_Unsigned subprog_format_count = 0;
|
|
Dwarf_Unsigned *subprog_entry_types = 0;
|
|
Dwarf_Unsigned *subprog_entry_forms = 0;
|
|
Dwarf_Unsigned subprogs_count = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
Dwarf_Unsigned j = 0;
|
|
int dres = 0;
|
|
|
|
/* line_ptr_end is *after* the valid area */
|
|
if (line_ptr >= line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
subprog_format_count = *(unsigned char *) line_ptr;
|
|
line_ptr = line_ptr + sizeof(Dwarf_Small);
|
|
subprog_entry_types = malloc(sizeof(Dwarf_Unsigned) *
|
|
subprog_format_count);
|
|
if (subprog_entry_types == NULL) {
|
|
_dwarf_error_string(dbg, err, DW_DLE_ALLOC_FAIL,
|
|
"DW_DLE_ALLOC_FAIL allocating subprog_entry_types");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (subprog_format_count > total_length) {
|
|
IssueExpError(dbg,err,
|
|
"Subprog format count Count too "
|
|
"large to be real",
|
|
subprog_format_count);
|
|
free(subprog_entry_types);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
subprog_entry_forms = malloc(sizeof(Dwarf_Unsigned) *
|
|
subprog_format_count);
|
|
if (subprog_entry_forms == NULL) {
|
|
free(subprog_entry_types);
|
|
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
|
|
_dwarf_error_string(dbg, err, DW_DLE_ALLOC_FAIL,
|
|
"DW_DLE_ALLOC_FAIL allocating subprog_entry_forms");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
for (i = 0; i < subprog_format_count; i++) {
|
|
|
|
dres=read_uword_de(&line_ptr,subprog_entry_types+i,
|
|
dbg,err,line_ptr_end);
|
|
if (dres != DW_DLV_OK) {
|
|
free(subprog_entry_types);
|
|
free(subprog_entry_forms);
|
|
return dres;
|
|
}
|
|
if (subprog_entry_types[i] > total_length) {
|
|
IssueExpError(dbg,err,
|
|
"Subprog entry_types[i] count Count too "
|
|
"large to be real",
|
|
subprog_entry_types[i]);
|
|
free(subprog_entry_types);
|
|
free(subprog_entry_forms);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dres=read_uword_de(&line_ptr,subprog_entry_forms+i,
|
|
dbg,err,line_ptr_end);
|
|
if (dres != DW_DLV_OK) {
|
|
free(subprog_entry_types);
|
|
free(subprog_entry_forms);
|
|
return dres;
|
|
}
|
|
if (subprog_entry_forms[i] > total_length) {
|
|
IssueExpError(dbg,err,
|
|
"Subprog entry_forms[i] count Count too "
|
|
"large to be real",
|
|
subprog_entry_forms[i]);
|
|
free(subprog_entry_types);
|
|
free(subprog_entry_forms);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
dres=read_uword_de(&line_ptr,&subprogs_count,
|
|
dbg,err,line_ptr_end);
|
|
if (dres != DW_DLV_OK) {
|
|
free(subprog_entry_types);
|
|
free(subprog_entry_forms);
|
|
return dres;
|
|
}
|
|
if (subprogs_count > total_length) {
|
|
IssueExpError(dbg,err,
|
|
"Subprogs Count too large to be real",
|
|
subprogs_count);
|
|
free(subprog_entry_types);
|
|
free(subprog_entry_forms);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
line_context->lc_subprogs =
|
|
malloc(sizeof(struct Dwarf_Subprog_Entry_s) *
|
|
subprogs_count);
|
|
if (line_context->lc_subprogs == NULL) {
|
|
free(subprog_entry_types);
|
|
free(subprog_entry_forms);
|
|
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
memset(line_context->lc_subprogs, 0,
|
|
sizeof(struct Dwarf_Subprog_Entry_s) * subprogs_count);
|
|
for (i = 0; i < subprogs_count; i++) {
|
|
struct Dwarf_Subprog_Entry_s *curline =
|
|
line_context->lc_subprogs + i;
|
|
for (j = 0; j < subprog_format_count; j++) {
|
|
Dwarf_Unsigned lntype =
|
|
subprog_entry_types[j];
|
|
Dwarf_Unsigned lnform =
|
|
subprog_entry_forms[j];
|
|
switch (lntype) {
|
|
case DW_LNCT_GNU_subprogram_name:
|
|
res = _dwarf_decode_line_string_form(dbg,
|
|
lntype,lnform,
|
|
local_length_size,
|
|
&line_ptr,
|
|
line_ptr_end,
|
|
(char **)&curline->ds_subprog_name,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(subprog_entry_types);
|
|
free(subprog_entry_forms);
|
|
return res;
|
|
}
|
|
break;
|
|
case DW_LNCT_GNU_decl_file:
|
|
res = _dwarf_decode_line_udata_form(dbg,
|
|
lntype,lnform,
|
|
&line_ptr,
|
|
&curline->ds_decl_file,
|
|
line_ptr_end,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(subprog_entry_forms);
|
|
free(subprog_entry_types);
|
|
return res;
|
|
}
|
|
break;
|
|
case DW_LNCT_GNU_decl_line:
|
|
res = _dwarf_decode_line_udata_form(dbg,
|
|
lntype,lnform,
|
|
&line_ptr,
|
|
&curline->ds_decl_line,
|
|
line_ptr_end,
|
|
err);
|
|
if (res != DW_DLV_OK) {
|
|
free(subprog_entry_forms);
|
|
free(subprog_entry_types);
|
|
return res;
|
|
}
|
|
break;
|
|
default:
|
|
free(subprog_entry_forms);
|
|
free(subprog_entry_types);
|
|
_dwarf_report_bad_lnct(dbg,
|
|
lntype,
|
|
DW_DLE_LINE_NUMBER_HEADER_ERROR,
|
|
"DW_DLE_LINE_NUMBER_HEADER_ERROR",
|
|
err);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (line_ptr >= line_ptr_end) {
|
|
free(subprog_entry_types);
|
|
free(subprog_entry_forms);
|
|
_dwarf_error_string(dbg, err,
|
|
DW_DLE_LINE_NUMBER_HEADER_ERROR,
|
|
"DW_DLE_LINE_NUMBER_HEADER_ERROR:"
|
|
" Reading suprogram entry DW_LNCT* types "
|
|
" we run off the end of the table");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
free(subprog_entry_types);
|
|
free(subprog_entry_forms);
|
|
line_context->lc_subprogs_count = subprogs_count;
|
|
}
|
|
if (version == EXPERIMENTAL_LINE_TABLES_VERSION) {
|
|
lp_begin = line_context->lc_line_prologue_start +
|
|
line_context->lc_logicals_table_offset;
|
|
} else {
|
|
lp_begin = line_context->lc_line_prologue_start +
|
|
line_context->lc_prologue_length;
|
|
}
|
|
if (line_ptr > line_ptr_end) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (line_ptr != lp_begin) {
|
|
if (line_ptr > lp_begin) {
|
|
_dwarf_error(dbg, err, DW_DLE_LINE_PROLOG_LENGTH_BAD);
|
|
return DW_DLV_ERROR;
|
|
} else {
|
|
/* Bug in compiler. These
|
|
bytes are really part of the instruction
|
|
stream. The line_context->lc_prologue_length is
|
|
wrong (12 too high). */
|
|
if (bogus_bytes_ptr) {
|
|
*bogus_bytes_ptr = line_ptr;
|
|
}
|
|
if (bogus_bytes) {
|
|
/* How far off things are. We expect the
|
|
value 12 ! Negative value seems impossible. */
|
|
/* ptrdiff_t is generated but not named */
|
|
*bogus_bytes = (lp_begin - line_ptr);
|
|
}
|
|
}
|
|
/* Ignore the lp_begin calc. Assume line_ptr right.
|
|
Making up for compiler bug. */
|
|
lp_begin = line_ptr;
|
|
}
|
|
line_context->lc_line_ptr_start = lp_begin;
|
|
if (line_context->lc_actuals_table_offset) {
|
|
/* This means two tables. */
|
|
line_context->lc_table_count = 2;
|
|
} else {
|
|
if (line_context->lc_line_ptr_end > lp_begin) {
|
|
line_context->lc_table_count = 1;
|
|
} else {
|
|
line_context->lc_table_count = 0;
|
|
}
|
|
}
|
|
*updated_data_start_out = lp_begin;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* Read one line table program. For two-level line tables, this
|
|
function is called once for each table. */
|
|
static int
|
|
read_line_table_program(Dwarf_Debug dbg,
|
|
Dwarf_Small *line_ptr,
|
|
Dwarf_Small *line_ptr_end,
|
|
Dwarf_Small *orig_line_ptr,
|
|
Dwarf_Small *section_start,
|
|
Dwarf_Line_Context line_context,
|
|
Dwarf_Half address_size,
|
|
Dwarf_Bool doaddrs, /* Only true if SGI IRIX rqs calling. */
|
|
Dwarf_Bool dolines,
|
|
Dwarf_Bool is_single_table,
|
|
Dwarf_Bool is_actuals_table,
|
|
Dwarf_Error *error,
|
|
int *err_count_out)
|
|
{
|
|
Dwarf_Unsigned i = 0;
|
|
Dwarf_File_Entry cur_file_entry = 0;
|
|
Dwarf_Line *logicals = line_context->lc_linebuf_logicals;
|
|
Dwarf_Unsigned logicals_count =
|
|
line_context->lc_linecount_logicals;
|
|
|
|
struct Dwarf_Line_Registers_s regs;
|
|
|
|
/* 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_Unsigned leb128_num = 0;
|
|
Dwarf_Signed 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_Unsigned line_count = 0;
|
|
|
|
/* This is the length of an extended opcode instr. */
|
|
Dwarf_Unsigned instr_length = 0;
|
|
|
|
/* 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;
|
|
|
|
/* Mark a line record as being DW_LNS_set_address */
|
|
Dwarf_Bool is_addr_set = false;
|
|
|
|
(void)orig_line_ptr;
|
|
(void)err_count_out;
|
|
/* Initialize the one state machine variable that depends on the
|
|
prefix. */
|
|
_dwarf_set_line_table_regs_default_values(®s,
|
|
line_context->lc_version_number,
|
|
line_context->lc_default_is_stmt);
|
|
|
|
/* Start of statement program. */
|
|
while (line_ptr < line_ptr_end) {
|
|
int type = 0;
|
|
Dwarf_Small opcode = 0;
|
|
|
|
#ifdef PRINTING_DETAILS
|
|
{
|
|
dwarfstring m9a;
|
|
dwarfstring_constructor(&m9a);
|
|
dwarfstring_append_printf_u(&m9a,
|
|
" [0x%06" DW_PR_DSx "] ",
|
|
/* ptrdiff_t generated but not named */
|
|
(line_ptr - section_start));
|
|
_dwarf_printf(dbg,dwarfstring_string(&m9a));
|
|
dwarfstring_destructor(&m9a);
|
|
}
|
|
#endif /* PRINTING_DETAILS */
|
|
opcode = *(Dwarf_Small *) line_ptr;
|
|
line_ptr++;
|
|
/* 'type' is the output */
|
|
WHAT_IS_OPCODE(type, opcode, line_context->lc_opcode_base,
|
|
line_context->lc_opcode_length_table, line_ptr,
|
|
line_context->lc_std_op_count);
|
|
|
|
if (type == LOP_DISCARD) {
|
|
int oc = 0;
|
|
int opcnt = line_context->lc_opcode_length_table[opcode];
|
|
#ifdef PRINTING_DETAILS
|
|
{
|
|
dwarfstring m9b;
|
|
dwarfstring_constructor(&m9b);
|
|
dwarfstring_append_printf_i(&m9b,
|
|
"*** DWARF CHECK: DISCARD standard opcode %d ",
|
|
opcode);
|
|
dwarfstring_append_printf_i(&m9b,
|
|
"with %d operands: not understood.", opcnt);
|
|
_dwarf_printf(dbg,dwarfstring_string(&m9b));
|
|
*err_count_out += 1;
|
|
dwarfstring_destructor(&m9b);
|
|
}
|
|
#endif /* PRINTING_DETAILS */
|
|
for (oc = 0; oc < opcnt; oc++) {
|
|
int ocres = 0;
|
|
/* Read and discard operands we don't
|
|
understand.
|
|
arbitrary choice of unsigned read.
|
|
signed read would work as well. */
|
|
Dwarf_Unsigned utmp2 = 0;
|
|
|
|
(void) utmp2;
|
|
ocres = read_uword_de( &line_ptr,&utmp2,
|
|
dbg,error,line_ptr_end);
|
|
if (ocres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
curr_line = 0;
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
#ifdef PRINTING_DETAILS
|
|
{
|
|
dwarfstring m9e;
|
|
dwarfstring_constructor(&m9e);
|
|
dwarfstring_append_printf_u(&m9e,
|
|
" %" DW_PR_DUu,
|
|
utmp2);
|
|
dwarfstring_append_printf_u(&m9e,
|
|
" (0x%" DW_PR_XZEROS DW_PR_DUx ")",
|
|
utmp2);
|
|
_dwarf_printf(dbg,dwarfstring_string(&m9e));
|
|
dwarfstring_destructor(&m9e);
|
|
}
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
#ifdef PRINTING_DETAILS
|
|
_dwarf_printf(dbg,"***\n");
|
|
#endif /* PRINTING_DETAILS */
|
|
} 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) */
|
|
#ifdef PRINTING_DETAILS
|
|
unsigned origop = opcode;
|
|
#endif /* PRINTING_DETAILS */
|
|
Dwarf_Unsigned operation_advance = 0;
|
|
|
|
opcode = opcode - line_context->lc_opcode_base;
|
|
operation_advance =
|
|
(opcode / line_context->lc_line_range);
|
|
|
|
if (line_context->lc_maximum_ops_per_instruction < 2) {
|
|
regs.lr_address = regs.lr_address +
|
|
(operation_advance *
|
|
line_context->lc_minimum_instruction_length);
|
|
} else {
|
|
regs.lr_address = regs.lr_address +
|
|
(line_context->lc_minimum_instruction_length *
|
|
((regs.lr_op_index + operation_advance)/
|
|
line_context->lc_maximum_ops_per_instruction));
|
|
regs.lr_op_index =
|
|
(regs.lr_op_index +operation_advance)%
|
|
line_context->lc_maximum_ops_per_instruction;
|
|
}
|
|
|
|
regs.lr_line = regs.lr_line + line_context->lc_line_base +
|
|
opcode % line_context->lc_line_range;
|
|
if ((Dwarf_Signed)regs.lr_line < 0) {
|
|
/* Something is badly wrong */
|
|
dwarfstring m;
|
|
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_i(&m,
|
|
"\nERROR: DW_DLE_LINE_TABLE_LINENO_ERROR "
|
|
"The line number computes as %d "
|
|
"and negative line numbers "
|
|
"are not correct.",(Dwarf_Signed)regs.lr_line);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_LINE_TABLE_LINENO_ERROR,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
regs.lr_line = 0;
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
curr_line = 0;
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
#ifdef PRINTING_DETAILS
|
|
{
|
|
dwarfstring ma;
|
|
dwarfstring mb;
|
|
|
|
dwarfstring_constructor(&ma);
|
|
dwarfstring_constructor(&mb);
|
|
dwarfstring_append_printf_u(&mb,"Specialop %3u", origop);
|
|
_dwarf_printf(dbg,dwarfstring_string(&ma));
|
|
dwarfstring_destructor(&ma);
|
|
print_line_detail(dbg,dwarfstring_string(&mb),
|
|
opcode,line_count+1, ®s,is_single_table,
|
|
is_actuals_table);
|
|
dwarfstring_destructor(&mb);
|
|
dwarfstring_destructor(&ma);
|
|
}
|
|
#endif /* PRINTING_DETAILS */
|
|
|
|
if (dolines) {
|
|
curr_line =
|
|
(Dwarf_Line) _dwarf_get_alloc(dbg,DW_DLA_LINE,1);
|
|
if (curr_line == NULL) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
/* Mark a line record as being DW_LNS_set_address */
|
|
curr_line->li_l_data.li_is_addr_set =
|
|
is_addr_set;
|
|
is_addr_set = false;
|
|
curr_line->li_address = regs.lr_address;
|
|
curr_line->li_l_data.li_file =
|
|
(Dwarf_Signed) regs.lr_file;
|
|
curr_line->li_l_data.li_line =
|
|
(Dwarf_Signed) regs.lr_line;
|
|
curr_line->li_l_data.li_column =
|
|
(Dwarf_Half) regs.lr_column;
|
|
curr_line->li_l_data.li_is_stmt =
|
|
regs.lr_is_stmt;
|
|
curr_line->li_l_data.li_basic_block =
|
|
regs.lr_basic_block;
|
|
curr_line->li_l_data.li_end_sequence =
|
|
curr_line->li_l_data.
|
|
li_epilogue_begin = regs.lr_epilogue_begin;
|
|
curr_line->li_l_data.li_prologue_end =
|
|
regs.lr_prologue_end;
|
|
curr_line->li_l_data.li_isa =
|
|
regs.lr_isa;
|
|
curr_line->li_l_data.li_discriminator =
|
|
regs.lr_discriminator;
|
|
curr_line->li_l_data.li_call_context =
|
|
regs.lr_call_context;
|
|
curr_line->li_l_data.li_subprogram =
|
|
regs.lr_subprogram;
|
|
curr_line->li_context = line_context;
|
|
curr_line->li_is_actuals_table = is_actuals_table;
|
|
line_count++;
|
|
|
|
chain_line = (Dwarf_Chain)
|
|
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
|
|
if (chain_line == NULL) {
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
chain_line->ch_itemtype = DW_DLA_LINE;
|
|
chain_line->ch_item = curr_line;
|
|
_dwarf_update_chain_list(chain_line,&head_chain,
|
|
&curr_chain);
|
|
curr_line = 0;
|
|
}
|
|
|
|
regs.lr_basic_block = false;
|
|
regs.lr_prologue_end = false;
|
|
regs.lr_epilogue_begin = false;
|
|
regs.lr_discriminator = 0;
|
|
#ifdef PRINTING_DETAILS
|
|
#endif /* PRINTING_DETAILS */
|
|
} else if (type == LOP_STANDARD) {
|
|
#ifdef PRINTING_DETAILS
|
|
dwarfstring mb;
|
|
#endif /* PRINTING_DETAILS */
|
|
|
|
switch (opcode) {
|
|
case DW_LNS_copy:{
|
|
|
|
#ifdef PRINTING_DETAILS
|
|
print_line_detail(dbg,"DW_LNS_copy",
|
|
opcode,line_count+1, ®s,is_single_table,
|
|
is_actuals_table);
|
|
#endif /* PRINTING_DETAILS */
|
|
if (dolines) {
|
|
curr_line = (Dwarf_Line) _dwarf_get_alloc(dbg,
|
|
DW_DLA_LINE, 1);
|
|
if (curr_line == NULL) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
/* Mark a line record as DW_LNS_set_address */
|
|
curr_line->li_l_data.li_is_addr_set =
|
|
is_addr_set;
|
|
is_addr_set = false;
|
|
|
|
curr_line->li_address = regs.lr_address;
|
|
curr_line->li_l_data.li_file =
|
|
(Dwarf_Signed) regs.lr_file;
|
|
curr_line->li_l_data.li_line =
|
|
(Dwarf_Signed) regs.lr_line;
|
|
curr_line->li_l_data.li_column =
|
|
(Dwarf_Half) regs.lr_column;
|
|
curr_line->li_l_data.li_is_stmt =
|
|
regs.lr_is_stmt;
|
|
curr_line->li_l_data.
|
|
li_basic_block = regs.lr_basic_block;
|
|
curr_line->li_l_data.
|
|
li_end_sequence = regs.lr_end_sequence;
|
|
curr_line->li_context = line_context;
|
|
curr_line->li_is_actuals_table = is_actuals_table;
|
|
curr_line->li_l_data.
|
|
li_epilogue_begin = regs.lr_epilogue_begin;
|
|
curr_line->li_l_data.
|
|
li_prologue_end = regs.lr_prologue_end;
|
|
curr_line->li_l_data.li_isa =
|
|
regs.lr_isa;
|
|
curr_line->li_l_data.li_discriminator
|
|
= regs.lr_discriminator;
|
|
curr_line->li_l_data.li_call_context
|
|
= regs.lr_call_context;
|
|
curr_line->li_l_data.li_subprogram =
|
|
regs.lr_subprogram;
|
|
line_count++;
|
|
|
|
chain_line = (Dwarf_Chain)
|
|
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
|
|
if (chain_line == NULL) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
chain_line->ch_itemtype = DW_DLA_LINE;
|
|
chain_line->ch_item = curr_line;
|
|
_dwarf_update_chain_list(chain_line,&head_chain,
|
|
&curr_chain);
|
|
curr_line = 0;
|
|
}
|
|
|
|
regs.lr_basic_block = false;
|
|
regs.lr_prologue_end = false;
|
|
regs.lr_epilogue_begin = false;
|
|
regs.lr_discriminator = 0;
|
|
}
|
|
break;
|
|
case DW_LNS_advance_pc:{
|
|
Dwarf_Unsigned utmp2 = 0;
|
|
int advres = 0;
|
|
|
|
advres = read_uword_de( &line_ptr,&utmp2,
|
|
dbg,error,line_ptr_end);
|
|
if (advres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
#ifdef PRINTING_DETAILS
|
|
dwarfstring_constructor(&mb);
|
|
dwarfstring_append_printf_i(&mb,
|
|
"DW_LNS_advance_pc val %" DW_PR_DSd,
|
|
utmp2);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" 0x%" DW_PR_XZEROS DW_PR_DUx "\n",
|
|
utmp2);
|
|
_dwarf_printf(dbg,dwarfstring_string(&mb));
|
|
dwarfstring_destructor(&mb);
|
|
#endif /* PRINTING_DETAILS */
|
|
leb128_num = utmp2;
|
|
regs.lr_address = regs.lr_address +
|
|
line_context->lc_minimum_instruction_length *
|
|
leb128_num;
|
|
}
|
|
break;
|
|
case DW_LNS_advance_line:{
|
|
Dwarf_Signed stmp = 0;
|
|
int alres = 0;
|
|
|
|
alres = read_sword_de( &line_ptr,&stmp,
|
|
dbg,error,line_ptr_end);
|
|
if (alres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
advance_line = (Dwarf_Signed) stmp;
|
|
|
|
#ifdef PRINTING_DETAILS
|
|
dwarfstring_constructor(&mb);
|
|
dwarfstring_append_printf_i(&mb,
|
|
"DW_LNS_advance_line val %" DW_PR_DSd,
|
|
advance_line);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" 0x%" DW_PR_XZEROS DW_PR_DSx "\n",
|
|
advance_line);
|
|
_dwarf_printf(dbg,dwarfstring_string(&mb));
|
|
dwarfstring_destructor(&mb);
|
|
#endif /* PRINTING_DETAILS */
|
|
regs.lr_line = regs.lr_line + advance_line;
|
|
if ((Dwarf_Signed)regs.lr_line < 0) {
|
|
dwarfstring m;
|
|
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_i(&m,
|
|
"\nERROR: DW_DLE_LINE_TABLE_LINENO_ERROR"
|
|
" The line number is %d "
|
|
"and negative line numbers after "
|
|
"DW_LNS_ADVANCE_LINE ",
|
|
(Dwarf_Signed)regs.lr_line);
|
|
dwarfstring_append_printf_i(&m,
|
|
" of %d "
|
|
"are not correct.",stmp);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_LINE_TABLE_LINENO_ERROR,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
regs.lr_line = 0;
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
break;
|
|
case DW_LNS_set_file:{
|
|
Dwarf_Unsigned utmp2 = 0;
|
|
int sfres = 0;
|
|
|
|
sfres = read_uword_de( &line_ptr,&utmp2,
|
|
dbg,error,line_ptr_end);
|
|
if (sfres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
{
|
|
Dwarf_Signed fno = (Dwarf_Signed)utmp2;
|
|
if (fno < 0) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_LINE_INDEX_WRONG,
|
|
"DW_DLE_LINE_INDEX_WRONG "
|
|
"A DW_LNS_set_file has an "
|
|
"Impossible "
|
|
"file number ");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
|
|
regs.lr_file = utmp2;
|
|
#ifdef PRINTING_DETAILS
|
|
dwarfstring_constructor(&mb);
|
|
dwarfstring_append_printf_i(&mb,
|
|
"DW_LNS_set_file %ld\n",
|
|
regs.lr_file);
|
|
_dwarf_printf(dbg,dwarfstring_string(&mb));
|
|
dwarfstring_destructor(&mb);
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
break;
|
|
case DW_LNS_set_column:{
|
|
Dwarf_Unsigned utmp2 = 0;
|
|
int scres = 0;
|
|
|
|
scres = read_uword_de( &line_ptr,&utmp2,
|
|
dbg,error,line_ptr_end);
|
|
if (scres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
{
|
|
Dwarf_Signed cno = (Dwarf_Signed)utmp2;
|
|
if (cno < 0) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_LINE_INDEX_WRONG,
|
|
"DW_DLE_LINE_INDEX_WRONG "
|
|
"A DW_LNS_set_column has an "
|
|
"impossible "
|
|
"column number ");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
|
|
regs.lr_column = utmp2;
|
|
#ifdef PRINTING_DETAILS
|
|
dwarfstring_constructor(&mb);
|
|
|
|
dwarfstring_append_printf_i(&mb,
|
|
"DW_LNS_set_column val %" DW_PR_DSd ,
|
|
regs.lr_column);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" 0x%" DW_PR_XZEROS DW_PR_DSx "\n",
|
|
regs.lr_column);
|
|
_dwarf_printf(dbg,dwarfstring_string(&mb));
|
|
dwarfstring_destructor(&mb);
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
break;
|
|
case DW_LNS_negate_stmt:{
|
|
regs.lr_is_stmt = !regs.lr_is_stmt;
|
|
#ifdef PRINTING_DETAILS
|
|
_dwarf_printf(dbg, "DW_LNS_negate_stmt\n");
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
break;
|
|
case DW_LNS_set_basic_block:{
|
|
regs.lr_basic_block = true;
|
|
#ifdef PRINTING_DETAILS
|
|
_dwarf_printf(dbg,
|
|
"DW_LNS_set_basic_block\n");
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
break;
|
|
|
|
case DW_LNS_const_add_pc:{
|
|
opcode = MAX_LINE_OP_CODE -
|
|
line_context->lc_opcode_base;
|
|
if (line_context->lc_maximum_ops_per_instruction < 2){
|
|
Dwarf_Unsigned operation_advance =
|
|
(opcode / line_context->lc_line_range);
|
|
regs.lr_address = regs.lr_address +
|
|
line_context->lc_minimum_instruction_length *
|
|
operation_advance;
|
|
} else {
|
|
Dwarf_Unsigned operation_advance =
|
|
(opcode / line_context->lc_line_range);
|
|
regs.lr_address = regs.lr_address +
|
|
line_context->lc_minimum_instruction_length *
|
|
((regs.lr_op_index + operation_advance)/
|
|
line_context->lc_maximum_ops_per_instruction);
|
|
regs.lr_op_index =
|
|
(regs.lr_op_index +operation_advance)%
|
|
line_context->lc_maximum_ops_per_instruction;
|
|
}
|
|
#ifdef PRINTING_DETAILS
|
|
dwarfstring_constructor(&mb);
|
|
dwarfstring_append_printf_u(&mb,
|
|
"DW_LNS_const_add_pc new address 0x%"
|
|
DW_PR_XZEROS DW_PR_DSx "\n",
|
|
regs.lr_address);
|
|
_dwarf_printf(dbg,dwarfstring_string(&mb));
|
|
dwarfstring_destructor(&mb);
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
break;
|
|
case DW_LNS_fixed_advance_pc:{
|
|
Dwarf_Unsigned fpc = 0;
|
|
int apres = 0;
|
|
/*READ_UNALIGNED_CK(dbg, fixed_advance_pc,
|
|
Dwarf_Half, line_ptr,
|
|
DWARF_HALF_SIZE,error,line_ptr_end); */
|
|
apres = _dwarf_read_unaligned_ck_wrapper(dbg,
|
|
&fpc,line_ptr,DWARF_HALF_SIZE,line_ptr_end,
|
|
error);
|
|
fixed_advance_pc = fpc;
|
|
if (apres == DW_DLV_ERROR) {
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
return apres;
|
|
}
|
|
line_ptr += DWARF_HALF_SIZE;
|
|
if (line_ptr > line_ptr_end) {
|
|
dwarfstring g;
|
|
/* ptrdiff_t is generated but not named */
|
|
Dwarf_Unsigned localoff =
|
|
(line_ptr >= section_start)?
|
|
(line_ptr - section_start):0xfffffff;
|
|
|
|
dwarfstring_constructor(&g);
|
|
dwarfstring_append_printf_u(&g,
|
|
"DW_DLE_LINE_TABLE_BAD reading "
|
|
"DW_LNS_fixed_advance_pc we are "
|
|
"off this line table at section "
|
|
"offset. 0x%x .",
|
|
localoff);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_LINE_TABLE_BAD,
|
|
dwarfstring_string(&g));
|
|
dwarfstring_destructor(&g);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
regs.lr_address = regs.lr_address + fixed_advance_pc;
|
|
regs.lr_op_index = 0;
|
|
#ifdef PRINTING_DETAILS
|
|
dwarfstring_constructor(&mb);
|
|
dwarfstring_append_printf_i(&mb,
|
|
"DW_LNS_fixed_advance_pc val %"
|
|
DW_PR_DSd, fixed_advance_pc);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" 0x%" DW_PR_XZEROS DW_PR_DSx,
|
|
fixed_advance_pc);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" new address 0x%"
|
|
DW_PR_XZEROS DW_PR_DSx "\n",
|
|
regs.lr_address);
|
|
_dwarf_printf(dbg,
|
|
dwarfstring_string(&mb));
|
|
dwarfstring_destructor(&mb);
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
break;
|
|
|
|
/* New in DWARF3 */
|
|
case DW_LNS_set_prologue_end:{
|
|
regs.lr_prologue_end = true;
|
|
}
|
|
break;
|
|
/* New in DWARF3 */
|
|
case DW_LNS_set_epilogue_begin:{
|
|
regs.lr_epilogue_begin = true;
|
|
#ifdef PRINTING_DETAILS
|
|
_dwarf_printf(dbg,
|
|
"DW_LNS_set_prologue_end set true.\n");
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
break;
|
|
|
|
/* New in DWARF3 */
|
|
case DW_LNS_set_isa:{
|
|
Dwarf_Unsigned utmp2 = 0;
|
|
int sires = 0;
|
|
|
|
sires = read_uword_de( &line_ptr,&utmp2,
|
|
dbg,error,line_ptr_end);
|
|
if (sires == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
regs.lr_isa = utmp2;
|
|
|
|
#ifdef PRINTING_DETAILS
|
|
dwarfstring_constructor(&mb);
|
|
dwarfstring_append_printf_u(&mb,
|
|
"DW_LNS_set_isa new value 0x%"
|
|
DW_PR_XZEROS DW_PR_DUx ".\n",
|
|
utmp2);
|
|
_dwarf_printf(dbg,dwarfstring_string(&mb));
|
|
dwarfstring_destructor(&mb);
|
|
#endif /* PRINTING_DETAILS */
|
|
if (regs.lr_isa != utmp2) {
|
|
/* The value of the isa did
|
|
not fit in our
|
|
local so we record it wrong.
|
|
declare an error. */
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,
|
|
head_chain,line_count);
|
|
_dwarf_error(dbg, error,
|
|
DW_DLE_LINE_NUM_OPERANDS_BAD);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* Experimental two-level line tables */
|
|
/* DW_LNS_set_address_from_logical and
|
|
DW_LNS_set_subprogram
|
|
share the same opcode. Disambiguate by checking
|
|
is_actuals_table. */
|
|
case DW_LNS_set_subprogram:
|
|
|
|
if (is_actuals_table) {
|
|
/* DW_LNS_set_address_from_logical */
|
|
Dwarf_Signed stmp = 0;
|
|
int atres = 0;
|
|
|
|
atres = read_sword_de( &line_ptr,&stmp,
|
|
dbg,error,line_ptr_end);
|
|
if (atres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
advance_line = (Dwarf_Signed) stmp;
|
|
regs.lr_line = regs.lr_line + advance_line;
|
|
if ((Dwarf_Signed)regs.lr_line < 0) {
|
|
dwarfstring m;
|
|
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_i(&m,
|
|
"\nERROR: DW_DLE_LINE_TABLE_LINENO_ERROR"
|
|
" The line number is %d "
|
|
"and negative line numbers after "
|
|
"DW_LNS_set_subprogram ",
|
|
(Dwarf_Signed)regs.lr_line);
|
|
dwarfstring_append_printf_i(&m,
|
|
" of %d applied "
|
|
"are not correct.",stmp);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_LINE_TABLE_LINENO_ERROR,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
regs.lr_line = 0;
|
|
_dwarf_free_chain_entries(dbg,
|
|
head_chain,line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
|
|
}
|
|
if (regs.lr_line >= 1 &&
|
|
regs.lr_line - 1 < logicals_count) {
|
|
regs.lr_address =
|
|
logicals[regs.lr_line - 1]->li_address;
|
|
regs.lr_op_index = 0;
|
|
#ifdef PRINTING_DETAILS /* block 1 print */
|
|
dwarfstring_constructor(&mb);
|
|
dwarfstring_append_printf_i(&mb,
|
|
"DW_LNS_set_address_from"
|
|
"_logical "
|
|
"%" DW_PR_DSd,
|
|
stmp);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" 0x%" DW_PR_XZEROS DW_PR_DSx,
|
|
stmp);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" newaddr="
|
|
" 0x%" DW_PR_XZEROS DW_PR_DUx ".\n",
|
|
regs.lr_address);
|
|
_dwarf_printf(dbg,
|
|
dwarfstring_string(&mb));
|
|
dwarfstring_destructor(&mb);
|
|
#endif /* PRINTING_DETAILS */
|
|
} else {
|
|
#ifdef PRINTING_DETAILS /* block 2 print */
|
|
dwarfstring_constructor(&mb);
|
|
dwarfstring_append_printf_i(&mb,
|
|
"DW_LNS_set_address_from_logical line"
|
|
" is %" DW_PR_DSd ,
|
|
regs.lr_line);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" 0x%" DW_PR_XZEROS DW_PR_DSx ".\n",
|
|
regs.lr_line);
|
|
_dwarf_printf(dbg,
|
|
dwarfstring_string(&mb));
|
|
dwarfstring_destructor(&mb);
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
} else {
|
|
/* DW_LNS_set_subprogram,
|
|
building logicals table. */
|
|
Dwarf_Unsigned utmp2 = 0;
|
|
int spres = 0;
|
|
|
|
regs.lr_call_context = 0;
|
|
spres = read_uword_de( &line_ptr,&utmp2,
|
|
dbg,error,line_ptr_end);
|
|
if (spres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
regs.lr_subprogram = utmp2;
|
|
#ifdef PRINTING_DETAILS /* block 3 print */
|
|
dwarfstring_constructor(&mb);
|
|
dwarfstring_append_printf_i(&mb,
|
|
"DW_LNS_set_subprogram "
|
|
"%" DW_PR_DSd,
|
|
utmp2);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" 0x%" DW_PR_XZEROS DW_PR_DSx "\n",
|
|
utmp2);
|
|
_dwarf_printf(dbg,
|
|
dwarfstring_string(&mb));
|
|
dwarfstring_destructor(&mb);
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
break;
|
|
/* Experimental two-level line tables */
|
|
case DW_LNS_inlined_call: {
|
|
Dwarf_Signed stmp = 0;
|
|
Dwarf_Unsigned ilcuw = 0;
|
|
int icres = 0;
|
|
|
|
icres = read_sword_de( &line_ptr,&stmp,
|
|
dbg,error,line_ptr_end);
|
|
if (icres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
regs.lr_call_context = line_count + stmp;
|
|
icres = read_uword_de(&line_ptr,&ilcuw,
|
|
dbg,error,line_ptr_end);
|
|
regs.lr_subprogram = ilcuw;
|
|
if (icres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
#ifdef PRINTING_DETAILS
|
|
dwarfstring_constructor(&mb);
|
|
dwarfstring_append_printf_i(&mb,
|
|
"DW_LNS_inlined_call "
|
|
"%" DW_PR_DSd ,stmp);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" (0x%" DW_PR_XZEROS DW_PR_DSx "),",
|
|
stmp);
|
|
dwarfstring_append_printf_i(&mb,
|
|
"%" DW_PR_DSd,
|
|
regs.lr_subprogram);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" (0x%" DW_PR_XZEROS DW_PR_DSx ")",
|
|
regs.lr_subprogram);
|
|
dwarfstring_append_printf_i(&mb,
|
|
" callcontext=" "%" DW_PR_DSd ,
|
|
regs.lr_call_context);
|
|
dwarfstring_append_printf_u(&mb,
|
|
" (0x%" DW_PR_XZEROS DW_PR_DSx ")\n",
|
|
regs.lr_call_context);
|
|
_dwarf_printf(dbg,
|
|
dwarfstring_string(&mb));
|
|
dwarfstring_destructor(&mb);
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
break;
|
|
|
|
/* Experimental two-level line tables */
|
|
case DW_LNS_pop_context: {
|
|
Dwarf_Unsigned logical_num = regs.lr_call_context;
|
|
Dwarf_Chain logical_chain = head_chain;
|
|
Dwarf_Line logical_line = 0;
|
|
|
|
if (logical_num > 0 && logical_num <= line_count) {
|
|
for (i = 1; i < logical_num; i++) {
|
|
logical_chain = logical_chain->ch_next;
|
|
}
|
|
logical_line =
|
|
(Dwarf_Line) logical_chain->ch_item;
|
|
regs.lr_file =
|
|
logical_line->li_l_data.li_file;
|
|
regs.lr_line =
|
|
logical_line->li_l_data.li_line;
|
|
regs.lr_column =
|
|
logical_line->
|
|
li_l_data.li_column;
|
|
regs.lr_discriminator =
|
|
logical_line->
|
|
li_l_data.li_discriminator;
|
|
regs.lr_is_stmt =
|
|
logical_line->
|
|
li_l_data.li_is_stmt;
|
|
regs.lr_call_context =
|
|
logical_line->
|
|
li_l_data.li_call_context;
|
|
regs.lr_subprogram =
|
|
logical_line->
|
|
li_l_data.li_subprogram;
|
|
#ifdef PRINTING_DETAILS
|
|
{
|
|
dwarfstring pcon;
|
|
dwarfstring_constructor(&pcon);
|
|
dwarfstring_append_printf_u(&pcon,
|
|
"DW_LNS_pop_context set"
|
|
" from logical "
|
|
"%" DW_PR_DUu ,logical_num);
|
|
dwarfstring_append_printf_u(&pcon,
|
|
" (0x%" DW_PR_XZEROS DW_PR_DUx ")\n",
|
|
logical_num);
|
|
_dwarf_printf(dbg,
|
|
dwarfstring_string(&pcon));
|
|
dwarfstring_destructor(&pcon);
|
|
}
|
|
} else {
|
|
dwarfstring pcon;
|
|
dwarfstring_constructor(&pcon);
|
|
dwarfstring_append_printf_u(&pcon,
|
|
"DW_LNS_pop_context does nothing, logical"
|
|
"%" DW_PR_DUu ,
|
|
logical_num);
|
|
dwarfstring_append_printf_u(&pcon,
|
|
" (0x%" DW_PR_XZEROS DW_PR_DUx ")\n",
|
|
logical_num);
|
|
_dwarf_printf(dbg,
|
|
dwarfstring_string(&pcon));
|
|
dwarfstring_destructor(&pcon);
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_LINE_TABLE_BAD,
|
|
"DW_DLE_LINE_TABLE_BAD: "
|
|
"Impossible standard line table operator");
|
|
return DW_DLV_ERROR;
|
|
} /* End switch (opcode) */
|
|
} else if (type == LOP_EXTENDED) {
|
|
Dwarf_Unsigned utmp3 = 0;
|
|
Dwarf_Small ext_opcode = 0;
|
|
int leres = 0;
|
|
|
|
leres = read_uword_de( &line_ptr,&utmp3,
|
|
dbg,error,line_ptr_end);
|
|
if (leres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
instr_length = 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. */
|
|
if (line_ptr >= line_ptr_end) {
|
|
dwarfstring g;
|
|
/* ptrdiff_t is generated but not named */
|
|
Dwarf_Unsigned localoffset =
|
|
(line_ptr >= section_start)?
|
|
(line_ptr - section_start) : 0;
|
|
|
|
dwarfstring_constructor(&g);
|
|
dwarfstring_append_printf_u(&g,
|
|
"DW_DLE_LINE_TABLE_BAD reading "
|
|
"extended op we are "
|
|
"off this line table at section "
|
|
"offset 0x%x .",
|
|
localoffset);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_LINE_TABLE_BAD,
|
|
dwarfstring_string(&g));
|
|
dwarfstring_destructor(&g);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,head_chain,line_count);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
ext_opcode = *(Dwarf_Small *) line_ptr;
|
|
line_ptr++;
|
|
if (line_ptr > line_ptr_end) {
|
|
dwarfstring g;
|
|
/* ptrdiff_t is generated but not named */
|
|
Dwarf_Unsigned localoff =
|
|
(line_ptr >= section_start)?
|
|
(line_ptr - section_start):0xfffffff;
|
|
|
|
dwarfstring_constructor(&g);
|
|
dwarfstring_append_printf_u(&g,
|
|
"DW_DLE_LINE_TABLE_BAD reading "
|
|
"extended op opcode we are "
|
|
"off this line table at section "
|
|
"offset 0x%x .",
|
|
localoff);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_LINE_TABLE_BAD,
|
|
dwarfstring_string(&g));
|
|
dwarfstring_destructor(&g);
|
|
_dwarf_free_chain_entries(dbg,head_chain,line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
switch (ext_opcode) {
|
|
|
|
case DW_LNE_end_sequence:{
|
|
regs.lr_end_sequence = true;
|
|
if (dolines) {
|
|
curr_line = (Dwarf_Line)
|
|
_dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
|
|
if (!curr_line) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
#ifdef PRINTING_DETAILS
|
|
print_line_detail(dbg,
|
|
"DW_LNE_end_sequence extended",
|
|
ext_opcode, line_count+1,®s,
|
|
is_single_table, is_actuals_table);
|
|
#endif /* PRINTING_DETAILS */
|
|
curr_line->li_address = regs.lr_address;
|
|
curr_line->li_l_data.li_file =
|
|
(Dwarf_Signed) regs.lr_file;
|
|
curr_line->li_l_data.li_line =
|
|
(Dwarf_Signed) regs.lr_line;
|
|
curr_line->li_l_data.li_column =
|
|
(Dwarf_Half) regs.lr_column;
|
|
curr_line->li_l_data.li_is_stmt =
|
|
regs.lr_is_stmt;
|
|
curr_line->li_l_data.
|
|
li_basic_block = regs.lr_basic_block;
|
|
curr_line->li_l_data.
|
|
li_end_sequence = regs.lr_end_sequence;
|
|
curr_line->li_context = line_context;
|
|
curr_line->li_is_actuals_table = is_actuals_table;
|
|
curr_line->li_l_data.
|
|
li_epilogue_begin = regs.lr_epilogue_begin;
|
|
curr_line->li_l_data.
|
|
li_prologue_end = regs.lr_prologue_end;
|
|
curr_line->li_l_data.li_isa =
|
|
regs.lr_isa;
|
|
curr_line->li_l_data.li_discriminator
|
|
= regs.lr_discriminator;
|
|
curr_line->li_l_data.li_call_context
|
|
= regs.lr_call_context;
|
|
curr_line->li_l_data.li_subprogram =
|
|
regs.lr_subprogram;
|
|
line_count++;
|
|
chain_line = (Dwarf_Chain)
|
|
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
|
|
if (chain_line == NULL) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
chain_line->ch_itemtype = DW_DLA_LINE;
|
|
chain_line->ch_item = curr_line;
|
|
_dwarf_update_chain_list(chain_line,
|
|
&head_chain,&curr_chain);
|
|
curr_line = 0;
|
|
}
|
|
_dwarf_set_line_table_regs_default_values(®s,
|
|
line_context->lc_version_number,
|
|
line_context->lc_default_is_stmt);
|
|
}
|
|
break;
|
|
|
|
case DW_LNE_set_address:{
|
|
int sares = 0;
|
|
/* READ_UNALIGNED_CK(dbg, regs.lr_address,
|
|
Dwarf_Addr,
|
|
line_ptr, address_size,error,line_ptr_end); */
|
|
sares = _dwarf_read_unaligned_ck_wrapper(dbg,
|
|
®s.lr_address,line_ptr,
|
|
address_size,line_ptr_end,
|
|
error);
|
|
if (sares == DW_DLV_ERROR) {
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
return sares;
|
|
}
|
|
|
|
/* Mark a line record as being DW_LNS_set_address */
|
|
is_addr_set = true;
|
|
#ifdef PRINTING_DETAILS
|
|
{
|
|
dwarfstring sadd;
|
|
dwarfstring_constructor(&sadd);
|
|
dwarfstring_append_printf_u(&sadd,
|
|
"DW_LNE_set_address address 0x%"
|
|
DW_PR_XZEROS DW_PR_DUx "\n",
|
|
regs.lr_address);
|
|
_dwarf_printf(dbg,dwarfstring_string(&sadd));
|
|
dwarfstring_destructor(&sadd);
|
|
}
|
|
#endif /* PRINTING_DETAILS */
|
|
if (doaddrs) {
|
|
/* SGI IRIX rqs processing only. */
|
|
curr_line = (Dwarf_Line) _dwarf_get_alloc(dbg,
|
|
DW_DLA_LINE, 1);
|
|
if (!curr_line) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* Mark a line record as being
|
|
DW_LNS_set_address */
|
|
curr_line->li_l_data.li_is_addr_set
|
|
= is_addr_set;
|
|
is_addr_set = false;
|
|
curr_line->li_address = regs.lr_address;
|
|
#ifdef __sgi /* SGI IRIX ONLY */
|
|
/* ptrdiff_t is generated but not named */
|
|
curr_line->li_offset =
|
|
line_ptr - dbg->de_debug_line.dss_data;
|
|
#endif /* __sgi */
|
|
line_count++;
|
|
chain_line = (Dwarf_Chain)
|
|
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
|
|
if (chain_line == NULL) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
chain_line->ch_itemtype = DW_DLA_LINE;
|
|
chain_line->ch_item = curr_line;
|
|
_dwarf_update_chain_list(chain_line,
|
|
&head_chain,&curr_chain);
|
|
curr_line = 0;
|
|
}
|
|
regs.lr_op_index = 0;
|
|
line_ptr += address_size;
|
|
if (line_ptr > line_ptr_end) {
|
|
dwarfstring g;
|
|
/* ptrdiff_t is generated but not named */
|
|
Dwarf_Unsigned localoff =
|
|
(line_ptr >= section_start)?
|
|
(line_ptr - section_start):0xfffffff;
|
|
|
|
dwarfstring_constructor(&g);
|
|
dwarfstring_append_printf_u(&g,
|
|
"DW_DLE_LINE_TABLE_BAD reading "
|
|
"DW_LNE_set_address we are "
|
|
"off this line table at section "
|
|
"offset 0x%x .",
|
|
localoff);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_LINE_TABLE_BAD,
|
|
dwarfstring_string(&g));
|
|
dwarfstring_destructor(&g);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DW_LNE_define_file:
|
|
if (dolines) {
|
|
int dlres = 0;
|
|
Dwarf_Unsigned value = 0;
|
|
|
|
cur_file_entry = (Dwarf_File_Entry)
|
|
malloc(sizeof(struct Dwarf_File_Entry_s));
|
|
if (cur_file_entry == NULL) {
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
memset(cur_file_entry,0,
|
|
sizeof(struct Dwarf_File_Entry_s));
|
|
_dwarf_add_to_files_list(line_context,
|
|
cur_file_entry);
|
|
cur_file_entry->fi_file_name =
|
|
(Dwarf_Small *) line_ptr;
|
|
dlres = _dwarf_check_string_valid(dbg,
|
|
line_ptr,line_ptr,line_ptr_end,
|
|
DW_DLE_DEFINE_FILE_STRING_BAD,error);
|
|
if (dlres != DW_DLV_OK) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return dlres;
|
|
}
|
|
line_ptr = line_ptr + strlen((char *) line_ptr)
|
|
+ 1;
|
|
dlres = read_uword_de( &line_ptr,&value,
|
|
dbg,error,line_ptr_end);
|
|
if (dlres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
cur_file_entry->fi_dir_index =
|
|
(Dwarf_Signed)value;
|
|
cur_file_entry->fi_dir_index_present = TRUE;
|
|
dlres = read_uword_de( &line_ptr,&value,
|
|
dbg,error,line_ptr_end);
|
|
if (dlres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
cur_file_entry->fi_time_last_mod = value;
|
|
dlres = read_uword_de( &line_ptr,&value,
|
|
dbg,error,line_ptr_end);
|
|
if (dlres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
cur_file_entry->fi_file_length = value;
|
|
cur_file_entry->fi_dir_index_present = TRUE;
|
|
cur_file_entry->fi_time_last_mod_present = TRUE;
|
|
cur_file_entry->fi_file_length_present = TRUE;
|
|
#ifdef PRINTING_DETAILS
|
|
{
|
|
dwarfstring m9c;
|
|
dwarfstring_constructor(&m9c);
|
|
dwarfstring_append_printf_s(&m9c,
|
|
"DW_LNE_define_file %s \n",
|
|
(char *)cur_file_entry->fi_file_name);
|
|
dwarfstring_append_printf_i(&m9c,
|
|
" dir index %d\n",
|
|
(int) cur_file_entry->fi_dir_index);
|
|
|
|
{
|
|
time_t tt3 = (time_t) cur_file_entry->
|
|
fi_time_last_mod;
|
|
|
|
/* ctime supplies newline */
|
|
dwarfstring_append_printf_u(&m9c,
|
|
" last time 0x%x ",
|
|
(Dwarf_Unsigned)tt3);
|
|
dwarfstring_append_printf_s(&m9c,
|
|
"%s",
|
|
ctime(&tt3));
|
|
}
|
|
dwarfstring_append_printf_i(&m9c,
|
|
" file length %ld ",
|
|
cur_file_entry->fi_file_length);
|
|
dwarfstring_append_printf_u(&m9c,
|
|
"0x%lx\n",
|
|
cur_file_entry->fi_file_length);
|
|
_dwarf_printf(dbg,dwarfstring_string(&m9c));
|
|
dwarfstring_destructor(&m9c);
|
|
}
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
break;
|
|
case DW_LNE_set_discriminator:{
|
|
/* New in DWARF4 */
|
|
int sdres = 0;
|
|
Dwarf_Unsigned utmp2 = 0;
|
|
|
|
sdres = read_uword_de( &line_ptr,&utmp2,
|
|
dbg,error,line_ptr_end);
|
|
if (sdres == DW_DLV_ERROR) {
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
regs.lr_discriminator = utmp2;
|
|
|
|
#ifdef PRINTING_DETAILS
|
|
{
|
|
dwarfstring mk;
|
|
dwarfstring_constructor(&mk);
|
|
dwarfstring_append_printf_u(&mk,
|
|
"DW_LNE_set_discriminator 0x%"
|
|
DW_PR_XZEROS DW_PR_DUx "\n",
|
|
utmp2);
|
|
_dwarf_printf(dbg,dwarfstring_string(&mk));
|
|
dwarfstring_destructor(&mk);
|
|
}
|
|
#endif /* PRINTING_DETAILS */
|
|
}
|
|
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;
|
|
/* ptrdiff_t is generated but not named */
|
|
Dwarf_Unsigned space_left =
|
|
(line_ptr <= line_ptr_end)?
|
|
(line_ptr_end - line_ptr):0xfffffff;
|
|
|
|
/* By catching this here instead of PRINTING_DETAILS
|
|
we avoid reading off of our data of interest*/
|
|
if (instr_length < 1 ||
|
|
space_left < remaining_bytes ||
|
|
remaining_bytes > DW_LNE_LEN_MAX) {
|
|
dwarfstring g;
|
|
/* ptrdiff_t is generated but not named */
|
|
Dwarf_Unsigned localoff =
|
|
(line_ptr >= section_start)?
|
|
(line_ptr - section_start):0xfffffff;
|
|
|
|
dwarfstring_constructor(&g);
|
|
dwarfstring_append_printf_u(&g,
|
|
"DW_DLE_LINE_TABLE_BAD reading "
|
|
"unknown DW_LNE_extended op opcode 0x%x ",
|
|
ext_opcode);
|
|
dwarfstring_append_printf_u(&g,
|
|
"we are "
|
|
"off this line table at section "
|
|
"offset 0x%x and ",
|
|
localoff);
|
|
dwarfstring_append_printf_u(&g,
|
|
"instruction length "
|
|
"%u.",instr_length);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_LINE_TABLE_BAD,
|
|
dwarfstring_string(&g));
|
|
dwarfstring_destructor(&g);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
#ifdef PRINTING_DETAILS
|
|
{
|
|
dwarfstring m9d;
|
|
dwarfstring_constructor(&m9d);
|
|
dwarfstring_append_printf_u(&m9d,
|
|
"DW_LNE extended op 0x%x ",
|
|
ext_opcode);
|
|
dwarfstring_append_printf_u(&m9d,
|
|
"Bytecount: %" DW_PR_DUu ,
|
|
(Dwarf_Unsigned)instr_length);
|
|
if (remaining_bytes > 0) {
|
|
/* If remaining bytes > distance to end
|
|
we will have an error. */
|
|
dwarfstring_append(&m9d," linedata: 0x");
|
|
while (remaining_bytes > 0) {
|
|
dwarfstring_append_printf_u(&m9d,
|
|
"%02x",
|
|
(unsigned char)(*(line_ptr)));
|
|
line_ptr++;
|
|
#if 0
|
|
/* A test above (see space_left above)
|
|
proves we will not run off the end here.
|
|
The following test is too late anyway,
|
|
we might have read off the end just
|
|
before line_ptr incremented! */
|
|
if (line_ptr >= line_ptr_end) {
|
|
dwarfstring g;
|
|
/* ptrdiff_t generated but not named */
|
|
Dwarf_Unsigned localoff =
|
|
(line_ptr >= section_start)?
|
|
(line_ptr - section_start):0xfffffff;
|
|
|
|
dwarfstring_constructor(&g);
|
|
dwarfstring_append_printf_u(&g,
|
|
"DW_DLE_LINE_TABLE_BAD reading "
|
|
"DW_LNE extended op remaining bytes "
|
|
"we are "
|
|
"off this line table at section "
|
|
"offset 0x%x .",
|
|
localoff);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_LINE_TABLE_BAD,
|
|
dwarfstring_string(&g));
|
|
dwarfstring_destructor(&g);
|
|
dwarfstring_destructor(&m9d);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,
|
|
DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,
|
|
head_chain,line_count);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
#endif
|
|
remaining_bytes--;
|
|
}
|
|
}
|
|
_dwarf_printf(dbg,dwarfstring_string(&m9d));
|
|
dwarfstring_destructor(&m9d);
|
|
}
|
|
#else /* ! PRINTING_DETAILS */
|
|
line_ptr += remaining_bytes;
|
|
if (line_ptr > line_ptr_end) {
|
|
dwarfstring g;
|
|
/* ptrdiff_t generated but not named */
|
|
Dwarf_Unsigned localoff =
|
|
(line_ptr >= section_start)?
|
|
(line_ptr - section_start):0xfffffff;
|
|
|
|
dwarfstring_constructor(&g);
|
|
dwarfstring_append_printf_u(&g,
|
|
"DW_DLE_LINE_TABLE_BAD reading "
|
|
"DW_LNE extended op remaining bytes "
|
|
"we are "
|
|
"off this line table at section "
|
|
"offset 0x%x .",
|
|
localoff);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_LINE_TABLE_BAD,
|
|
dwarfstring_string(&g));
|
|
dwarfstring_destructor(&g);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
}
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
#endif /* PRINTING_DETAILS */
|
|
_dwarf_printf(dbg,"\n");
|
|
}
|
|
break;
|
|
} /* End switch. */
|
|
} else {
|
|
/* ASSERT: impossible, see the macro definition */
|
|
_dwarf_free_chain_entries(dbg,head_chain,
|
|
line_count);
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_LINE_TABLE_BAD,
|
|
"DW_DLE_LINE_TABLE_BAD: Actually is "
|
|
"an impossible type from WHAT_IS_CODE");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
block_line = (Dwarf_Line *)
|
|
_dwarf_get_alloc(dbg, DW_DLA_LIST, line_count);
|
|
if (block_line == NULL) {
|
|
curr_chain = head_chain;
|
|
_dwarf_free_chain_entries(dbg,head_chain,line_count);
|
|
if (curr_line) {
|
|
dwarf_dealloc(dbg,curr_line,DW_DLA_LINE);
|
|
curr_line = 0;
|
|
}
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
curr_chain = head_chain;
|
|
for (i = 0; i < line_count; i++) {
|
|
Dwarf_Chain t = 0;
|
|
*(block_line + i) = curr_chain->ch_item;
|
|
curr_chain->ch_item = 0;
|
|
curr_chain->ch_itemtype = 0;
|
|
t = curr_chain;
|
|
curr_chain = curr_chain->ch_next;
|
|
dwarf_dealloc(dbg, t, DW_DLA_CHAIN);
|
|
}
|
|
|
|
if (is_single_table || !is_actuals_table) {
|
|
line_context->lc_linebuf_logicals = block_line;
|
|
line_context->lc_linecount_logicals = line_count;
|
|
} else {
|
|
line_context->lc_linebuf_actuals = block_line;
|
|
line_context->lc_linecount_actuals = line_count;
|
|
}
|
|
#ifdef PRINTING_DETAILS
|
|
{
|
|
dwarfstring mc;
|
|
dwarfstring_constructor(&mc);
|
|
if (is_single_table) {
|
|
if (!line_count) {
|
|
dwarfstring_append_printf_u(&mc,
|
|
" Line table is present (offset 0x%"
|
|
DW_PR_XZEROS DW_PR_DUx
|
|
") but no lines present\n",
|
|
line_context->lc_section_offset);
|
|
}
|
|
} else if (is_actuals_table) {
|
|
if (!line_count) {
|
|
dwarfstring_append_printf_u(&mc,
|
|
" Line table present (offset 0x%"
|
|
DW_PR_XZEROS DW_PR_DUx
|
|
") but no actuals lines present\n",
|
|
line_context->lc_section_offset);
|
|
}
|
|
} else {
|
|
if (!line_count) {
|
|
dwarfstring_append_printf_u(&mc,
|
|
" Line table present (offset 0x%"
|
|
DW_PR_XZEROS DW_PR_DUx
|
|
") but no logicals lines present\n",
|
|
line_context->lc_section_offset);
|
|
}
|
|
}
|
|
if (dwarfstring_strlen(&mc)) {
|
|
_dwarf_printf(dbg,dwarfstring_string(&mc));
|
|
}
|
|
dwarfstring_destructor(&mc);
|
|
}
|
|
#endif /* PRINTING_DETAILS */
|
|
return DW_DLV_OK;
|
|
}
|