Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
0f270d8
Trace formal parameters whose location is a register
mernst Oct 10, 2026
2d34e1a
Address code review of register-parameter tracing
mernst Oct 10, 2026
5ffb72a
Address code review of register-parameter tracing
mernst Oct 11, 2026
5df375c
Address code review of register-parameter tracing
mernst Oct 11, 2026
6337680
Index saved entrance registers by DWARF register number
mernst Oct 11, 2026
d914a74
Address code review of register-parameter tracing
mernst Oct 11, 2026
674c534
Read DWARF registers through their guest-state offsets
mernst Oct 11, 2026
d3c21c6
Omit a formal parameter whose location Fjalar cannot read from the .d…
mernst Oct 11, 2026
aa367c6
Merge remote-tracking branch 'origin/dwarf-register-access' into regi…
mernst Oct 11, 2026
c48e46a
Merge remote-tracking branch 'origin/omit-unreadable-params' into reg…
mernst Oct 11, 2026
29692dd
Share one supported-op predicate; fix overflow, fix-up, and register-…
mernst Oct 11, 2026
0f08253
Address code review findings on DWARF register access
mernst Oct 11, 2026
071458b
Do not save the frame pointer at entry; #90 saves all registers
mernst Oct 11, 2026
0cb0a41
Merge remote-tracking branch 'origin/dwarf-register-access' into regi…
mernst Oct 12, 2026
1656f48
Treat a register location as unsupported; test a location with an off…
mernst Oct 12, 2026
b22db92
Reduce this pull request to omitting unreadable parameters from the .…
mernst Oct 12, 2026
6f84728
Omit a formal parameter whose location contains an unsupported DWARF op
mernst Oct 12, 2026
f016945
Remove an unused copy of the location evaluator
mernst Oct 12, 2026
1f7e404
Rename a stale debug-message label
mernst Oct 12, 2026
30557ba
Document dwarf_op_reg_num at its definition
mernst Oct 12, 2026
21ecdf5
Omit parameters with location lists; check the .dtrace file in the test
mernst Oct 12, 2026
9d37c9e
Support a location that is one whole piece; sort test output
mernst Oct 12, 2026
8f67556
Document harvest_formal_param_location_unsupported and harvest_formal…
mernst Oct 12, 2026
50edff3
Merge remote-tracking branch 'origin/remove-unused-evaluator' into dw…
mernst Oct 12, 2026
6daef48
Merge remote-tracking branch 'origin/dwarf-register-access' into regi…
mernst Oct 12, 2026
8018d10
Save only the registers that valid parameter locations use; give no s…
mernst Oct 12, 2026
501b409
Treat a final DW_OP_piece of size 0 as unsupported
mernst Oct 12, 2026
8f520ce
Merge remote-tracking branch 'origin/register-params' into unsupporte…
mernst Oct 13, 2026
af76882
Merge remote-tracking branch 'origin/master' into dwarf-register-access
mernst Oct 16, 2026
ca6636d
Merge remote-tracking branch 'origin/master' into register-params
mernst Oct 16, 2026
7d675ac
Merge remote-tracking branch 'origin/master' into unsupported-locatio…
mernst Oct 16, 2026
95b599d
Merge remote-tracking branch 'origin/dwarf-register-access' into regi…
mernst Oct 17, 2026
4cfbe74
Move the detection of unsupported location operations to #95
mernst Oct 17, 2026
041a892
Merge branch 'register-params' into unsupported-location-op
mernst Oct 17, 2026
a2b981f
Merge codespecs/fjalar master into register-params
mernst Oct 17, 2026
47606c8
Merge codespecs/fjalar master into unsupported-location-op
mernst Oct 17, 2026
fec4516
Merge #90 (register-params) into unsupported-location-op
mernst Oct 17, 2026
fa1aaac
Merge codespecs/fjalar master into register-params
mernst Oct 18, 2026
5029dfa
Merge codespecs/fjalar master into unsupported-location-op
mernst Oct 18, 2026
55422fd
Merge register-params into unsupported-location-op
mernst Oct 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions valgrind/fjalar/basic-tool/basic-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ void fjalar_tool_handle_function_entrance(FunctionExecutionState* f_state) {
0,
1,
0, 0,
0,
&basicAction);

