#include "config.h"
#include "dwarf_incl.h"
#include <stdio.h>
#include <stdlib.h>
#include "dwarf_line.h"
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
int
dwarf_srcfiles(Dwarf_Die die,
char ***srcfiles,
Dwarf_Signed * srcfilecount, Dwarf_Error * error)
{
Dwarf_Small *line_ptr;
Dwarf_Attribute stmt_list_attr;
Dwarf_Attribute comp_dir_attr;
Dwarf_Small *comp_dir = 0;
Dwarf_Unsigned line_offset = 0;
char **ret_files = 0;
Dwarf_Debug dbg = 0;
Dwarf_Chain curr_chain, prev_chain, head_chain = NULL;
int resattr = 0;
int lres = 0;
struct Line_Table_Prefix_s line_prefix;
int i = 0;
int res = 0;
if (error != NULL)
*error = NULL;
CHECK_DIE(die, DW_DLV_ERROR)
dbg = die->di_cu_context->cc_dbg;
resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
if (resattr != DW_DLV_OK) {
return resattr;
}
if (dbg->de_debug_line_index == 0) {
_dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_NULL);
return (DW_DLV_ERROR);
}
res =
_dwarf_load_section(dbg,
dbg->de_debug_line_index,
&dbg->de_debug_line, error);
if (res != DW_DLV_OK) {
return res;
}
lres = dwarf_formudata(stmt_list_attr, &line_offset, error);
if (lres != DW_DLV_OK) {
return lres;
}
if (line_offset >= dbg->de_debug_line_size) {
_dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
return (DW_DLV_ERROR);
}
line_ptr = dbg->de_debug_line + line_offset;
dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);
resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
if (resattr == DW_DLV_ERROR) {
return resattr;
}
if (resattr == DW_DLV_OK) {
int cres;
char *cdir;
cres = dwarf_formstring(comp_dir_attr, &cdir, error);
if (cres == DW_DLV_ERROR) {
return cres;
} else if (cres == DW_DLV_OK) {
comp_dir = (Dwarf_Small *) cdir;
}
}
if (resattr == DW_DLV_OK) {
dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
}
dwarf_init_line_table_prefix(&line_prefix);
{
Dwarf_Small *line_ptr_out = 0;
int dres = dwarf_read_line_table_prefix(dbg,
line_ptr,
dbg->de_debug_line_size,
&line_ptr_out,
&line_prefix, error);
if (dres == DW_DLV_ERROR)
return dres;
if (dres == DW_DLV_NO_ENTRY) {
dwarf_free_line_table_prefix(&line_prefix);
return dres;
}
line_ptr = line_ptr_out;
}
for (i = 0; i < line_prefix.pf_files_count; ++i) {
struct Line_Table_File_Entry_s *fe =
line_prefix.pf_line_table_file_entries + i;
char *file_name = (char *) fe->lte_filename;
char *dir_name = 0;
char *full_name = 0;
Dwarf_Unsigned dir_index = fe->lte_directory_index;
if (dir_index == 0) {
dir_name = (char *) comp_dir;
} else {
dir_name =
(char *) line_prefix.pf_include_directories[fe->
lte_directory_index
- 1];
}
if ((*file_name) == '/' || dir_name == 0) {
full_name = file_name;
} else {
full_name = (char *) _dwarf_get_alloc(dbg, DW_DLA_STRING,
strlen(dir_name) + 1 +
strlen(file_name) +
1);
if (full_name == NULL) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
strcpy(full_name, dir_name);
strcat(full_name, "/");
strcat(full_name, file_name);
}
curr_chain =
(Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if (curr_chain == NULL) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
curr_chain->ch_item = full_name;
if (head_chain == NULL)
head_chain = prev_chain = curr_chain;
else {
prev_chain->ch_next = curr_chain;
prev_chain = curr_chain;
}
}
curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if (curr_chain == NULL) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
if (line_prefix.pf_files_count == 0) {
*srcfiles = NULL;
*srcfilecount = 0;
return (DW_DLV_NO_ENTRY);
}
ret_files = (char **)
_dwarf_get_alloc(dbg, DW_DLA_LIST, line_prefix.pf_files_count);
if (ret_files == NULL) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
curr_chain = head_chain;
for (i = 0; i < line_prefix.pf_files_count; i++) {
*(ret_files + i) = curr_chain->ch_item;
prev_chain = curr_chain;
curr_chain = curr_chain->ch_next;
dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
}
*srcfiles = ret_files;
*srcfilecount = line_prefix.pf_files_count;
return (DW_DLV_OK);
}
int
_dwarf_internal_srclines(Dwarf_Die die,
Dwarf_Line ** linebuf,
Dwarf_Signed * count,
Dwarf_Bool doaddrs,
Dwarf_Bool dolines, Dwarf_Error * error)
{
Dwarf_Small *line_ptr;
Dwarf_Small *line_ptr_end;
Dwarf_Attribute stmt_list_attr;
Dwarf_Attribute comp_dir_attr;
Dwarf_Small *comp_dir = NULL;
Dwarf_Unsigned line_offset;
Dwarf_File_Entry file_entries;
Dwarf_Addr address = 0;
Dwarf_Word file = 1;
Dwarf_Word line = 1;
Dwarf_Word column = 0;
Dwarf_Bool is_stmt = false;
Dwarf_Bool basic_block = false;
Dwarf_Bool prologue_end = false;
Dwarf_Bool epilogue_begin = false;
Dwarf_Small isa = 0;
Dwarf_Bool end_sequence = false;
Dwarf_File_Entry cur_file_entry, prev_file_entry;
Dwarf_Sword i = 0;
Dwarf_Sword file_entry_count = 0;
Dwarf_Small opcode;
Dwarf_Line_Context line_context;
Dwarf_Line curr_line;
Dwarf_Word leb128_num;
Dwarf_Word leb128_length;
Dwarf_Sword advance_line;
Dwarf_Half fixed_advance_pc;
Dwarf_Sword line_count = 0;
Dwarf_Word instr_length;
Dwarf_Small ext_opcode;
struct Line_Table_Prefix_s prefix;
Dwarf_Chain chain_line, head_chain = NULL, curr_chain;
Dwarf_Line *block_line;
Dwarf_Debug dbg;
int resattr;
int lres;
int res;
if (error != NULL)
*error = NULL;
CHECK_DIE(die, DW_DLV_ERROR)
dbg = die->di_cu_context->cc_dbg;
res =
_dwarf_load_section(dbg,
dbg->de_debug_line_index,
&dbg->de_debug_line, error);
if (res != DW_DLV_OK) {
return res;
}
resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
if (resattr != DW_DLV_OK) {
return resattr;
}
lres = dwarf_formudata(stmt_list_attr, &line_offset, error);
if (lres != DW_DLV_OK) {
return lres;
}
if (line_offset >= dbg->de_debug_line_size) {
_dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
return (DW_DLV_ERROR);
}
line_ptr = dbg->de_debug_line + line_offset;
dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);
resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
if (resattr == DW_DLV_ERROR) {
return resattr;
}
if (resattr == DW_DLV_OK) {
int cres;
char *cdir;
cres = dwarf_formstring(comp_dir_attr, &cdir, error);
if (cres == DW_DLV_ERROR) {
return cres;
} else if (cres == DW_DLV_OK) {
comp_dir = (Dwarf_Small *) cdir;
}
}
if (resattr == DW_DLV_OK) {
dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
}
dwarf_init_line_table_prefix(&prefix);
{
Dwarf_Small *newlinep = 0;
int res = dwarf_read_line_table_prefix(dbg,
line_ptr,
dbg->de_debug_line_size,
&newlinep,
&prefix,
error);
if (res == DW_DLV_ERROR) {
dwarf_free_line_table_prefix(&prefix);
return res;
}
if (res == DW_DLV_NO_ENTRY) {
dwarf_free_line_table_prefix(&prefix);
return res;
}
line_ptr_end = prefix.pf_line_ptr_end;
line_ptr = newlinep;
}
line_context = (Dwarf_Line_Context)
_dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1);
if (line_context == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
file_entries = prev_file_entry = NULL;
for (i = 0; i < prefix.pf_files_count; ++i) {
struct Line_Table_File_Entry_s *pfxfile =
prefix.pf_line_table_file_entries + i;
cur_file_entry = (Dwarf_File_Entry)
_dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
if (cur_file_entry == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
cur_file_entry->fi_file_name = pfxfile->lte_filename;
cur_file_entry->fi_dir_index = pfxfile->lte_directory_index;
cur_file_entry->fi_time_last_mod =
pfxfile->lte_last_modification_time;
cur_file_entry->fi_file_length = pfxfile->lte_length_of_file;
if (file_entries == NULL)
file_entries = cur_file_entry;
else
prev_file_entry->fi_next = cur_file_entry;
prev_file_entry = cur_file_entry;
file_entry_count++;
}
is_stmt = prefix.pf_default_is_stmt;
while (line_ptr < line_ptr_end) {
int type;
opcode = *(Dwarf_Small *) line_ptr;
line_ptr++;
WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base,
prefix.pf_opcode_length_table, line_ptr,
prefix.pf_std_op_count);
if (type == LOP_DISCARD) {
int oc;
int opcnt = prefix.pf_opcode_length_table[opcode];
for (oc = 0; oc < opcnt; oc++) {
Dwarf_Unsigned utmp2;
DECODE_LEB128_UWORD(line_ptr, utmp2)
}
} else if (type == LOP_SPECIAL) {
opcode = opcode - prefix.pf_opcode_base;
address = address + prefix.pf_minimum_instruction_length *
(opcode / prefix.pf_line_range);
line =
line + prefix.pf_line_base +
opcode % prefix.pf_line_range;
if (dolines) {
curr_line =
(Dwarf_Line) _dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
if (curr_line == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
curr_line->li_address = address;
curr_line->li_addr_line.li_l_data.li_file =
(Dwarf_Sword) file;
curr_line->li_addr_line.li_l_data.li_line =
(Dwarf_Sword) line;
curr_line->li_addr_line.li_l_data.li_column =
(Dwarf_Half) column;
curr_line->li_addr_line.li_l_data.li_is_stmt = is_stmt;
curr_line->li_addr_line.li_l_data.li_basic_block =
basic_block;
curr_line->li_addr_line.li_l_data.li_end_sequence =
curr_line->li_addr_line.li_l_data.
li_epilogue_begin = epilogue_begin;
curr_line->li_addr_line.li_l_data.li_prologue_end =
prologue_end;
curr_line->li_addr_line.li_l_data.li_isa = isa;
curr_line->li_context = line_context;
line_count++;
chain_line = (Dwarf_Chain)
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if (chain_line == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
chain_line->ch_item = curr_line;
if (head_chain == NULL)
head_chain = curr_chain = chain_line;
else {
curr_chain->ch_next = chain_line;
curr_chain = chain_line;
}
}
basic_block = false;
} else if (type == LOP_STANDARD) {
switch (opcode) {
case DW_LNS_copy:{
if (dolines) {
curr_line =
(Dwarf_Line) _dwarf_get_alloc(dbg,
DW_DLA_LINE,
1);
if (curr_line == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
curr_line->li_address = address;
curr_line->li_addr_line.li_l_data.li_file =
(Dwarf_Sword) file;
curr_line->li_addr_line.li_l_data.li_line =
(Dwarf_Sword) line;
curr_line->li_addr_line.li_l_data.li_column =
(Dwarf_Half) column;
curr_line->li_addr_line.li_l_data.li_is_stmt =
is_stmt;
curr_line->li_addr_line.li_l_data.
li_basic_block = basic_block;
curr_line->li_addr_line.li_l_data.
li_end_sequence = end_sequence;
curr_line->li_context = line_context;
curr_line->li_addr_line.li_l_data.
li_epilogue_begin = epilogue_begin;
curr_line->li_addr_line.li_l_data.
li_prologue_end = prologue_end;
curr_line->li_addr_line.li_l_data.li_isa = isa;
line_count++;
chain_line = (Dwarf_Chain)
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if (chain_line == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
chain_line->ch_item = curr_line;
if (head_chain == NULL)
head_chain = curr_chain = chain_line;
else {
curr_chain->ch_next = chain_line;
curr_chain = chain_line;
}
}
basic_block = false;
prologue_end = false;
epilogue_begin = false;
break;
}
case DW_LNS_advance_pc:{
Dwarf_Unsigned utmp2;
DECODE_LEB128_UWORD(line_ptr, utmp2)
leb128_num = (Dwarf_Word) utmp2;
address =
address +
prefix.pf_minimum_instruction_length *
leb128_num;
break;
}
case DW_LNS_advance_line:{
Dwarf_Signed stmp;
DECODE_LEB128_SWORD(line_ptr, stmp)
advance_line = (Dwarf_Sword) stmp;
line = line + advance_line;
break;
}
case DW_LNS_set_file:{
Dwarf_Unsigned utmp2;
DECODE_LEB128_UWORD(line_ptr, utmp2)
file = (Dwarf_Word) utmp2;
break;
}
case DW_LNS_set_column:{
Dwarf_Unsigned utmp2;
DECODE_LEB128_UWORD(line_ptr, utmp2)
column = (Dwarf_Word) utmp2;
break;
}
case DW_LNS_negate_stmt:{
is_stmt = !is_stmt;
break;
}
case DW_LNS_set_basic_block:{
basic_block = true;
break;
}
case DW_LNS_const_add_pc:{
opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base;
address =
address +
prefix.pf_minimum_instruction_length * (opcode /
prefix.
pf_line_range);
break;
}
case DW_LNS_fixed_advance_pc:{
READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
line_ptr, sizeof(Dwarf_Half));
line_ptr += sizeof(Dwarf_Half);
address = address + fixed_advance_pc;
break;
}
case DW_LNS_set_prologue_end:{
prologue_end = true;
break;
}
case DW_LNS_set_epilogue_begin:{
epilogue_begin = true;
break;
}
case DW_LNS_set_isa:{
Dwarf_Unsigned utmp2;
DECODE_LEB128_UWORD(line_ptr, utmp2)
isa = utmp2;
if (isa != utmp2) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error,
DW_DLE_LINE_NUM_OPERANDS_BAD);
return (DW_DLV_ERROR);
}
break;
}
}
} else if (type == LOP_EXTENDED) {
Dwarf_Unsigned utmp3;
DECODE_LEB128_UWORD(line_ptr, utmp3)
instr_length = (Dwarf_Word) utmp3;
ext_opcode = *(Dwarf_Small *) line_ptr;
line_ptr++;
switch (ext_opcode) {
case DW_LNE_end_sequence:{
end_sequence = true;
if (dolines) {
curr_line = (Dwarf_Line)
_dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
if (curr_line == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
curr_line->li_address = address;
curr_line->li_addr_line.li_l_data.li_file =
(Dwarf_Sword) file;
curr_line->li_addr_line.li_l_data.li_line =
(Dwarf_Sword) line;
curr_line->li_addr_line.li_l_data.li_column =
(Dwarf_Half) column;
curr_line->li_addr_line.li_l_data.li_is_stmt =
prefix.pf_default_is_stmt;
curr_line->li_addr_line.li_l_data.
li_basic_block = basic_block;
curr_line->li_addr_line.li_l_data.
li_end_sequence = end_sequence;
curr_line->li_context = line_context;
curr_line->li_addr_line.li_l_data.
li_epilogue_begin = epilogue_begin;
curr_line->li_addr_line.li_l_data.
li_prologue_end = prologue_end;
curr_line->li_addr_line.li_l_data.li_isa = isa;
line_count++;
chain_line = (Dwarf_Chain)
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if (chain_line == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
chain_line->ch_item = curr_line;
if (head_chain == NULL)
head_chain = curr_chain = chain_line;
else {
curr_chain->ch_next = chain_line;
curr_chain = chain_line;
}
}
address = 0;
file = 1;
line = 1;
column = 0;
is_stmt = prefix.pf_default_is_stmt;
basic_block = false;
end_sequence = false;
prologue_end = false;
epilogue_begin = false;
break;
}
case DW_LNE_set_address:{
if (instr_length - 1 == dbg->de_pointer_size) {
READ_UNALIGNED(dbg, address, Dwarf_Addr,
line_ptr, dbg->de_pointer_size);
if (doaddrs) {
curr_line =
(Dwarf_Line) _dwarf_get_alloc(dbg,
DW_DLA_LINE,
1);
if (curr_line == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error,
DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
curr_line->li_address = address;
curr_line->li_addr_line.li_offset =
line_ptr - dbg->de_debug_line;
line_count++;
chain_line = (Dwarf_Chain)
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if (chain_line == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error,
DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
chain_line->ch_item = curr_line;
if (head_chain == NULL)
head_chain = curr_chain = chain_line;
else {
curr_chain->ch_next = chain_line;
curr_chain = chain_line;
}
}
line_ptr += dbg->de_pointer_size;
} else {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error,
DW_DLE_LINE_SET_ADDR_ERROR);
return (DW_DLV_ERROR);
}
break;
}
case DW_LNE_define_file:{
if (dolines) {
cur_file_entry = (Dwarf_File_Entry)
_dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
if (cur_file_entry == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
cur_file_entry->fi_file_name =
(Dwarf_Small *) line_ptr;
line_ptr =
line_ptr + strlen((char *) line_ptr) + 1;
cur_file_entry->fi_dir_index = (Dwarf_Sword)
_dwarf_decode_u_leb128(line_ptr,
&leb128_length);
line_ptr = line_ptr + leb128_length;
cur_file_entry->fi_time_last_mod =
_dwarf_decode_u_leb128(line_ptr,
&leb128_length);
line_ptr = line_ptr + leb128_length;
cur_file_entry->fi_file_length =
_dwarf_decode_u_leb128(line_ptr,
&leb128_length);
line_ptr = line_ptr + leb128_length;
if (file_entries == NULL)
file_entries = cur_file_entry;
else
prev_file_entry->fi_next = cur_file_entry;
prev_file_entry = cur_file_entry;
file_entry_count++;
}
break;
}
default:{
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error,
DW_DLE_LINE_EXT_OPCODE_BAD);
return (DW_DLV_ERROR);
}
}
}
}
block_line = (Dwarf_Line *)
_dwarf_get_alloc(dbg, DW_DLA_LIST, line_count);
if (block_line == NULL) {
dwarf_free_line_table_prefix(&prefix);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
curr_chain = head_chain;
for (i = 0; i < line_count; i++) {
*(block_line + i) = curr_chain->ch_item;
head_chain = curr_chain;
curr_chain = curr_chain->ch_next;
dwarf_dealloc(dbg, head_chain, DW_DLA_CHAIN);
}
line_context->lc_file_entries = file_entries;
line_context->lc_file_entry_count = file_entry_count;
line_context->lc_include_directories_count =
prefix.pf_include_directories_count;
if (prefix.pf_include_directories_count > 0) {
line_context->lc_include_directories =
prefix.pf_include_directories[0];
}
line_context->lc_line_count = line_count;
line_context->lc_compilation_directory = comp_dir;
line_context->lc_version_number = prefix.pf_version;
line_context->lc_dbg = dbg;
*count = line_count;
*linebuf = block_line;
dwarf_free_line_table_prefix(&prefix);
return (DW_DLV_OK);
}
int
dwarf_srclines(Dwarf_Die die,
Dwarf_Line ** linebuf,
Dwarf_Signed * linecount, Dwarf_Error * error)
{
Dwarf_Signed count;
int res;
res = _dwarf_internal_srclines(die, linebuf, &count, false,
true, error);
if (res != DW_DLV_OK) {
return res;
}
*linecount = count;
return res;
}
int
dwarf_linebeginstatement(Dwarf_Line line,
Dwarf_Bool * return_bool, Dwarf_Error * error)
{
if (line == NULL || return_bool == 0) {
_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
return (DW_DLV_ERROR);
}
*return_bool = (line->li_addr_line.li_l_data.li_is_stmt);
return DW_DLV_OK;
}
int
dwarf_lineendsequence(Dwarf_Line line,
Dwarf_Bool * return_bool, Dwarf_Error * error)
{
if (line == NULL) {
_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
return (DW_DLV_ERROR);
}
*return_bool = (line->li_addr_line.li_l_data.li_end_sequence);
return DW_DLV_OK;
}
int
dwarf_lineno(Dwarf_Line line,
Dwarf_Unsigned * ret_lineno, Dwarf_Error * error)
{
if (line == NULL || ret_lineno == 0) {
_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
return (DW_DLV_ERROR);
}
*ret_lineno = (line->li_addr_line.li_l_data.li_line);
return DW_DLV_OK;
}
int
dwarf_line_srcfileno(Dwarf_Line line,
Dwarf_Unsigned * ret_fileno, Dwarf_Error * error)
{
if (line == NULL || ret_fileno == 0) {
_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
return (DW_DLV_ERROR);
}
*ret_fileno = (line->li_addr_line.li_l_data.li_file);
return DW_DLV_OK;
}
int
dwarf_lineaddr(Dwarf_Line line,
Dwarf_Addr * ret_lineaddr, Dwarf_Error * error)
{
if (line == NULL || ret_lineaddr == 0) {
_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
return (DW_DLV_ERROR);
}
*ret_lineaddr = (line->li_address);
return DW_DLV_OK;
}
int
dwarf_lineoff(Dwarf_Line line,
Dwarf_Signed * ret_lineoff, Dwarf_Error * error)
{
if (line == NULL || ret_lineoff == 0) {
_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
return (DW_DLV_ERROR);
}
*ret_lineoff =
(line->li_addr_line.li_l_data.li_column ==
0 ? -1 : line->li_addr_line.li_l_data.li_column);
return DW_DLV_OK;
}
int
dwarf_linesrc(Dwarf_Line line, char **ret_linesrc, Dwarf_Error * error)
{
Dwarf_Signed i;
Dwarf_File_Entry file_entry;
Dwarf_Small *name_buffer;
Dwarf_Small *include_directories;
Dwarf_Debug dbg;
unsigned int comp_dir_len;
if (line == NULL) {
_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
return (DW_DLV_ERROR);
}
if (line->li_context == NULL) {
_dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_NULL);
return (DW_DLV_ERROR);
}
dbg = line->li_context->lc_dbg;
if (line->li_addr_line.li_l_data.li_file >
line->li_context->lc_file_entry_count) {
_dwarf_error(dbg, error, DW_DLE_LINE_FILE_NUM_BAD);
return (DW_DLV_ERROR);
}
if (line->li_addr_line.li_l_data.li_file == 0) {
_dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME);
return (DW_DLV_ERROR);
}
file_entry = line->li_context->lc_file_entries;
for (i = line->li_addr_line.li_l_data.li_file - 1; i > 0; i--)
file_entry = file_entry->fi_next;
if (file_entry->fi_file_name == NULL) {
_dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME);
return (DW_DLV_ERROR);
}
if (*(char *) file_entry->fi_file_name == '/') {
*ret_linesrc = ((char *) file_entry->fi_file_name);
return DW_DLV_OK;
}
if (file_entry->fi_dir_index == 0) {
if (line->li_context->lc_compilation_directory == NULL) {
comp_dir_len = 0;
} else {
comp_dir_len = strlen((char *)
(line->li_context->
lc_compilation_directory));
}
name_buffer =
_dwarf_get_alloc(line->li_context->lc_dbg, DW_DLA_STRING,
comp_dir_len + 1 +
strlen((char *) file_entry->fi_file_name) +
1);
if (name_buffer == NULL) {
_dwarf_error(line->li_context->lc_dbg, error,
DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
if (comp_dir_len > 0) {
strcpy((char *) name_buffer,
(char *) (line->li_context->
lc_compilation_directory));
strcat((char *) name_buffer, "/");
}
strcat((char *) name_buffer, (char *) file_entry->fi_file_name);
*ret_linesrc = ((char *) name_buffer);
return DW_DLV_OK;
}
if (file_entry->fi_dir_index >
line->li_context->lc_include_directories_count) {
_dwarf_error(dbg, error, DW_DLE_INCL_DIR_NUM_BAD);
return (DW_DLV_ERROR);
}
include_directories = line->li_context->lc_include_directories;
for (i = file_entry->fi_dir_index - 1; i > 0; i--)
include_directories += strlen((char *) include_directories) + 1;
if (line->li_context->lc_compilation_directory) {
comp_dir_len = strlen((char *)
(line->li_context->
lc_compilation_directory));
} else {
comp_dir_len = 0;
}
name_buffer = _dwarf_get_alloc(dbg, DW_DLA_STRING,
(*include_directories == '/' ?
0 : comp_dir_len + 1) +
strlen((char *) include_directories)
+ 1 +
strlen((char *) file_entry->
fi_file_name) + 1);
if (name_buffer == NULL) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
if (*include_directories != '/') {
if (comp_dir_len > 0) {
strcpy((char *) name_buffer,
(char *) line->li_context->lc_compilation_directory);
if (name_buffer[comp_dir_len - 1] != '/') {
name_buffer[comp_dir_len] = '/';
name_buffer[comp_dir_len + 1] = 0;
}
}
} else {
strcpy((char *) name_buffer, "");
}
strcat((char *) name_buffer, (char *) include_directories);
strcat((char *) name_buffer, "/");
strcat((char *) name_buffer, (char *) file_entry->fi_file_name);
*ret_linesrc = ((char *) name_buffer);
return DW_DLV_OK;
}
int
dwarf_lineblock(Dwarf_Line line,
Dwarf_Bool * return_bool, Dwarf_Error * error)
{
if (line == NULL) {
_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
return (DW_DLV_ERROR);
}
*return_bool = (line->li_addr_line.li_l_data.li_basic_block);
return DW_DLV_OK;
}
#if 0
int
dwarf_pclines(Dwarf_Debug dbg,
Dwarf_Addr pc,
Dwarf_Line ** linebuf,
Dwarf_Signed slide,
Dwarf_Signed * linecount, Dwarf_Error * error)
{
Dwarf_Line line;
Dwarf_Line prev_line;
Dwarf_Bool check_line, first_line;
Dwarf_Signed diff, i;
Dwarf_Addr pc_less, pc_more;
Dwarf_Line *pc_line_buf, *pc_line;
Dwarf_Signed chain_count;
chain_head = NULL;
check_line = true;
first_line = true;
diff = MAX_LINE_DIFF;
for (i = 0; i < dbg->de_cu_line_count; i++) {
line = *(dbg->de_cu_line_ptr + i);
prev_line = first_line ? NULL : *(dbg->de_cu_line_ptr + i - 1);
if (line->li_address == pc) {
chain_ptr = (struct chain *)
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if (chain_ptr == NULL) {
_dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
chain_ptr->line = line;
chain_ptr->diff = diff = 0;
chain_ptr->next = chain_head;
chain_head = chain_ptr;
} else
if (check_line && line->li_address > pc &&
(first_line ? 0 : prev_line->li_address) < pc)
if (slide == DW_DLS_BACKWARD && !first_line) {
pc_less = prev_line->li_address;
if (pc - pc_less <= diff) {
chain_ptr = (struct chain *)
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if (chain_ptr == NULL) {
_dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
chain_ptr->line = prev_line;
chain_ptr->diff = diff = pc - pc_less;
chain_ptr->next = chain_head;
chain_head = chain_ptr;
}
check_line = false;
} else if (slide == DW_DLS_FORWARD) {
pc_more = line->li_address;
if (pc_more - pc <= diff) {
chain_ptr = (struct chain *)
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if (chain_ptr == NULL) {
_dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
chain_ptr->line = line;
chain_ptr->diff = diff = pc_more - pc;
chain_ptr->next = chain_head;
chain_head = chain_ptr;
}
check_line = false;
} else
if (line->li_address < pc)
check_line = true;
first_line = false;
}
chain_count = 0;
for (chain_ptr = chain_head; chain_ptr != NULL;
chain_ptr = chain_ptr->next)
if (chain_ptr->diff == diff)
chain_count++;
pc_line_buf = pc_line = (Dwarf_Line)
_dwarf_get_alloc(dbg, DW_DLA_LIST, chain_count);
for (chain_ptr = chain_head; chain_ptr != NULL;
chain_ptr = chain_ptr->next)
if (chain_ptr->diff == diff) {
*pc_line = chain_ptr->line;
pc_line++;
}
for (chain_ptr = chain_head; chain_ptr != NULL;) {
chain_head = chain_ptr;
chain_ptr = chain_ptr->next;
dwarf_dealloc(dbg, chain_head, DW_DLA_CHAIN);
}
*linebuf = pc_line_buf;
return (chain_count);
}
#endif
void
dwarf_srclines_dealloc(Dwarf_Debug dbg, Dwarf_Line * linebuf,
Dwarf_Signed count)
{
Dwarf_Signed i = 0;
struct Dwarf_Line_Context_s *context = 0;
if (count > 0) {
context = linebuf[0]->li_context;
}
for (i = 0; i < count; ++i) {
dwarf_dealloc(dbg, linebuf[i], DW_DLA_LINE);
}
dwarf_dealloc(dbg, linebuf, DW_DLA_LIST);
if (context) {
Dwarf_File_Entry fe = context->lc_file_entries;
while (fe) {
Dwarf_File_Entry fenext = fe->fi_next;
dwarf_dealloc(dbg, fe, DW_DLA_FILE_ENTRY);
fe = fenext;
}
dwarf_dealloc(dbg, context, DW_DLA_LINE_CONTEXT);
}
return;
}
#define STANDARD_OPERAND_COUNT_DWARF2 9
#define STANDARD_OPERAND_COUNT_DWARF3 12
static unsigned char
dwarf_standard_opcode_operand_count[STANDARD_OPERAND_COUNT_DWARF3] = {
0,
1, 1, 1, 1,
0, 0, 0,
1,
0, 0, 1
};
int
dwarf_read_line_table_prefix(Dwarf_Debug dbg,
Dwarf_Small * data_start,
Dwarf_Unsigned data_length,
Dwarf_Small ** updated_data_start_out,
struct Line_Table_Prefix_s *prefix_out,
Dwarf_Error * err)
{
Dwarf_Small *line_ptr = data_start;
Dwarf_Unsigned total_length = 0;
int local_length_size = 0;
int local_extension_size = 0;
Dwarf_Unsigned prologue_length = 0;
Dwarf_Half version = 0;
Dwarf_Unsigned directories_count = 0;
Dwarf_Unsigned directories_malloc = 0;
Dwarf_Unsigned files_count = 0;
Dwarf_Unsigned files_malloc = 0;
Dwarf_Small *line_ptr_end = 0;
prefix_out->pf_line_ptr_start = line_ptr;
READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned,
line_ptr, local_length_size, local_extension_size);
line_ptr_end = line_ptr + total_length;
prefix_out->pf_line_ptr_end = line_ptr_end;
prefix_out->pf_length_field_length = local_length_size +
local_extension_size;
if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) {
_dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
return (DW_DLV_ERROR);
}
if (line_ptr_end > data_start + data_length) {
_dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
return (DW_DLV_ERROR);
}
prefix_out->pf_total_length = total_length;
READ_UNALIGNED(dbg, version, Dwarf_Half,
line_ptr, sizeof(Dwarf_Half));
prefix_out->pf_version = version;
line_ptr += sizeof(Dwarf_Half);
if (version != CURRENT_VERSION_STAMP &&
version != CURRENT_VERSION_STAMP3) {
_dwarf_error(dbg, err, DW_DLE_VERSION_STAMP_ERROR);
return (DW_DLV_ERROR);
}
READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned,
line_ptr, local_length_size);
prefix_out->pf_prologue_length = prologue_length;
line_ptr += local_length_size;
prefix_out->pf_line_prologue_start = line_ptr;
prefix_out->pf_minimum_instruction_length =
*(unsigned char *) line_ptr;
line_ptr = line_ptr + sizeof(Dwarf_Small);
prefix_out->pf_default_is_stmt = *(unsigned char *) line_ptr;
line_ptr = line_ptr + sizeof(Dwarf_Small);
prefix_out->pf_line_base = *(signed char *) line_ptr;
line_ptr = line_ptr + sizeof(Dwarf_Sbyte);
prefix_out->pf_line_range = *(unsigned char *) line_ptr;
line_ptr = line_ptr + sizeof(Dwarf_Small);
prefix_out->pf_opcode_base = *(unsigned char *) line_ptr;
line_ptr = line_ptr + sizeof(Dwarf_Small);
prefix_out->pf_opcode_length_table = line_ptr;
line_ptr += prefix_out->pf_opcode_base - 1;
{
int operand_ck_fail = true;
if (prefix_out->pf_opcode_base >= STANDARD_OPERAND_COUNT_DWARF3) {
int mismatch = memcmp(dwarf_standard_opcode_operand_count,
prefix_out->pf_opcode_length_table,
STANDARD_OPERAND_COUNT_DWARF3);
if (!mismatch) {
operand_ck_fail = false;
prefix_out->pf_std_op_count =
STANDARD_OPERAND_COUNT_DWARF3;
}
}
if (operand_ck_fail) {
if (prefix_out->pf_opcode_base >=
STANDARD_OPERAND_COUNT_DWARF2) {
int mismatch =
memcmp(dwarf_standard_opcode_operand_count,
prefix_out->pf_opcode_length_table,
STANDARD_OPERAND_COUNT_DWARF2);
if (!mismatch) {
operand_ck_fail = false;
prefix_out->pf_std_op_count =
STANDARD_OPERAND_COUNT_DWARF2;
}
}
}
if (operand_ck_fail) {
_dwarf_error(dbg, err, DW_DLE_LINE_NUM_OPERANDS_BAD);
return (DW_DLV_ERROR);
}
}
directories_count = 0;
directories_malloc = 5;
prefix_out->pf_include_directories = malloc(sizeof(Dwarf_Small *) *
directories_malloc);
if (prefix_out->pf_include_directories == NULL) {
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
memset(prefix_out->pf_include_directories, 0,
sizeof(Dwarf_Small *) * directories_malloc);
while ((*(char *) line_ptr) != '\0') {
if (directories_count >= directories_malloc) {
Dwarf_Unsigned expand = 2 * directories_malloc;
Dwarf_Unsigned bytesalloc = sizeof(Dwarf_Small *) * expand;
Dwarf_Small **newdirs =
realloc(prefix_out->pf_include_directories,
bytesalloc);
if (!newdirs) {
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
memset(newdirs + directories_malloc, 0,
sizeof(Dwarf_Small *) * directories_malloc);
directories_malloc = expand;
prefix_out->pf_include_directories = newdirs;
}
prefix_out->pf_include_directories[directories_count] =
line_ptr;
line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
directories_count++;
}
prefix_out->pf_include_directories_count = directories_count;
line_ptr++;
files_count = 0;
files_malloc = 5;
prefix_out->pf_line_table_file_entries =
malloc(sizeof(struct Line_Table_File_Entry_s) * files_malloc);
if (prefix_out->pf_line_table_file_entries == NULL) {
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
memset(prefix_out->pf_line_table_file_entries, 0,
sizeof(struct Line_Table_File_Entry_s) * files_malloc);
while (*(char *) line_ptr != '\0') {
Dwarf_Unsigned utmp;
Dwarf_Unsigned dir_index = 0;
Dwarf_Unsigned lastmod = 0;
Dwarf_Unsigned file_length = 0;
struct Line_Table_File_Entry_s *curline;
Dwarf_Word leb128_length = 0;
if (files_count >= files_malloc) {
Dwarf_Unsigned expand = 2 * files_malloc;
struct Line_Table_File_Entry_s *newfiles =
realloc(prefix_out->pf_line_table_file_entries,
sizeof(struct Line_Table_File_Entry_s) *
expand);
if (!newfiles) {
_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
memset(newfiles + files_malloc, 0,
sizeof(struct Line_Table_File_Entry_s) *
files_malloc);
files_malloc = expand;
prefix_out->pf_line_table_file_entries = newfiles;
}
curline = prefix_out->pf_line_table_file_entries + files_count;
curline->lte_filename = line_ptr;
line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
DECODE_LEB128_UWORD(line_ptr, utmp)
dir_index = (Dwarf_Sword) utmp;
if (dir_index > directories_count) {
_dwarf_error(dbg, err, DW_DLE_DIR_INDEX_BAD);
return (DW_DLV_ERROR);
}
curline->lte_directory_index = dir_index;
lastmod = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
line_ptr = line_ptr + leb128_length;
curline->lte_last_modification_time = lastmod;
file_length = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
line_ptr = line_ptr + leb128_length;
curline->lte_length_of_file = file_length;
++files_count;
}
prefix_out->pf_files_count = files_count;
++line_ptr;
if (line_ptr != (prefix_out->pf_line_prologue_start +
prefix_out->pf_prologue_length)) {
_dwarf_error(dbg, err, DW_DLE_LINE_PROLOG_LENGTH_BAD);
return (DW_DLV_ERROR);
}
*updated_data_start_out = line_ptr;
return DW_DLV_OK;
}
void
dwarf_init_line_table_prefix(struct Line_Table_Prefix_s *pf)
{
memset(pf, 0, sizeof(*pf));
}
void
dwarf_free_line_table_prefix(struct Line_Table_Prefix_s *pf)
{
if (pf->pf_include_directories) {
free(pf->pf_include_directories);
pf->pf_include_directories = 0;
}
if (pf->pf_line_table_file_entries) {
free(pf->pf_line_table_file_entries);
pf->pf_line_table_file_entries = 0;
}
return;
}