#include "config.h"
#include <stdio.h>
#include "dwarf_incl.h"
#include "dwarf_alloc.h"
#include "dwarf_error.h"
#include "dwarf_util.h"
#include "dwarf_str_offsets.h"
#define TRUE 1
#define FALSE 0
#define STR_OFFSETS_MAGIC 0x2feed2
#define VALIDATE_SOT(xsot) \
if
(!xsot) { \
_dwarf_error(NULL,error,DW_DLE_STR_OFFSETS_NULLARGUMENT); \
return
DW_DLV_ERROR; \
} \
if
(!xsot->so_dbg) { \
_dwarf_error(NULL,error,DW_DLE_STR_OFFSETS_NULL_DBG); \
return
DW_DLV_ERROR; \
} \
if
(xsot->so_magic_value != STR_OFFSETS_MAGIC) { \
_dwarf_error(xsot->so_dbg,error,DW_DLE_STR_OFFSETS_NO_MAGIC); \
return
DW_DLV_ERROR; \
}
#if 0
static
void
dump_bytes(
char
* msg,Dwarf_Small * start,
long
len)
{
Dwarf_Small *end = start + len;
Dwarf_Small *cur = start;
printf
(
"%s "
,msg);
for
(; cur < end; cur++) {
printf
(
"%02x "
, *cur);
}
printf
(
"\n"
);
}
#endif
int
dwarf_open_str_offsets_table_access(Dwarf_Debug dbg,
Dwarf_Str_Offsets_Table * table_data,
Dwarf_Error * error)
{
int
res = 0;
Dwarf_Str_Offsets_Table local_table_data = 0;
Dwarf_Small *offsets_start_ptr = 0;
Dwarf_Unsigned sec_size = 0;
if
(!dbg) {
_dwarf_error(NULL,error,DW_DLE_STR_OFFSETS_NULL_DBG); \
return
DW_DLV_ERROR; \
}
if
(!table_data) {
_dwarf_error(dbg,error,DW_DLE_STR_OFFSETS_NULLARGUMENT); \
return
DW_DLV_ERROR; \
}
res = _dwarf_load_section(dbg, &dbg->de_debug_str_offsets,error);
if
(res != DW_DLV_OK) {
return
res;
}
offsets_start_ptr = dbg->de_debug_str_offsets.dss_data;
if
(!offsets_start_ptr) {
return
DW_DLV_NO_ENTRY;
}
sec_size = dbg->de_debug_str_offsets.dss_size;
local_table_data = (Dwarf_Str_Offsets_Table)_dwarf_get_alloc(dbg,
DW_DLA_STR_OFFSETS,1);
if
(!local_table_data) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return
DW_DLV_ERROR;
}
local_table_data->so_dbg = dbg;
local_table_data->so_magic_value = STR_OFFSETS_MAGIC;
local_table_data->so_section_start_ptr = offsets_start_ptr;
local_table_data->so_section_end_ptr = offsets_start_ptr +sec_size;
local_table_data->so_section_size = sec_size;
local_table_data->so_next_table_offset = 0;
local_table_data->so_wasted_section_bytes = 0;
*table_data = local_table_data;
return
DW_DLV_OK;
}
int
dwarf_close_str_offsets_table_access(
Dwarf_Str_Offsets_Table table_data,
Dwarf_Error * error)
{
Dwarf_Debug dbg = 0;
VALIDATE_SOT(table_data)
dbg = table_data->so_dbg;
table_data->so_magic_value = 0xdead;
dwarf_dealloc(dbg,table_data, DW_DLA_STR_OFFSETS);
return
DW_DLV_OK;
}
int
dwarf_str_offsets_value_by_index(Dwarf_Str_Offsets_Table sot,
Dwarf_Unsigned index,
Dwarf_Unsigned *stroffset,
Dwarf_Error *error)
{
Dwarf_Small *entryptr = 0;
Dwarf_Unsigned val = 0;
VALIDATE_SOT(sot)
if
(index >= sot->so_array_entry_count) {
_dwarf_error(sot->so_dbg,error, DW_DLE_STR_OFFSETS_ARRAY_INDEX_WRONG);
return
DW_DLV_ERROR;
}
entryptr = sot->so_array_ptr + (index * sot->so_array_entry_size);
READ_UNALIGNED_CK(sot->so_dbg, val, Dwarf_Unsigned,
entryptr, sot->so_array_entry_size,error,sot->so_end_cu_ptr);
*stroffset = val;
return
DW_DLV_OK;
}
static
int
find_next_str_offsets_tab(Dwarf_Str_Offsets_Table sot,
Dwarf_Unsigned starting_offset,
Dwarf_Unsigned *table_offset_out,
Dwarf_Error *error)
{
Dwarf_Small *word_ptra = 0;
Dwarf_Small *word_ptrb = 0;
Dwarf_Unsigned offset = starting_offset;
word_ptra = word_ptrb = sot->so_section_start_ptr +offset;
for
( ; ; word_ptrb += DWARF_32BIT_SIZE) {
Dwarf_Unsigned one32bit = 0;
if
(word_ptrb >= sot->so_section_end_ptr) {
sot->so_wasted_section_bytes += (word_ptrb - word_ptra);
return
DW_DLV_NO_ENTRY;
}
READ_UNALIGNED_CK(sot->so_dbg, one32bit, Dwarf_Unsigned,
word_ptrb, DWARF_32BIT_SIZE,
error,sot->so_section_end_ptr);
if
(one32bit) {
break
;
}
offset += DWARF_32BIT_SIZE;
}
sot->so_wasted_section_bytes += (word_ptrb - word_ptra);
*table_offset_out = offset;
return
DW_DLV_OK;
}
#define MIN_HEADER_LENGTH 8
int
dwarf_next_str_offsets_table(Dwarf_Str_Offsets_Table sot,
Dwarf_Unsigned *unit_length_out,
Dwarf_Unsigned *unit_length_offset_out,
Dwarf_Unsigned *table_start_offset_out,
Dwarf_Half *entry_size_out,
Dwarf_Half *version_out,
Dwarf_Half *padding_out,
Dwarf_Unsigned *table_value_count_out,
Dwarf_Error * error)
{
Dwarf_Small *table_start_ptr = 0;
Dwarf_Small *table_end_ptr = 0;
Dwarf_Unsigned table_offset = 0;
Dwarf_Unsigned local_length_size = 0;
UNUSEDARG Dwarf_Unsigned local_extension_size = 0;
Dwarf_Unsigned length = 0;
Dwarf_Half version = 0;
Dwarf_Half padding = 0;
int
res = 0;
VALIDATE_SOT(sot)
res = find_next_str_offsets_tab(sot,
sot->so_next_table_offset,
&table_offset,error);
if
(res != DW_DLV_OK) {
if
(res == DW_DLV_NO_ENTRY) {
if
(table_offset > sot->so_next_table_offset) {
sot->so_wasted_section_bytes +=
(table_offset - sot->so_next_table_offset);
}
}
return
res;
}
if
(table_offset > sot->so_next_table_offset) {
sot->so_wasted_section_bytes +=
(table_offset - sot->so_next_table_offset);
}
table_start_ptr = sot->so_section_start_ptr + table_offset;
sot->so_header_ptr = table_start_ptr;
if
(table_start_ptr >= sot->so_section_end_ptr) {
if
(table_start_ptr == sot->so_section_end_ptr) {
return
DW_DLV_NO_ENTRY;
}
}
if
((table_start_ptr + MIN_HEADER_LENGTH) > sot->so_section_end_ptr) {
_dwarf_error(sot->so_dbg,error,
DW_DLE_STR_OFFSETS_EXTRA_BYTES);
return
DW_DLV_ERROR;
}
READ_AREA_LENGTH_CK(sot->so_dbg,length,Dwarf_Unsigned,
table_start_ptr,local_length_size,
local_extension_size,error,
sot->so_section_size,sot->so_section_end_ptr);
table_end_ptr = table_start_ptr + length;
READ_UNALIGNED_CK(sot->so_dbg, version, Dwarf_Half,
table_start_ptr, DWARF_HALF_SIZE,
error,sot->so_section_end_ptr);
table_start_ptr += DWARF_HALF_SIZE;
READ_UNALIGNED_CK(sot->so_dbg, padding, Dwarf_Half,
table_start_ptr, DWARF_HALF_SIZE,
error,sot->so_section_end_ptr);
table_start_ptr += DWARF_HALF_SIZE;
if
(version != DW_STR_OFFSETS_VERSION5) {
_dwarf_error(sot->so_dbg,error,
DW_DLE_STR_OFFSETS_VERSION_WRONG);
return
DW_DLV_ERROR;
}
{
Dwarf_Unsigned entrycount = 0;
Dwarf_Unsigned entrybytes = 0;
entrybytes = table_end_ptr - table_start_ptr;
if
(entrybytes % local_length_size) {
_dwarf_error(sot->so_dbg,error,
DW_DLE_STR_OFFSETS_ARRAY_SIZE);
return
DW_DLV_ERROR;
}
entrycount = entrybytes/local_length_size;
sot->so_next_table_offset = table_end_ptr -
sot->so_section_start_ptr;
sot->so_end_cu_ptr = table_end_ptr;
sot->so_array_ptr = table_start_ptr;
sot->so_table_start_offset = table_offset;
sot->so_array_start_offset = table_start_ptr -
sot->so_section_start_ptr;
sot->so_array_entry_count = entrycount;
sot->so_array_entry_size = local_length_size;
sot->so_table_count += 1;
*unit_length_out = length;
*unit_length_offset_out = sot->so_table_start_offset;
*table_start_offset_out = sot->so_array_start_offset;
*entry_size_out = local_length_size;
*version_out = version;
*padding_out = padding;
*table_value_count_out = entrycount;
return
DW_DLV_OK;
}
}
int
dwarf_str_offsets_statistics(Dwarf_Str_Offsets_Table table_data,
Dwarf_Unsigned * wasted_byte_count,
Dwarf_Unsigned * table_count,
Dwarf_Error * error)
{
VALIDATE_SOT(table_data)
if
(wasted_byte_count) {
*wasted_byte_count = table_data->so_wasted_section_bytes;
}
if
(table_count) {
*table_count = table_data->so_table_count;
}
return
DW_DLV_OK;
}