VG_(printf)(" Function formal parameters:\n");
Expand All @@ -104,6 +105,7 @@ void fjalar_tool_handle_function_entrance(FunctionExecutionState* f_state) {
(Addr)f_state->virtualStack
+ f_state->virtualStackFPOffset,
f_state->FP,
f_state->entryRegs,
&basicAction);
}

Expand All @@ -116,6 +118,7 @@ void fjalar_tool_handle_function_exit(FunctionExecutionState* f_state) {
0,
0,
0, 0,
0,
&basicAction);

VG_(printf)(" Function formal parameters:\n");
Expand All @@ -126,6 +129,7 @@ void fjalar_tool_handle_function_exit(FunctionExecutionState* f_state) {
(Addr)f_state->virtualStack
+ f_state->virtualStackFPOffset,
f_state->FP,
f_state->entryRegs,
&basicAction);

VG_(printf)(" Return value:\n");
Expand Down
3 changes: 3 additions & 0 deletions valgrind/fjalar/disambig.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ void generateDisambigFile() {
0,
0,
0,
0,
&printDisambigAction);

FJALAR_DPRINTF("=> generateDisambigFile: Finished Globals\n\n");
Expand Down Expand Up @@ -239,13 +240,15 @@ void generateDisambigFile() {
0,
0,
0,
0,
&printDisambigAction);

visitVariableGroup(FUNCTION_RETURN_VAR,
cur_entry,
0,
0,
0,
0,
&printDisambigAction);

fputs("\n", disambig_fp);
Expand Down
63 changes: 55 additions & 8 deletions valgrind/fjalar/dwarf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,14 @@ decode_location_expression (unsigned char * data,

if(ll) {ll->atom = op;}

/* An op that Fjalar's evaluator cannot apply, such as an unreadable register,
DW_OP_stack_value, or DW_OP_plus (the evaluator has no operand
stack), makes a formal parameter's location unreadable.
DW_OP_piece is handled below. */
if (ok_to_harvest && op != DW_OP_nop && op != DW_OP_piece
&& !location_op_is_supported (op))
harvest_formal_param_location_unsupported (entry);

switch (op)
{
case DW_OP_addr:
Expand All @@ -1469,10 +1477,20 @@ decode_location_expression (unsigned char * data,
break;
case DW_OP_const1u:
SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
if (ok_to_harvest)
if (entry && tag_is_formal_parameter(entry->tag_name)) {
harvest_formal_param_location_atom(entry, op, uvalue);
harvest_formal_param_location_offset(entry, uvalue);
}
printf ("DW_OP_const1u: %lu", (unsigned long) uvalue);
break;
case DW_OP_const1s:
SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 1, end);
if (ok_to_harvest)
if (entry && tag_is_formal_parameter(entry->tag_name)) {
harvest_formal_param_location_atom(entry, op, svalue);
harvest_formal_param_location_offset(entry, svalue);
}
printf ("DW_OP_const1s: %ld", (long) svalue);
break;
case DW_OP_const2u:
Expand Down Expand Up @@ -1512,16 +1530,22 @@ decode_location_expression (unsigned char * data,
printf ("DW_OP_const4s: %ld", (long) svalue);
break;
case DW_OP_const8u:
SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
printf ("DW_OP_const8u: %lu ", (unsigned long) uvalue);
SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
printf ("%lu", (unsigned long) uvalue);
SAFE_BYTE_GET_AND_INC (uvalue, data, 8, end);
if (ok_to_harvest)
if (entry && tag_is_formal_parameter(entry->tag_name)) {
harvest_formal_param_location_atom(entry, op, uvalue);
harvest_formal_param_location_offset(entry, uvalue);
}
printf ("DW_OP_const8u: %s", dwarf_vmatoa ("u", uvalue));
break;
case DW_OP_const8s:
SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end);
printf ("DW_OP_const8s: %ld ", (long) svalue);
SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end);
printf ("%ld", (long) svalue);
SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 8, end);
if (ok_to_harvest)
if (entry && tag_is_formal_parameter(entry->tag_name)) {
harvest_formal_param_location_atom(entry, op, svalue);
harvest_formal_param_location_offset(entry, svalue);
}
printf ("DW_OP_const8s: %s", dwarf_vmatoa ("d", svalue));
break;
case DW_OP_constu:
READ_ULEB (uvalue, data, end);
Expand Down Expand Up @@ -1809,6 +1833,17 @@ decode_location_expression (unsigned char * data,
break;
case DW_OP_piece:
READ_ULEB (uvalue, data, end);
/* Fjalar can read a location that consists of one piece, if that
piece is the whole parameter; extractOneFormalParameterVar
checks the size. A piece that is not the last op means that
the parameter is split. A piece of size 0 covers no bytes. */
if (ok_to_harvest)
{
if (data == end && uvalue != 0)
harvest_formal_param_location_piece (entry, uvalue);
else
harvest_formal_param_location_unsupported (entry);
}
printf ("DW_OP_piece: %s", dwarf_vmatoa ("u", uvalue));
break;
case DW_OP_deref_size:
Expand Down Expand Up @@ -3821,6 +3856,10 @@ read_and_display_attr_value (unsigned long attribute,
if (ok_to_harvest) {
// frame base location list
harvest_frame_base(entry, DW_OP_list, uvalue);
// Fjalar does not evaluate a location list for a formal
// parameter, so it cannot read the parameter.
if (attribute == DW_AT_location)
harvest_formal_param_location_unsupported(entry);
}
printf ("(");
printf ("location list");
Expand Down Expand Up @@ -9710,6 +9749,14 @@ regname (unsigned int regno, int name_only_p)
return reg;
}

/* Returns the name of DWARF register REGNO, for Fjalar's debugging
output. */
const char *
dwarf_reg_name (unsigned int regno)
{
return regname (regno, 1);
}

static void
frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_regs)
{
Expand Down
18 changes: 18 additions & 0 deletions valgrind/fjalar/fjalar_dwarf.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,21 @@ location_expression_to_string(enum dwarf_location_atom op) {
return(0); // to stop compiler warning
}
}

