lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <u43x62rul2jxorsljyo6qb2xztnx3wufwdnz32erfhsdomao4a@on7c5uvse4jc>
Date: Tue, 10 Jun 2025 18:23:31 -0700
From: Josh Poimboeuf <jpoimboe@...nel.org>
To: Alexandre Chartre <alexandre.chartre@...cle.com>
Cc: linux-kernel@...r.kernel.org, mingo@...nel.org, peterz@...radead.org
Subject: Re: [RFC 10/13] objtool: Trace instruction state changes during
 function validation

On Fri, Jun 06, 2025 at 05:34:37PM +0200, Alexandre Chartre wrote:
> +++ b/tools/objtool/check.c
> @@ -111,6 +111,111 @@ static void vtrace_insn(struct instruction *insn, const char *format, ...)
>  		free((char *)addr_str);
>  }
>  
> +/*
> + * Macros to trace CFI state attributes changes.
> + */
> +
> +#define VTRACE_CFI_ATTR(attr, prev, next, fmt, ...)			\
> +	do {								\
> +		if ((prev)->attr != (next)->attr)			\
> +			VTRACE_PRINTF("%s=" fmt " ", #attr, __VA_ARGS__); \
> +	} while (0)
> +
> +#define VTRACE_CFI_ATTR_BOOL(attr, prev, next)				\
> +	VTRACE_CFI_ATTR(attr, prev, next,				\
> +			"%s", (next)->attr ? "true" : "false")
> +
> +#define VTRACE_CFI_ATTR_NUM(attr, prev, next, fmt)			\
> +	VTRACE_CFI_ATTR(attr, prev, next, fmt, (next)->attr)
> +
> +/*
> + * Functions and macros to trace CFI registers changes.
> + */
> +
> +static void vtrace_cfi_register(const char *prefix, int reg, const char *fmt,
> +				int base_prev, int offset_prev,
> +				int base_next, int offset_next)
> +{

In keeping with the namespace of the other vtrace_cfi_reg_*()
functions/macros, I'd suggest calling this vtrace_cfi_reg()

(or trace_cfi_reg() if we go with my previous suggestion to remove the "v"
everywhere)

> +	const char *rname;
> +
> +	if (base_prev == base_next && offset_prev == offset_next)
> +		return;
> +
> +	if (prefix)
> +		VTRACE_PRINTF("%s:", prefix);
> +
> +	rname = register_name(reg);

For similar reasons, "register_name()" -> "reg_name()".

> +
> +	if (base_next == CFI_UNDEFINED) {
> +		VTRACE_PRINTF("%1$s=<undef> ", rname);
> +	} else {
> +		VTRACE_PRINTF(fmt, rname,
> +			      register_name(base_next), offset_next);
> +	}
> +}
> +
> +static void vtrace_cfi_reg_value(const char *prefix, int reg,
> +				 int base_prev, int offset_prev,
> +				 int base_next, int offset_next)
> +{
> +	vtrace_cfi_register(prefix, reg, "%1$s=%2$s%3$+d ",
> +			    base_prev, offset_prev, base_next, offset_next);
> +}
> +
> +static void vtrace_cfi_reg_reference(const char *prefix, int reg,
> +				     int base_prev, int offset_prev,
> +				     int base_next, int offset_next)
> +{
> +	vtrace_cfi_register(prefix, reg, "%1$s=(%2$s%3$+d) ",
> +			    base_prev, offset_prev, base_next, offset_next);
> +}
> +
> +#define VTRACE_CFI_REG_VAL(reg, prev, next)				\
> +	vtrace_cfi_reg_value(NULL, reg, prev.base, prev.offset,		\
> +			     next.base, next.offset)
> +
> +#define VTRACE_CFI_REG_REF(reg, prev, next)				\
> +	vtrace_cfi_reg_reference(NULL, reg, prev.base, prev.offset,	\
> +				 next.base, next.offset)

For similar reasons, "*_val()" and "*_ref()".

> +
> +static void vtrace_insn_state(struct instruction *insn,
> +			      struct insn_state *sprev,
> +			      struct insn_state *snext)
> +{
> +	struct cfi_state *cprev, *cnext;
> +	int i;
> +
> +	if (memcmp(sprev, snext, sizeof(struct insn_state)) == 0)
> +		return;

"!memcmp()"

> @@ -3698,6 +3803,7 @@ static int validate_insn(struct objtool_file *file, struct symbol *func,
>  			 struct instruction *prev_insn, struct instruction *next_insn,
>  			 bool *validate_nextp)
>  {
> +	struct insn_state state_prev;

Can we call it prev_state for consistency with prev_insn?

>  	struct alternative *alt;
>  	u8 visited;
>  	int ret;
> @@ -3814,7 +3920,15 @@ static int validate_insn(struct objtool_file *file, struct symbol *func,
>  	if (skip_alt_group(insn))
>  		return 0;
>  
> -	if (handle_insn_ops(insn, next_insn, statep))
> +	if (vtrace)
> +		state_prev = *statep;
> +
> +	ret = handle_insn_ops(insn, next_insn, statep);
> +
> +	if (vtrace)
> +		vtrace_insn_state(insn, &state_prev, statep);

For consistency with the other tracing, can the trace statement be a
capitalized macro, with the "vtrace" check hidden?

	state_prev = *statep;
	ret = handle_insn_ops(insn, next_insn, statep);
	TRACE_INSN_STATE(insn, &state_prev, statep);

> +++ b/tools/objtool/disas.c
> @@ -29,6 +29,33 @@ struct disas_context {
>  	((*(dinfo)->fprintf_func)((dinfo)->stream, __VA_ARGS__))
>  
>  
> +#define REGISTER_NAME_MAXLEN   16
> +
> +/*
> + * Return the name of a register. Note that the same static buffer
> + * is returned if the name is dynamically generated.
> + */
> +const char *register_name(unsigned int reg)
> +{
> +	static char rname_buffer[REGISTER_NAME_MAXLEN];
> +
> +	switch (reg) {
> +	case CFI_UNDEFINED:
> +		return "<undefined>";
> +	case CFI_CFA:
> +		return "cfa";
> +	case CFI_SP_INDIRECT:
> +		return "(sp)";
> +	case CFI_BP_INDIRECT:
> +		return "(bp)";
> +	}
> +
> +	if (snprintf(rname_buffer, REGISTER_NAME_MAXLEN, "r%d", reg) == 1)
> +		return NULL;
> +
> +	return (const char *)rname_buffer;
> +}
> +

Would this not be a better fit as a static function in check.c?  Its
only callers are there.  And it references the CFI stuff.

Or we might also want to consider moving all the trace_*() functions to
their own file, trace.c or so.

-- 
Josh

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