Fuzzers stress the assembler in ways no sane programmer would ever do.
One x86 oss-fuzz testcase (cleaned up a litte) was:
.sect .debug_frame
call x
.long x,0
.space 1
.long 0,0
The call insn leaves the frag data corresponding to a CIE
uninitialised until later in assembly, leading to reports of
uninitialised data access in ehopt.c:check_eh_frame.
Hack around this problem by noticing an insn has been assembled in
dwarf2_emit_insn. The existing frag has_code can't be used as that
leads to alignment complaints, so add a new segment_info flag.
* subsegs.h (struct segment_info_struct): Move bss and hadone
later. Rename hadone to stab_seen. Add insn_seen bitfield.
* dwarf2dbg.c (dwarf2_emit_insn): Set insn_seen.
* ehopt.c (check_eh_frame): Disable optimisation if insn_seen.
* stabs.c (s_stab_generic): Adjust for hadone rename.
{
struct dwarf2_line_info loc;
+ seg_info (now_seg)->insn_seen = 1;
+
if (debug_type != DEBUG_DWARF2
? !dwarf2_loc_directive_seen
: !seen_at_least_1_file ())
switch (d->state)
{
case state_idle:
- if (*pnbytes == 4)
+ /* This might be the size of the CIE or FDE. We want to know
+ the size so that we don't accidentally optimize across an FDE
+ boundary. We recognize the size in one of two forms: a
+ symbol which will later be defined as a difference, or a
+ subtraction of two symbols. Either way, we can tell when we
+ are at the end of the FDE because the symbol becomes defined
+ (in the case of a subtraction, the end symbol, from which the
+ start symbol is being subtracted). Other ways of describing
+ the size will not be optimized. */
+ if (*pnbytes == 4
+ && !seg_info (now_seg)->insn_seen
+ && (exp->X_op == O_symbol || exp->X_op == O_subtract)
+ && !S_IS_DEFINED (exp->X_add_symbol))
{
- /* This might be the size of the CIE or FDE. We want to know
- the size so that we don't accidentally optimize across an FDE
- boundary. We recognize the size in one of two forms: a
- symbol which will later be defined as a difference, or a
- subtraction of two symbols. Either way, we can tell when we
- are at the end of the FDE because the symbol becomes defined
- (in the case of a subtraction, the end symbol, from which the
- start symbol is being subtracted). Other ways of describing
- the size will not be optimized. */
- if ((exp->X_op == O_symbol || exp->X_op == O_subtract)
- && ! S_IS_DEFINED (exp->X_add_symbol))
- {
- d->state = state_saw_size;
- d->size_end_sym = exp->X_add_symbol;
- if (!d->cie_info.f)
- d->cie_info.f = frag_now;
- }
+ d->state = state_saw_size;
+ d->size_end_sym = exp->X_add_symbol;
+ if (!d->cie_info.f)
+ d->cie_info.f = frag_now;
}
break;
obstack_free (¬es, stab_secname);
subseg_set (stab, 0);
- if (!seg_info (stab)->hadone)
+ if (!seg_info (stab)->stab_seen)
{
bfd_set_section_flags (stab,
SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
#ifdef INIT_STAB_SECTION
INIT_STAB_SECTION (stab, stabstr);
#endif
- seg_info (stab)->hadone = 1;
+ seg_info (stab)->stab_seen = 1;
}
}
else if (freenames)
frag chain, even if it contains no (complete) frags. */
extern frchainS *frchain_now;
-typedef struct segment_info_struct {
+typedef struct segment_info_struct
+{
frchainS *frchainP;
- unsigned int hadone : 1;
-
- /* This field is set if this is a .bss section which does not really
- have any contents. Once upon a time a .bss section did not have
- any frags, but that is no longer true. This field prevent the
- SEC_HAS_CONTENTS flag from being set for the section even if
- there are frags. */
- unsigned int bss : 1;
/* Fixups for this segment. This is only valid after the frchains
are run together. */
/* Used by dwarf2dbg.c for this section's line table entries. */
void *dwarf2_line_seg;
- union {
+ /* This field is set if this is a .bss section which does not really
+ have any contents. Once upon a time a .bss section did not have
+ any frags, but that is no longer true. This field prevent the
+ SEC_HAS_CONTENTS flag from being set for the section even if
+ there are frags. */
+ unsigned int bss : 1;
+
+ /* Set whenever dwarf2_emit_insn is called, and used to disable
+ .eh_frame and .debug_frame optimisation. This is an anti-fuzzer
+ measure. */
+ unsigned int insn_seen : 1;
+
+ /* Used by the stabs code. */
+ unsigned int stab_seen : 1;
+
+ union
+ {
/* Current size of section holding stabs strings. */
unsigned long stab_string_size;
/* Initial frag for ELF. */
char *p;
- }
- stabu;
+ } stabu;
#ifdef NEED_LITERAL_POOL
unsigned long literal_pool_size;