// Returns true if Fjalar's location evaluator (in visitVariableGroup) applies
// op. A register operation (DW_OP_reg* or DW_OP_breg*) is supported only if
// Fjalar can read the register; Fjalar saves such a register, with its A and
// V bits and DynComp tags, at function entrance. extractOneFormalParameterVar
// further restricts which locations that use DW_OP_reg* it accepts.
int location_op_is_supported(unsigned int op) {
if ((op >= DW_OP_breg0) && (op <= DW_OP_breg31)) {
return (op - DW_OP_breg0) < FJALAR_NUM_DWARF_REGS;
}
if ((op >= DW_OP_reg0) && (op <= DW_OP_reg31)) {
return (op - DW_OP_reg0) < FJALAR_NUM_DWARF_REGS;
}
return ((op == DW_OP_deref)
|| ((op >= DW_OP_const1u) && (op <= DW_OP_consts))
|| (op == DW_OP_plus_uconst)
|| (op == DW_OP_fbreg));
}
13 changes: 13 additions & 0 deletions valgrind/fjalar/fjalar_dwarf.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,17 @@ typedef struct _dwarf_location {
// A conversion between DWARF location atoms and a string representation
const char* location_expression_to_string(enum dwarf_location_atom op);

// One more than the largest DWARF register number that Fjalar can
// read.
#if defined(VGA_amd64)
#define FJALAR_NUM_DWARF_REGS 16
#else
#define FJALAR_NUM_DWARF_REGS 9
#endif

// Returns true if visitVariableGroup can evaluate op in the location
// expression of a formal parameter. decode_location_expression
// records every such op in the formal parameter's dwarf_stack.
int location_op_is_supported(unsigned int op);

#endif /* FJALAR_DWARF_H */
64 changes: 64 additions & 0 deletions valgrind/fjalar/fjalar_include.h
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,11 @@ typedef struct _VariableEntry {
// location information will have validLoc = False
Bool validLoc;

// True if the DWARF information gives a location that Fjalar cannot
// read (see location_has_unsupported_op in typedata.h). Then
// validLoc is False and location_expression is empty.
Bool locationUnsupported;

// In some situations (The primary one being dealing with the
// formal parameters to main - see the MAIN STACK LAYOUT comment
// in fjalar_traversal.c for more information) the location of
Expand Down Expand Up @@ -690,6 +695,12 @@ typedef struct _FunctionEntry {

UInt nonce;

// Bit N is set if the valid location of some formal parameter uses
// DWARF register N (via DW_OP_regN or DW_OP_bregN) and Fjalar can
// read that register. Fjalar saves those registers at function
// entrance in FunctionExecutionState.entryRegs.
UInt entryRegsMask;

} FunctionEntry;


Expand Down Expand Up @@ -740,6 +751,36 @@ These data structures and functions provide mechanisms for runtime
traversals within data structures and arrays
**********************************************************************/

#if defined(VGA_amd64)
// The DWARF register number of the frame pointer
#define DWARF_FP_REG 6
#else
// The DWARF register number of the frame pointer
#define DWARF_FP_REG 5
#endif

// FJALAR_NUM_DWARF_REGS is defined in fjalar_dwarf.h.

// If atom is DW_OP_regN or DW_OP_bregN, sets *regNum to N and returns
// True. Otherwise, returns False.
Bool dwarf_op_reg_num(UInt atom, UInt* regNum);

// Returns true if Fjalar can read the register with the given DWARF
// register number.
Bool dwarf_reg_is_readable(UInt regNum);

// Returns the guest-state offset of the register with the given DWARF
// register number, which must be readable.
Int dwarf_reg_guest_offset(UInt regNum);

// Returns the current value of the register with the given DWARF
// register number, which must be readable.
Addr read_dwarf_reg(ThreadId tid, UInt regNum);

// Returns the name of the register with the given DWARF register
// number, for debugging output (defined in dwarf.c).
const HChar* dwarf_reg_name(UInt regNum);

// Entries for tracking the runtime state of functions at entrances
// and exits (used mainly by FunctionExecutionStateStack in
// fjalar_main.c). This class CANNOT BE SUBCLASSED because it is
Expand Down Expand Up @@ -789,8 +830,25 @@ typedef struct {
// should be invisible to the calling function anyways.
char* virtualStack;
int virtualStackByteSize; // Number of 1-byte entries in virtualStack
// Number of bytes in the allocation that starts at virtualStack,
// which also contains entryRegs
int allocByteSize;
int virtualStackFPOffset; // Where in the stack the frame pointer was

// The values at function entrance of the registers, indexed by
// DWARF register number: entryRegs[N] holds register N, if bit N
// of func->entryRegsMask is set. A formal parameter whose location is a
// register (DW_OP_reg*) is read from here, and the address of one
// whose location is relative to a register (DW_OP_breg*) is computed
// from here, at both entrance and exit, for the same reason as
// virtualStack: the function body and epilogue may change the
// registers. At function entrance,
// Fjalar copies those registers, with their A and V bits and
// DynComp tags, to entryRegs. entryRegs has FJALAR_NUM_DWARF_REGS
// elements and lies in the same allocation as virtualStack, just
// after it; it is null if func->entryRegsMask is 0.
Addr* entryRegs;


Addr lowSP;
} FunctionExecutionState;
Expand Down Expand Up @@ -955,6 +1013,12 @@ void visitVariableGroup(VariableOrigin varOrigin,
// address space (it's what we'll dereference)
Addr stackBaseAddr,
Addr stackBaseAddrGuest,
// The values of the registers at function
// entrance, which is
// FunctionExecutionState.entryRegs (only
// used for varOrigin == FUNCTION_FORMAL_PARAM
// and if stackBaseAddr is non-zero)
Addr* entryRegs,
// This function performs an action for each
// variable visited:
TraversalAction *performAction);
Expand Down
Loading