dwarf_frame.c revision 07dc1947c362e187fb955d283b692f8769dd5def
/*
Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
under the terms of version 2.1 of the GNU Lesser General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it would be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Further, this software is distributed without any warranty that it is
free of the rightful claim of any third person regarding infringement
or the like. Any license provided herein, whether implied or
otherwise, applies only to this software file. Patent licenses, if
any, provided herein do not apply to combinations of this program with
other software, or any other product whatsoever.
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
USA.
Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
Mountain View, CA 94043, or:
For further information regarding this notice, see:
*/
/* The address of the Free Software Foundation is
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301, USA.
SGI has moved from the Crittenden Lane address.
*/
#include "config.h"
#include "dwarf_incl.h"
#include <stdio.h>
#include <stdlib.h>
#include "dwarf_frame.h"
#include "dwarf_arange.h" /* Using Arange as a way to build a
list */
do { \
return (DW_DLV_ERROR); \
} \
return (DW_DLV_ERROR); \
} } while (0)
#define MIN(a,b) (((a) < (b))? a:b)
int last_reg_num,
int initial_value);
struct Dwarf_Frame_s *fde_table,
unsigned table_real_data_size,
Dwarf_Error * error);
#if 0
/* Only used for debugging libdwarf. */
static void dump_frame_rule(char *msg,
struct Dwarf_Reg_Rule_s *reg_rule);
#endif
/*
This function is the heart of the debug_frame stuff. Don't even
think of reading this without reading both the Libdwarf and
consumer API carefully first. This function basically executes
frame instructions contained in a Cie or an Fde, but does in a
number of different ways depending on the information sought.
Start_instr_ptr points to the first byte of the frame instruction
stream, and final_instr_ptr to the to the first byte after the
last.
The offsets returned in the frame instructions are factored. That
is they need to be multiplied by either the code_alignment_factor
or the data_alignment_factor, as appropriate to obtain the actual
offset. This makes it possible to expand an instruction stream
without the corresponding Cie. However, when an Fde frame instr
sequence is being expanded there must be a valid Cie with a pointer
to an initial table row.
If successful, returns DW_DLV_OK
And sets returned_count thru the pointer
if make_instr is true.
If make_instr is false returned_count
should NOT be used by the caller (returned_count
is set to 0 thru the pointer by this routine...)
If unsuccessful, returns DW_DLV_ERROR
and sets returned_error to the error code
It does not do a whole lot of input validation being a private
function. Please make sure inputs are valid.
(1) If make_instr is true, it makes a list of pointers to
Dwarf_Frame_Op structures containing the frame instructions
executed. A pointer to this list is returned in ret_frame_instr.
Make_instr is true only when a list of frame instructions is to be
returned. In this case since we are not interested in the contents
of the table, the input Cie can be NULL. This is the only case
where the inpute Cie can be NULL.
(2) If search_pc is true, frame instructions are executed till
either a location is reached that is greater than the search_pc_val
provided, or all instructions are executed. At this point the
last row of the table generated is returned in a structure.
A pointer to this structure is supplied in table.
(3) This function is also used to create the initial table row
defined by a Cie. In this case, the Dwarf_Cie pointer cie, is
NULL. For an FDE, however, cie points to the associated Cie.
make_instr - make list of frame instr? 0/1
ret_frame_instr - Ptr to list of ptrs to frame instrs
search_pc - Search for a pc value? 0/1
search_pc_val - Search for this pc value
initial_loc - Initial code location value.
start_instr_ptr - Ptr to start of frame instrs.
final_instr_ptr - Ptr just past frame instrs.
table - Ptr to struct with last row.
cie - Ptr to Cie used by the Fde.
Different cies may have distinct address-sizes, so the cie
is used, not de_pointer_size.
*/
int
int *returned_error)
{
do { \
} \
} /*CONSTCOND */ while(0)
#define SIMPLE_ERROR_RETURN(code) \
free(localregtab); \
*returned_error = code; \
return DW_DLV_ERROR
/* Sweeps the frame instructions. */
/* Register numbers not limited to just 255, thus not using
Dwarf_Small. */
typedef int reg_num_type;
pc-value
corresponding to the
frame instructions.
Starts at zero when
the caller has no
value to pass in. */
/* Must be min de_pointer_size bytes and must be at least sizeof
Dwarf_ufixed */
Dwarf_Unsigned adv_loc = 0;
sizeof(struct
struct Dwarf_Reg_Rule_s cfa_reg;
/* This is used to end executing frame instructions. */
/* Becomes true when search_pc is true and current_loc */
/* is greater than search_pc_val. */
Dwarf_Bool search_over = false;
/* Used by the DW_FRAME_advance_loc instr */
/* to hold the increment in pc value. */
/* Contains the length in bytes of */
/* an leb128 encoded number. */
/* Counts the number of frame instructions executed. */
Dwarf_Word instr_count = 0;
/*
These contain the current fields of the current frame
instruction. */
Dwarf_Small fp_base_op = 0;
/* The value in fp_offset may be signed, though we call it
unsigned. This works ok for 2-s complement arithmetic. */
/*
Stack_table points to the row (Dwarf_Frame ie) being pushed or
popped by a remember or restore instruction. Top_stack points to
the top of the stack of rows. */
/*
These are used only when make_instr is true. Curr_instr is a
pointer to the current frame instruction executed.
Curr_instr_ptr, head_instr_list, and curr_instr_list are used to
form a chain of Dwarf_Frame_Op structs. Dealloc_instr_ptr is
used to deallocate the structs used to form the chain.
Head_instr_block points to a contiguous list of pointers to the
Dwarf_Frame_Op structs executed. */
/*
These are the alignment_factors taken from the Cie provided.
When no input Cie is provided they are set to 1, because only
factored offsets are required. */
/*
This flag indicates when an actual alignment factor is needed.
So if a frame instruction that computes an offset using an
alignment factor is encountered when this flag is set, an error
is returned because the Cie did not have a valid augmentation. */
Dwarf_Bool need_augmentation = false;
Dwarf_Word i;
/* Initialize first row from associated Cie. Using temp regs
explicity */
if (localregtab == 0) {
}
{
struct Dwarf_Reg_Rule_s *t2reg =
/* Should never happen, it makes no sense to have the
table sizes change. There is no real allowance for
the set of registers to change dynamically in a
single Dwarf_Debug (except the size can be set near
initial Dwarf_Debug creation time). */
}
}
} else {
}
}
/*
The idea here is that the code_alignment_factor and
data_alignment_factor which are needed for certain instructions
are valid only when the Cie has a proper augmentation string. So
if the augmentation is not right, only Frame instruction can be
read. */
} else {
}
Dwarf_Small instr = 0;
Dwarf_Small opcode = 0;
reg_num_type reg_no = 0;
instr_ptr += sizeof(Dwarf_Small);
} else {
fp_extended_op = 0;
}
fp_register = 0;
fp_offset = 0;
switch (opcode) {
case DW_CFA_advance_loc:
{
/* base op */
if (need_augmentation) {
}
search_over = search_pc &&
/* If gone past pc needed, retain old pc. */
if (!search_over) {
}
break;
}
case DW_CFA_offset:
{ /* base op */
reg_no =
if (need_augmentation) {
}
break;
}
case DW_CFA_restore:
{ /* base op */
else if (!make_instr) {
}
break;
}
case DW_CFA_set_loc:
{
Dwarf_Addr new_loc = 0;
if (new_loc != 0 && current_loc != 0) {
/* Pre-relocation or before current_loc is set the
test comparing new_loc and current_loc makes no
sense. Testing for non-zero (above) is a way
(fallible) to check that current_loc, new_loc
are already relocated. */
if (new_loc <= current_loc) {
/* Within a frame, address must increase.
Seemingly it has not. Seems to be an error. */
}
}
/* If gone past pc needed, retain old pc. */
if (!search_over) {
}
break;
}
case DW_CFA_advance_loc1:
{
instr_ptr += sizeof(Dwarf_Small);
if (need_augmentation) {
}
search_over = search_pc &&
/* If gone past pc needed, retain old pc. */
if (!search_over) {
}
break;
}
case DW_CFA_advance_loc2:
{
instr_ptr, sizeof(Dwarf_Half));
instr_ptr += sizeof(Dwarf_Half);
if (need_augmentation) {
}
search_over = search_pc &&
/* If gone past pc needed, retain old pc. */
if (!search_over) {
}
break;
}
case DW_CFA_advance_loc4:
{
instr_ptr, sizeof(Dwarf_ufixed));
instr_ptr += sizeof(Dwarf_ufixed);
if (need_augmentation) {
}
search_over = search_pc &&
/* If gone past pc needed, retain old pc. */
if (!search_over) {
}
break;
}
case DW_CFA_offset_extended:
{
if (need_augmentation) {
}
break;
}
case DW_CFA_restore_extended:
{
} else {
if (!make_instr) {
}
}
break;
}
case DW_CFA_undefined:
{
break;
}
case DW_CFA_same_value:
{
break;
}
case DW_CFA_register:
{
reg_num_type reg_noA = 0;
reg_num_type reg_noB = 0;
}
break;
}
case DW_CFA_remember_state:
{
if (stack_table == NULL) {
}
for (i = 0; i < reg_count; i++)
break;
}
case DW_CFA_restore_state:
{
}
for (i = 0; i < reg_count; i++)
break;
}
case DW_CFA_def_cfa:
{
if (need_augmentation) {
}
break;
}
case DW_CFA_def_cfa_register:
{
/* Do NOT set ru_offset_or_block_len or ru_is_off here.
See dwarf2/3 spec. */
break;
}
case DW_CFA_def_cfa_offset:
{
if (need_augmentation) {
}
/* Do set ru_is_off here, as here factored_N_value
counts. */
break;
}
case DW_CFA_nop:
{
break;
}
/* DWARF3 ops begin here. */
{
/* A single DW_FORM_block representing a dwarf
expression. The form block establishes the way to
compute the CFA. */
Dwarf_Unsigned block_len = 0;
}
break;
case DW_CFA_expression:
{
/* An unsigned leb128 value is the first operand (a
register number). The second operand is single
DW_FORM_block representing a dwarf expression. The
evaluator pushes the CFA on the evaluation stack
then evaluates the expression to compute the value
of the register contents. */
Dwarf_Unsigned lreg = 0;
Dwarf_Unsigned block_len = 0;
}
break;
{
/* The first operand is an unsigned leb128 register
number. The second is a signed factored offset.
Identical to DW_CFA_offset_extended except the
secondoperand is signed */
if (need_augmentation) {
}
}
break;
case DW_CFA_def_cfa_sf:
{
/* The first operand is an unsigned leb128 register
number. The second is a signed leb128 factored
offset. Identical to DW_CFA_def_cfa except that the
second operand is signed and factored. */
if (need_augmentation) {
}
}
break;
case DW_CFA_def_cfa_offset_sf:
{
/* The operand is a signed leb128 operand representing
a factored offset. Identical to
DW_CFA_def_cfa_offset excep the operand is signed
and factored. */
if (need_augmentation) {
}
/* Do set ru_is_off here, as here factored_N_value
counts. */
}
break;
case DW_CFA_val_offset:
{
/* The first operand is an unsigned leb128 register
number. The second is a factored unsigned offset.
Makes the register be a val_offset(N) rule with N =
factored_offset*data_alignment_factor. */
if (need_augmentation) {
}
/* Do set ru_is_off here, as here factored_N_value
counts. */
break;
}
case DW_CFA_val_offset_sf:
{
/* The first operand is an unsigned leb128 register
number. The second is a factored signed offset.
Makes the register be a val_offset(N) rule with N =
factored_offset*data_alignment_factor. */
if (need_augmentation) {
}
/* Do set ru_is_off here, as here factored_N_value
counts. */
}
break;
case DW_CFA_val_expression:
{
/* The first operand is an unsigned leb128 register
number. The second is a DW_FORM_block representing a
DWARF expression. The rule for the register number
becomes a val_expression(E) rule. */
Dwarf_Unsigned lreg = 0;
Dwarf_Unsigned block_len = 0;
}
break;
/* END DWARF3 new ops. */
#ifdef DW_CFA_GNU_window_save
case DW_CFA_GNU_window_save:
{
/* no information: this just tells unwinder to restore
the window registers from the previous frame's
window save area */
break;
}
#endif
#ifdef DW_CFA_GNU_args_size
/* single uleb128 is the current arg area size in bytes. No
register exists yet to save this in */
case DW_CFA_GNU_args_size:
{
break;
}
#endif
default:
/* ERROR, we have an opcode we know nothing about. Memory
leak here, but an error like this is not supposed to
happen so we ignore the leak. These used to be ignored,
now we notice and report. */
}
if (make_instr) {
instr_count++;
curr_instr = (Dwarf_Frame_Op *)
if (curr_instr == NULL) {
}
if (curr_instr_item == NULL) {
}
if (head_instr_chain == NULL)
else {
}
}
}
/*
If frame instruction decoding was right we would stop exactly at
final_instr_ptr. */
if (instr_ptr > final_instr_ptr) {
}
/* Fill in the actual output table, the space the caller passed in. */
}
/* CONSTCOND */
/* Do not update the main table with the cfa_reg.
Just leave cfa_reg as cfa_reg. */
}
/* Dealloc anything remaining on stack. */
}
if (make_instr) {
/* Allocate list of pointers to Dwarf_Frame_Op's. */
if (head_instr_block == NULL) {
}
/*
Store pointers to Dwarf_Frame_Op's in this list and
deallocate the structs that chain the Dwarf_Frame_Op's. */
for (i = 0; i < instr_count; i++) {
*(head_instr_block + i) =
}
} else {
*returned_count = 0;
}
return DW_DLV_OK;
}
/* Depending on version, either read the return address register
as a ubyte or as an leb number.
The form of this value changed for DWARF3.
*/
{
Dwarf_Unsigned uvalue = 0;
Dwarf_Word leb128_length = 0;
if (version == 1) {
*size = 1;
return uvalue;
}
*size = leb128_length;
return uvalue;
}
/* Trivial consumer function.
*/
int
{
return (DW_DLV_ERROR);
}
return DW_DLV_OK;
}
int dwarf_get_cie_index(
Dwarf_Error* error )
{
{
return (DW_DLV_ERROR);
}
return (DW_DLV_OK);
}
/*
For g++ .eh_frame fde and cie.
the cie id is different as the
definition of the cie_id in an fde
is the distance back from the address of the
value to the cie.
Or 0 if this is a true cie.
Non standard dwarf, designed this way to be
convenient at run time for an allocated
(mapped into memory as part of the running image) section.
*/
int
Dwarf_Error * error)
{
return res;
}
/* cie_id_value */ 0,
/* use_gnu_cie_calc= */ 1,
error);
return res;
}
/*
For standard dwarf .debug_frame
cie_id is -1 in a cie, and
is the section offset in the .debug_frame section
of the cie otherwise. Standard dwarf
*/
int
Dwarf_Error * error)
{
return res;
}
/* use_gnu_cie_calc= */ 0,
error);
return res;
}
/*
Only works on dwarf sections, not eh_frame
Given a Dwarf_Die, see if it has a
DW_AT_MIPS_fde attribute and if so use that
to get an fde offset.
Then create a Dwarf_Fde to return thru the ret_fde pointer.
Also creates a cie (pointed at from the Dwarf_Fde).
*/
int
{
Dwarf_Unsigned fde_offset = 0;
Dwarf_Signed signdval = 0;
unsigned char *fde_ptr = 0;
unsigned char *cie_ptr = 0;
Dwarf_Unsigned cie_id = 0;
/* Fields for the current Cie being read. */
int res = 0;
int resattr = 0;
int sdatares = 0;
struct cie_fde_prefix_s prefix;
struct cie_fde_prefix_s prefix_c;
return (DW_DLV_ERROR);
}
return resattr;
}
/* why is this formsdata? FIX */
return sdatares;
}
return res;
}
/* First read in the 'common prefix' to figure out what * we are to
do with this entry. */
&prefix,
error);
if (res == DW_DLV_ERROR) {
return res;
}
if (res == DW_DLV_NO_ENTRY)
return res;
/* Pass NULL, not section pointer, for 3rd argument.
de_debug_frame.dss_data has no eh_frame relevance. */
(Dwarf_Small *) NULL,
/* use_gnu_cie_calc= */ 0,
/* Dwarf_Cie = */ 0,
if (res == DW_DLV_ERROR) {
return res;
} else if (res == DW_DLV_NO_ENTRY) {
return res;
}
/* DW_DLV_OK */
/* now read the cie corresponding to the fde */
if (res == DW_DLV_ERROR) {
return res;
}
if (res == DW_DLV_NO_ENTRY)
return res;
int res2 = 0;
/* Pass NULL, not section pointer, for 3rd argument.
de_debug_frame.dss_data has no eh_frame relevance. */
&prefix_c,
(Dwarf_Small *) NULL,
/* cie_count= */ 0,
/* use_gnu_cie_calc= */
if (res2 == DW_DLV_ERROR) {
return res;
} else if (res2 == DW_DLV_NO_ENTRY) {
return res;
}
} else {
return (DW_DLV_ERROR);
}
return DW_DLV_OK;
}
/* A dwarf consumer operation, see the consumer library documentation.
*/
int
Dwarf_Addr * low_pc,
{
return (DW_DLV_ERROR);
}
return (DW_DLV_ERROR);
}
/* We have always already done the section load here, so no need to
load the section. We did the section load in order to create the
Dwarf_Fde pointer passed in here. */
if (func_length != NULL)
if (fde_byte_length != NULL)
if (cie_offset != NULL)
if (fde_offset != NULL)
return DW_DLV_OK;
}
/* IRIX specific function. The exception tables
have C++ destructor information and are
at present undocumented. */
int
Dwarf_Error * error)
{
return (DW_DLV_ERROR);
}
return DW_DLV_OK;
}
/* A consumer code function.
Given a CIE pointer, return the normal CIE data thru
pointers.
Special augmentation data is not returned here.
*/
int
char **augmenter,
Dwarf_Error * error)
{
return (DW_DLV_ERROR);
}
return (DW_DLV_ERROR);
}
if (ptr_to_version != NULL)
if (code_alignment_factor != NULL)
if (data_alignment_factor != NULL)
if (return_address_register != NULL)
if (initial_instructions != NULL)
if (initial_instructions_length != NULL) {
}
return (DW_DLV_OK);
}
/* Return the register rules for all registers at a given pc.
*/
static int
Dwarf_Error * error)
{
Dwarf_Debug dbg = 0;
int dw_err = 0;
Dwarf_Sword icount = 0;
int res = 0;
return (DW_DLV_ERROR);
}
return (DW_DLV_ERROR);
}
pc_requested >=
return (DW_DLV_ERROR);
}
return (DW_DLV_ERROR);
}
/* ret_frame_instr= */ NULL,
/* search_pc */ false,
/* search_pc_val */ 0,
/* location */ 0,
cie->ci_cie_start)),
&dw_err);
if (res == DW_DLV_ERROR) {
return (res);
} else if (res == DW_DLV_NO_ENTRY) {
return res;
}
}
{
fde->fd_fde_start);
/* ret_frame_instr= */ NULL,
/* search_pc */ true,
/* search_pc_val */ pc_requested,
&dw_err);
}
if (res == DW_DLV_ERROR) {
return (res);
} else if (res == DW_DLV_NO_ENTRY) {
return res;
}
return DW_DLV_OK;
}
/* A consumer call for efficiently getting the register info
for all registers in one call.
The output table rules array is size DW_REG_TABLE_SIZE.
The frame info rules array in fde_table is of size
DW_REG_TABLE_SIZE too.
where DW_FRAME_CFA_COL is zero (in that case it's safe).
It is also restricted to the case where
DW_REG_TABLE_SIZE == DW_FRAME_LAST_REG_NUM ==
If this condition is not met calling this routine can result in
incorrect output or in memory corruption.
It is much better to use dwarf_get_fde_info_for_all_regs3()
instead of this interface.
*/
int
Dwarf_Addr * row_pc,
Dwarf_Error * error)
{
/* Table size: DW_REG_TABLE_SIZE */
struct Dwarf_Frame_s fde_table;
Dwarf_Sword i = 0;
int res = 0;
Dwarf_Debug dbg = 0;
/* For this interface the size is fixed at compile time. */
error);
return res;
/* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
*/
return res;
}
for (i = 0; i < output_table_real_data_size;
}
for (; i < DW_REG_TABLE_SIZE; ++i, ++out_rule) {
out_rule->dw_offset_relevant = 0;
}
/* The test is just in case it's not inside the table. For non-MIPS
it could be outside the table and that is just fine, it was
really a mistake to put it in the table in 1993. */
/* CONSTCOND */
}
return DW_DLV_OK;
}
/* A consumer call for efficiently getting the register info
for all registers in one call.
The output table rules array is size output_table_real_data_size.
(normally DW_REG_TABLE_SIZE).
The frame info rules array in fde_table is normally of size
DW_FRAME_LAST_REG_NUM.
*/
int
Dwarf_Addr * row_pc,
Dwarf_Error * error)
{
struct Dwarf_Frame_s fde_table;
Dwarf_Sword i = 0;
int res = 0;
Dwarf_Debug dbg = 0;
error);
/* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
*/
error);
return res;
}
for (i = 0; i < output_table_real_data_size;
}
out_rule->dw_offset_relevant = 0;
out_rule->dw_block_ptr = 0;
}
return DW_DLV_OK;
}
/* Gets the register info for a single register at a given PC value
for the FDE specified.
This is the old MIPS interface and should no longer be used.
Use dwarf_get_fde_info_for_reg3() instead.
*/
int
{
struct Dwarf_Frame_s fde_table;
int res = DW_DLV_ERROR;
Dwarf_Debug dbg = 0;
int output_table_real_data_size = 0;
error);
return res;
if (table_column >= output_table_real_data_size) {
return (DW_DLV_ERROR);
}
/* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
*/
res =
return res;
}
/* The problem here is that this interface cannot deal with
other sorts of (newer) dwarf frame values. Code must
use dwarf_get_fde_info_for_reg3() to get these
values correctly. We error rather than return
misleading incomplete data. */
return (DW_DLV_ERROR);
}
if (register_num != NULL)
} else {
if (register_num != NULL)
}
return DW_DLV_OK;
}
/* In this interface, table_column of DW_FRAME_CFA_COL
is not meaningful.
Use dwarf_get_fde_info_for_cfa_reg3() to get the CFA.
Call dwarf_set_frame_cfa_value() to set the correct column
after calling dwarf_init()
(DW_FRAME_CFA_COL3 is a sensible column to use).
*/
int
Dwarf_Error * error)
{
struct Dwarf_Frame_s fde_table;
int res = DW_DLV_ERROR;
Dwarf_Debug dbg = 0;
int table_real_data_size = 0;
return res;
if (table_column >= table_real_data_size) {
return (DW_DLV_ERROR);
}
/* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
*/
error);
return res;
}
if (register_num != NULL)
if (offset_or_block_len != NULL)
if (row_pc_out != NULL)
if (block_ptr)
/* Without value_type the data cannot be understood, so we insist
on it being present, we don't test it. */
return DW_DLV_OK;
}
/* For latest DWARF, this is the preferred interface.
It more portably deals with the CFA by not
making the CFA a column number, which means
DW_FRAME_CFA_COL3 becomes, like DW_CFA_SAME_VALUE,
a special value, not something one uses as an index.
Call dwarf_set_frame_cfa_value() to set the correct column
after calling dwarf_init()
(DW_FRAME_CFA_COL3 is a sensible column to use, and
is the default unless '--enable-oldframecol'
is used to configure libdwarf). */
int
Dwarf_Error * error)
{
struct Dwarf_Frame_s fde_table;
int res = DW_DLV_ERROR;
Dwarf_Debug dbg = 0;
int table_real_data_size = 0;
return res;
return res;
}
if (register_num != NULL)
if (offset_or_block_len != NULL)
if (row_pc_out != NULL)
if (block_ptr)
/* Without value_type the data cannot be understood, so we insist
on it being present, we don't test it. */
return DW_DLV_OK;
}
/*
Return pointer to the instructions in the dwarf
fde.
*/
int
Dwarf_Error * error)
{
Dwarf_Unsigned len = 0;
unsigned char *instrs = 0;
Dwarf_Debug dbg = 0;
return (DW_DLV_ERROR);
}
return (DW_DLV_ERROR);
}
*outinstraddr = instrs;
*outaddrlen = len;
return DW_DLV_OK;
}
/* Allows getting an fde from its table via an index.
With more error checking than simply indexing oneself.
*/
int
{
Dwarf_Debug dbg = 0;
Dwarf_Signed fdecount = 0;
return (DW_DLV_ERROR);
}
/* Assumes fde_data table has at least one entry. */
return (DW_DLV_NO_ENTRY);
}
return DW_DLV_OK;
}
/*
Lopc and hipc are extensions to the interface to
return the range of addresses that are described
by the returned fde.
*/
int
Dwarf_Addr * lopc,
{
Dwarf_Signed fdecount = 0;
return (DW_DLV_ERROR);
}
/* Assumes fde_data table has at least one entry. */
return (DW_DLV_ERROR);
}
{
/* The fde's are sorted by their addresses. Binary search to
find correct fde. */
Dwarf_Signed low = 0;
Dwarf_Signed middle = 0;
} else if (pc_of_interest >=
cur_fde->fd_address_range)) {
} else {
break;
}
}
}
if (fde) {
*hipc =
*returned_fde = fde;
return (DW_DLV_OK);
}
return (DW_DLV_NO_ENTRY);
}
/* Expands a single frame instruction block
from a specific cie
into a n array of Dwarf_Frame_Op-s.
This depends on having the cfa column set sensibly.
Call dwarf_set_frame_cfa_value() to set the correct column
after calling dwarf_init() unless you are using
the old MIPS frame interfaces (in which case the default
will be ok). (DW_FRAME_CFA_COL3 is a sensible column to use ).
*/
int
Dwarf_Error * error)
{
int res = DW_DLV_ERROR;
int dw_err;
Dwarf_Debug dbg = 0;
if (cie == 0) {
return (DW_DLV_ERROR);
}
if (returned_op_list == 0 || returned_op_count == 0) {
return (DW_DLV_ERROR);
}
/* The cast to Dwarf_Ptr may get a compiler warning, but it is safe
as it is just an i_length offset from 'instruction' itself. A
caller has made a big mistake if the result is not a valid
pointer. */
/* search_pc */ false,
/* search_pc_val */ 0,
/* location */ 0,
/* Dwarf_Frame */ NULL,
cie,
dbg,
&dw_err);
if (res == DW_DLV_ERROR) {
}
return (res);
}
return DW_DLV_OK;
}
/* Used by dwarfdump -v to print offsets, for debugging
dwarf info.
The dwarf_ version is preferred over the obsolete _dwarf version.
_dwarf version kept for compatibility.
*/
/* ARGSUSED 4 */
int
Dwarf_Error * err)
{
}
/* ARGSUSED 4 */
int
Dwarf_Error * err)
{
char *start = 0;
char *loc = 0;
return DW_DLV_OK;
}
/* Used by dwarfdump -v to print offsets, for debugging
dwarf info.
The dwarf_ version is preferred over the obsolete _dwarf version.
_dwarf version kept for compatibility.
*/
/* ARGSUSED 4 */
int
{
}
/* ARGSUSED 4 */
int
{
char *start = 0;
char *loc = 0;
return DW_DLV_OK;
}
/* Returns a pointer to target-specific augmentation data thru augdata
and returns the length of the data thru augdata_len.
It's up to the consumer code to know how to interpret the bytes
of target-specific data (endian issues apply too, these
are just raw bytes pointed to).
See Linux Standard Base Core Specification version 3.0 for
the details on .eh_frame info.
Returns DW_DLV_ERROR if fde is NULL or some other serious
error.
Returns DW_DLV_NO_ENTRY if there is no target-specific
augmentation data.
The bytes pointed to are in the Dwarf_Cie, and as long as that
is valid the bytes are there. No 'dealloc' call is needed
for the bytes.
*/
int
Dwarf_Small ** augdata,
Dwarf_Error * error)
{
return (DW_DLV_ERROR);
}
if (cie->ci_gnu_eh_augmentation_len == 0) {
return DW_DLV_NO_ENTRY;
}
return DW_DLV_OK;
}
/* Returns a pointer to target-specific augmentation data thru augdata
and returns the length of the data thru augdata_len.
It's up to the consumer code to know how to interpret the bytes
of target-specific data (endian issues apply too, these
are just raw bytes pointed to).
See Linux Standard Base Core Specification version 3.0 for
the details on .eh_frame info.
Returns DW_DLV_ERROR if fde is NULL or some other serious
error.
Returns DW_DLV_NO_ENTRY if there is no target-specific
augmentation data.
The bytes pointed to are in the Dwarf_Fde, and as long as that
is valid the bytes are there. No 'dealloc' call is needed
for the bytes.
*/
int
Dwarf_Small * *augdata,
Dwarf_Error * error)
{
return (DW_DLV_ERROR);
}
return (DW_DLV_ERROR);
}
if (cie->ci_gnu_eh_augmentation_len == 0) {
return DW_DLV_NO_ENTRY;
}
return DW_DLV_OK;
}
/* Initialize with same_value , a value which makes sense
The correct value to use is ABI dependent.
For register-windows machines most
or all registers should get DW_FRAME_UNDEFINED_VAL as the
correct initial value.
Some think DW_FRAME_UNDEFINED_VAL is always the
right value.
For some ABIs a setting which varies by register
would be more appropriate.
FIXME. */
static void
int last_reg_num, int initial_value)
{
t1reg->ru_offset_or_block_len = 0;
}
}
#if 0
/* Used solely for debugging libdwarf. */
static void
{
DW_PR_DUx "\n",
msg,
"DW_EXPR_OFFSET" :
"DW_EXPR_VAL_OFFSET" :
"DW_EXPR_VAL_EXPRESSION" :
"DW_EXPR_EXPRESSION" : "Unknown",
return;
}
#endif
/* This allows consumers to set the 'initial value' so that
at run time. Useful for dwarfdump and non-MIPS architectures..
The value defaults to one of
DW_FRAME_SAME_VALUE or DW_FRAME_UNKNOWN_VALUE
we may want to get this set to what the ABI says is correct.
Returns the value that was present before we changed it here.
*/
{
return orig;
}
/* The following spelling for backwards compatibility. */
{
}
/* This allows consumers to set the array size of the reg rules
table so that
at run time. Useful for non-MIPS archtectures.
The value defaults to DW_FRAME_LAST_REG_NUM.
consumers want to get this set to what the ABI says is correct.
Returns the value that was present before we changed it here.
*/
{
return orig;
}
/* This allows consumers to set the CFA register value
* at run time. Useful for non-MIPS archtectures.
* The value defaults to DW_FRAME_CFA_COL3 and should be
* higher than any real register in the ABI.
* consumers want to get this set to what the ABI says is correct.
* Returns the value that was present before we changed it here.
* */
{
return orig;
}
/* Similar to above, but for the other crucial fields for frames. */
{
return orig;
}
{
return orig;
}
static int
struct Dwarf_Frame_s *fde_table,
unsigned table_real_data_size,
Dwarf_Error * error)
{
unsigned entry_size = sizeof(struct Dwarf_Frame_s);
return (DW_DLV_ERROR);
}
return DW_DLV_OK;
}
static void
{
fde_table->fr_reg_count = 0;
}
/* Return DW_DLV_OK if we succeed. else return DW_DLV_ERROR.
*/
int
{
if (!dbg) {
return DW_DLV_ERROR;
}
sizeof(struct Dwarf_Reg_Rule_s));
return DW_DLV_ERROR;
}
return DW_DLV_OK;
}
void
_dwarf_frame_destructor(void *frame)
{
}
fp->fr_reg_count = 0;
}