Пример #1
0
static void
dot_cfi_endproc (int ignored ATTRIBUTE_UNUSED)
{
    if (frchain_now->frch_cfi_data == NULL)
    {
        as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
        ignore_rest_of_line ();
        return;
    }

    cfi_end_fde (symbol_temp_new_now ());

    demand_empty_rest_of_line ();
}
Пример #2
0
static void
output_fde (struct fde_entry *fde, struct cie_entry *cie,
	    struct cfi_insn_data *first, int align)
{
  symbolS *after_size_address, *end_address;
  expressionS exp;

  after_size_address = symbol_temp_make ();
  end_address = symbol_temp_make ();

  exp.X_op = O_subtract;
  exp.X_add_symbol = end_address;
  exp.X_op_symbol = after_size_address;
  exp.X_add_number = 0;
  emit_expr (&exp, 4);				/* Length.  */
  symbol_set_value_now (after_size_address);

  exp.X_add_symbol = after_size_address;
  exp.X_op_symbol = cie->start_address;
  emit_expr (&exp, 4);				/* CIE offset.  */

#ifdef DIFF_EXPR_OK  
  exp.X_add_symbol = fde->start_address;
  exp.X_op_symbol = symbol_temp_new_now ();
  emit_expr (&exp, 4);				/* Code offset.  */
#else
  exp.X_op = O_symbol;
  exp.X_add_symbol = fde->start_address;
  exp.X_op_symbol = NULL;
#ifdef tc_cfi_emit_pcrel_expr
  tc_cfi_emit_pcrel_expr (&exp, 4);		/* Code offset.  */
#else
  emit_expr (&exp, 4);				/* Code offset.  */
#endif
  exp.X_op = O_subtract;
#endif

  exp.X_add_symbol = fde->end_address;
  exp.X_op_symbol = fde->start_address;		/* Code length.  */
  emit_expr (&exp, 4);

  out_uleb128 (0);				/* Augmentation size.  */

  for (; first; first = first->next)
    output_cfi_insn (first);

  frag_align (align, DW_CFA_nop, 0);
  symbol_set_value_now (end_address);
}
Пример #3
0
static void
output_cie (struct cie_entry *cie)
{
  symbolS *after_size_address, *end_address;
  expressionS exp;
  struct cfi_insn_data *i;

  cie->start_address = symbol_temp_new_now ();
  after_size_address = symbol_temp_make ();
  end_address = symbol_temp_make ();

  exp.X_op = O_subtract;
  exp.X_add_symbol = end_address;
  exp.X_op_symbol = after_size_address;
  exp.X_add_number = 0;

  emit_expr (&exp, 4);				/* Length.  */
  symbol_set_value_now (after_size_address);
  out_four (0);					/* CIE id.  */
  out_one (DW_CIE_VERSION);			/* Version.  */
  out_one ('z');				/* Augmentation.  */
  out_one ('R');
  if (cie->signal_frame)
    out_one ('S');
  out_one (0);
  out_uleb128 (DWARF2_LINE_MIN_INSN_LENGTH);	/* Code alignment.  */
  out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT);	/* Data alignment.  */
  if (DW_CIE_VERSION == 1)			/* Return column.  */
    out_one (cie->return_column);
  else
    out_uleb128 (cie->return_column);
  out_uleb128 (1);				/* Augmentation size.  */
#if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
  out_one (DW_EH_PE_pcrel | DW_EH_PE_sdata4);
#else
  out_one (DW_EH_PE_sdata4);
#endif

  if (cie->first)
    for (i = cie->first; i != cie->last; i = i->next)
      output_cfi_insn (i);

  frag_align (2, DW_CFA_nop, 0);
  symbol_set_value_now (end_address);
}
Пример #4
0
static void
dot_cfi_endproc (int ignored ATTRIBUTE_UNUSED)
{
  struct fde_entry *fde;

  if (frchain_now->frch_cfi_data == NULL)
    {
      as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
      ignore_rest_of_line ();
      return;
    }

  fde = frchain_now->frch_cfi_data->cur_fde_data;

  cfi_end_fde (symbol_temp_new_now ());

  demand_empty_rest_of_line ();

  if ((cfi_sections & CFI_EMIT_target) != 0)
    tc_cfi_endproc (fde);
}
Пример #5
0
static void
dot_cfi_startproc (int ignored ATTRIBUTE_UNUSED)
{
  int simple = 0;

  if (frchain_now->frch_cfi_data != NULL)
    {
      as_bad (_("previous CFI entry not closed (missing .cfi_endproc)"));
      ignore_rest_of_line ();
      return;
    }

  cfi_new_fde (symbol_temp_new_now ());

  SKIP_WHITESPACE ();
  if (is_name_beginner (*input_line_pointer))
    {
      char *name, c;

      name = input_line_pointer;
      c = get_symbol_end ();

      if (strcmp (name, "simple") == 0)
	{
	  simple = 1;
	  *input_line_pointer = c;
	}
      else
	input_line_pointer = name;
    }
  demand_empty_rest_of_line ();

  frchain_now->frch_cfi_data->cur_cfa_offset = 0;
  if (!simple)
    tc_cfi_frame_initial_instructions ();

  if ((cfi_sections & CFI_EMIT_target) != 0)
    tc_cfi_startproc ();
}
Пример #6
0
static void
dwarf2_flush_pending_lines (symbolS *label)
{
  if (pending_lines)
    {
      struct line_subseg *lss;
      struct line_entry *e;

      if (!label)
	label = symbol_temp_new_now ();

      for (e = pending_lines; e; e = e->next)
	e->label = label;

      lss = get_line_subseg (now_seg, now_subseg);
      *lss->ptail = pending_lines;
      lss->ptail = pending_lines_tail;

      pending_lines = NULL;
      pending_lines_tail = &pending_lines;
    }
}
Пример #7
0
static void
dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
{
    struct cfi_escape_data *head, **tail, *e;
    struct cfi_insn_data *insn;

    if (frchain_now->frch_cfi_data == NULL)
    {
        as_bad (_("CFI instruction used without previous .cfi_startproc"));
        ignore_rest_of_line ();
        return;
    }

    /* If the last address was not at the current PC, advance to current.  */
    if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now
            || S_GET_VALUE (frchain_now->frch_cfi_data->last_address)
            != frag_now_fix ())
        cfi_add_advance_loc (symbol_temp_new_now ());

    tail = &head;
    do
    {
        e = xmalloc (sizeof (*e));
        do_parse_cons_expression (&e->exp, 1);
        *tail = e;
        tail = &e->next;
    }
    while (*input_line_pointer++ == ',');
    *tail = NULL;

    insn = alloc_cfi_insn_data ();
    insn->insn = CFI_escape;
    insn->u.esc = head;

    --input_line_pointer;
    demand_empty_rest_of_line ();
}
Пример #8
0
static int
out_header (asection *sec, expressionS *exp)
{
  symbolS *start_sym;
  symbolS *end_sym;

  subseg_set (sec, 0);
  start_sym = symbol_temp_new_now ();;
  end_sym = symbol_temp_make ();

  /* Total length of the information.  */
  exp->X_op = O_subtract;
  exp->X_add_symbol = end_sym;
  exp->X_op_symbol = start_sym;

  switch (DWARF2_FORMAT (sec))
    {
    case dwarf2_format_32bit:
      exp->X_add_number = -4;
      emit_expr (exp, 4);
      return 4;

    case dwarf2_format_64bit:
      exp->X_add_number = -12;
      out_four (-1);
      emit_expr (exp, 8);
      return 8;

    case dwarf2_format_64bit_irix:
      exp->X_add_number = -8;
      emit_expr (exp, 8);
      return 8;
    }

  as_fatal (_("internal error: unknown dwarf2 format"));
  return 0;
}
Пример #9
0
static void
dot_cfi (int arg)
{
    offsetT offset;
    unsigned reg1, reg2;

    if (frchain_now->frch_cfi_data == NULL)
    {
        as_bad (_("CFI instruction used without previous .cfi_startproc"));
        ignore_rest_of_line ();
        return;
    }

    /* If the last address was not at the current PC, advance to current.  */
    if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now
            || S_GET_VALUE (frchain_now->frch_cfi_data->last_address)
            != frag_now_fix ())
        cfi_add_advance_loc (symbol_temp_new_now ());

    switch (arg)
    {
    case DW_CFA_offset:
        reg1 = cfi_parse_reg ();
        cfi_parse_separator ();
        offset = cfi_parse_const ();
        cfi_add_CFA_offset (reg1, offset);
        break;

    case CFI_rel_offset:
        reg1 = cfi_parse_reg ();
        cfi_parse_separator ();
        offset = cfi_parse_const ();
        cfi_add_CFA_offset (reg1,
                            offset - frchain_now->frch_cfi_data->cur_cfa_offset);
        break;

    case DW_CFA_def_cfa:
        reg1 = cfi_parse_reg ();
        cfi_parse_separator ();
        offset = cfi_parse_const ();
        cfi_add_CFA_def_cfa (reg1, offset);
        break;

    case DW_CFA_register:
        reg1 = cfi_parse_reg ();
        cfi_parse_separator ();
        reg2 = cfi_parse_reg ();
        cfi_add_CFA_register (reg1, reg2);
        break;

    case DW_CFA_def_cfa_register:
        reg1 = cfi_parse_reg ();
        cfi_add_CFA_def_cfa_register (reg1);
        break;

    case DW_CFA_def_cfa_offset:
        offset = cfi_parse_const ();
        cfi_add_CFA_def_cfa_offset (offset);
        break;

    case CFI_adjust_cfa_offset:
        offset = cfi_parse_const ();
        cfi_add_CFA_def_cfa_offset (frchain_now->frch_cfi_data->cur_cfa_offset
                                    + offset);
        break;

    case DW_CFA_restore:
        for (;;)
        {
            reg1 = cfi_parse_reg ();
            cfi_add_CFA_restore (reg1);
            SKIP_WHITESPACE ();
            if (*input_line_pointer != ',')
                break;
            ++input_line_pointer;
        }
        break;

    case DW_CFA_undefined:
        for (;;)
        {
            reg1 = cfi_parse_reg ();
            cfi_add_CFA_undefined (reg1);
            SKIP_WHITESPACE ();
            if (*input_line_pointer != ',')
                break;
            ++input_line_pointer;
        }
        break;

    case DW_CFA_same_value:
        reg1 = cfi_parse_reg ();
        cfi_add_CFA_same_value (reg1);
        break;

    case CFI_return_column:
        reg1 = cfi_parse_reg ();
        cfi_set_return_column (reg1);
        break;

    case DW_CFA_remember_state:
        cfi_add_CFA_remember_state ();
        break;

    case DW_CFA_restore_state:
        cfi_add_CFA_restore_state ();
        break;

    case DW_CFA_GNU_window_save:
        cfi_add_CFA_insn (DW_CFA_GNU_window_save);
        break;

    case CFI_signal_frame:
        frchain_now->frch_cfi_data->cur_fde_data->signal_frame = 1;
        break;

    default:
        abort ();
    }

    demand_empty_rest_of_line ();
}
Пример #10
0
static void
output_fde (struct fde_entry *fde, struct cie_entry *cie,
            struct cfi_insn_data *first, int align)
{
    symbolS *after_size_address, *end_address;
    expressionS exp;
    offsetT augmentation_size;

    after_size_address = symbol_temp_make ();
    end_address = symbol_temp_make ();

    exp.X_op = O_subtract;
    exp.X_add_symbol = end_address;
    exp.X_op_symbol = after_size_address;
    exp.X_add_number = 0;
    emit_expr (&exp, 4);				/* Length.  */
    symbol_set_value_now (after_size_address);

    exp.X_add_symbol = after_size_address;
    exp.X_op_symbol = cie->start_address;
    emit_expr (&exp, 4);				/* CIE offset.  */

#ifdef DIFF_EXPR_OK
    exp.X_add_symbol = fde->start_address;
    exp.X_op_symbol = symbol_temp_new_now ();
    emit_expr (&exp, 4);				/* Code offset.  */
#else
    exp.X_op = O_symbol;
    exp.X_add_symbol = fde->start_address;
    exp.X_op_symbol = NULL;
#ifdef tc_cfi_emit_pcrel_expr
    tc_cfi_emit_pcrel_expr (&exp, 4);		/* Code offset.  */
#else
    emit_expr (&exp, 4);				/* Code offset.  */
#endif
    exp.X_op = O_subtract;
#endif

    exp.X_add_symbol = fde->end_address;
    exp.X_op_symbol = fde->start_address;		/* Code length.  */
    emit_expr (&exp, 4);

    augmentation_size = encoding_size (fde->lsda_encoding);
    out_uleb128 (augmentation_size);		/* Augmentation size.  */

    if (fde->lsda_encoding != DW_EH_PE_omit)
    {
        exp = fde->lsda;
        if ((fde->lsda_encoding & 0x70) == DW_EH_PE_pcrel)
        {
#ifdef DIFF_EXPR_OK
            exp.X_op = O_subtract;
            exp.X_op_symbol = symbol_temp_new_now ();
            emit_expr (&exp, augmentation_size);
#elif defined (tc_cfi_emit_pcrel_expr)
            tc_cfi_emit_pcrel_expr (&exp, augmentation_size);
#else
            abort ();
#endif
        }
        else
            emit_expr (&exp, augmentation_size);
    }

    for (; first; first = first->next)
        output_cfi_insn (first);

    frag_align (align, DW_CFA_nop, 0);
    symbol_set_value_now (end_address);
}
Пример #11
0
static void
out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg)
{
  char producer[128];
  char *comp_dir;
  expressionS expr;
  symbolS *info_start;
  symbolS *info_end;
  char *p;
  int len;
  enum dwarf2_format d2f;
  int sizeof_offset;

  subseg_set (info_seg, 0);

  info_start = symbol_temp_new_now ();
  info_end = symbol_temp_make ();

  /* Compilation Unit length.  */
  expr.X_op = O_subtract;
  expr.X_add_symbol = info_end;
  expr.X_op_symbol = info_start;

  d2f = DWARF2_FORMAT ();
  if (d2f == dwarf2_format_32bit)
    {
      expr.X_add_number = -4;
      emit_expr (&expr, 4);
      sizeof_offset = 4;
    }
  else if (d2f == dwarf2_format_64bit)
    {
      expr.X_add_number = -12;
      out_four (-1);
      emit_expr (&expr, 8);
      sizeof_offset = 8;
    }
  else if (d2f == dwarf2_format_64bit_irix)
    {
      expr.X_add_number = -8;
      emit_expr (&expr, 8);
      sizeof_offset = 8;
    }
  else
    {
      as_fatal (_("internal error: unknown dwarf2 format"));
    }

  /* DWARF version.  */
  out_two (2);

  /* .debug_abbrev offset */
  TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset);

  /* Target address size.  */
  out_byte (sizeof_address);

  /* DW_TAG_compile_unit DIE abbrev */
  out_uleb128 (1);

  /* DW_AT_stmt_list */
  /* ??? sizeof_offset */
  TC_DWARF2_EMIT_OFFSET (section_symbol (line_seg), 4);

  /* These two attributes may only be emitted if all of the code is
     contiguous.  Multiple sections are not that.  */
  if (all_segs->next == NULL)
    {
      /* DW_AT_low_pc */
      expr.X_op = O_symbol;
      expr.X_add_symbol = all_segs->text_start;
      expr.X_add_number = 0;
      emit_expr (&expr, sizeof_address);

      /* DW_AT_high_pc */
      expr.X_op = O_symbol;
      expr.X_add_symbol = all_segs->text_end;
      expr.X_add_number = 0;
      emit_expr (&expr, sizeof_address);
    }

  /* DW_AT_name.  We don't have the actual file name that was present
     on the command line, so assume files[1] is the main input file.
     We're not supposed to get called unless at least one line number
     entry was emitted, so this should always be defined.  */
  if (!files || files_in_use < 1)
    abort ();
  if (files[1].dir)
    {
      len = strlen (dirs[files[1].dir]);
      p = frag_more (len + 1);
      memcpy (p, dirs[files[1].dir], len);
      p[len] = '/';
    }
  len = strlen (files[1].filename) + 1;
  p = frag_more (len);
  memcpy (p, files[1].filename, len);

  /* DW_AT_comp_dir */
  comp_dir = getpwd ();
  len = strlen (comp_dir) + 1;
  p = frag_more (len);
  memcpy (p, comp_dir, len);

  /* DW_AT_producer */
  sprintf (producer, "GNU AS %s", VERSION);
  len = strlen (producer) + 1;
  p = frag_more (len);
  memcpy (p, producer, len);

  /* DW_AT_language.  Yes, this is probably not really MIPS, but the
     dwarf2 draft has no standard code for assembler.  */
  out_two (DW_LANG_Mips_Assembler);

  symbol_set_value_now (info_end);
}
Пример #12
0
static void
out_debug_line (segT line_seg)
{
  expressionS expr;
  symbolS *line_start;
  symbolS *prologue_end;
  symbolS *line_end;
  struct line_seg *s;
  enum dwarf2_format d2f;
  int sizeof_offset;

  subseg_set (line_seg, 0);

  line_start = symbol_temp_new_now ();
  prologue_end = symbol_temp_make ();
  line_end = symbol_temp_make ();

  /* Total length of the information for this compilation unit.  */
  expr.X_op = O_subtract;
  expr.X_add_symbol = line_end;
  expr.X_op_symbol = line_start;

  d2f = DWARF2_FORMAT ();
  if (d2f == dwarf2_format_32bit)
    {
      expr.X_add_number = -4;
      emit_expr (&expr, 4);
      sizeof_offset = 4;
    }
  else if (d2f == dwarf2_format_64bit)
    {
      expr.X_add_number = -12;
      out_four (-1);
      emit_expr (&expr, 8);
      sizeof_offset = 8;
    }
  else if (d2f == dwarf2_format_64bit_irix)
    {
      expr.X_add_number = -8;
      emit_expr (&expr, 8);
      sizeof_offset = 8;
    }
  else
    {
      as_fatal (_("internal error: unknown dwarf2 format"));
    }

  /* Version.  */
  out_two (2);

  /* Length of the prologue following this length.  */
  expr.X_op = O_subtract;
  expr.X_add_symbol = prologue_end;
  expr.X_op_symbol = line_start;
  expr.X_add_number = - (4 + 2 + 4);
  emit_expr (&expr, sizeof_offset);

  /* Parameters of the state machine.  */
  out_byte (DWARF2_LINE_MIN_INSN_LENGTH);
  out_byte (DWARF2_LINE_DEFAULT_IS_STMT);
  out_byte (DWARF2_LINE_BASE);
  out_byte (DWARF2_LINE_RANGE);
  out_byte (DWARF2_LINE_OPCODE_BASE);

  /* Standard opcode lengths.  */
  out_byte (0);			/* DW_LNS_copy */
  out_byte (1);			/* DW_LNS_advance_pc */
  out_byte (1);			/* DW_LNS_advance_line */
  out_byte (1);			/* DW_LNS_set_file */
  out_byte (1);			/* DW_LNS_set_column */
  out_byte (0);			/* DW_LNS_negate_stmt */
  out_byte (0);			/* DW_LNS_set_basic_block */
  out_byte (0);			/* DW_LNS_const_add_pc */
  out_byte (1);			/* DW_LNS_fixed_advance_pc */

  out_file_list ();

  symbol_set_value_now (prologue_end);

  /* For each section, emit a statement program.  */
  for (s = all_segs; s; s = s->next)
    process_entries (s->seg, s->head->head);

  symbol_set_value_now (line_end);
}
Пример #13
0
static void
dot_cfi_val_encoded_addr (int ignored ATTRIBUTE_UNUSED)
{
  struct cfi_insn_data *insn_ptr;
  offsetT encoding;

  if (frchain_now->frch_cfi_data == NULL)
    {
      as_bad (_("CFI instruction used without previous .cfi_startproc"));
      ignore_rest_of_line ();
      return;
    }

  /* If the last address was not at the current PC, advance to current.  */
  if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now
      || S_GET_VALUE (frchain_now->frch_cfi_data->last_address)
	 != frag_now_fix ())
    cfi_add_advance_loc (symbol_temp_new_now ());

  insn_ptr = alloc_cfi_insn_data ();
  insn_ptr->insn = CFI_val_encoded_addr;

  insn_ptr->u.ea.reg = cfi_parse_reg ();

  cfi_parse_separator ();
  encoding = cfi_parse_const ();
  if ((encoding & 0xff) != encoding
      || ((encoding & 0x70) != 0
#if CFI_DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
	  && (encoding & 0x70) != DW_EH_PE_pcrel
#endif
	  )
	 /* leb128 can be handled, but does something actually need it?  */
      || (encoding & 7) == DW_EH_PE_uleb128
      || (encoding & 7) > DW_EH_PE_udata8)
    {
      as_bad (_("invalid or unsupported encoding in .cfi_lsda"));
      encoding = DW_EH_PE_omit;
    }

  cfi_parse_separator ();
  expression_and_evaluate (&insn_ptr->u.ea.exp);
  switch (insn_ptr->u.ea.exp.X_op)
    {
    case O_symbol:
      break;
    case O_constant:
      if ((encoding & 0x70) != DW_EH_PE_pcrel)
        break;
    default:
      encoding = DW_EH_PE_omit;
      break;
    }

  insn_ptr->u.ea.encoding = encoding;
  if (encoding == DW_EH_PE_omit)
    {
      as_bad (_("wrong third argument to .cfi_val_encoded_addr"));
      ignore_rest_of_line ();
      return;
    }

  demand_empty_rest_of_line ();
}
Пример #14
0
static void
output_fde (struct fde_entry *fde, struct cie_entry *cie,
	    bfd_boolean eh_frame, struct cfi_insn_data *first,
	    int align)
{
  symbolS *after_size_address, *end_address;
  expressionS exp;
  offsetT augmentation_size;
  enum dwarf2_format fmt = DWARF2_FORMAT (now_seg);
  int offset_size;
  int addr_size;

  after_size_address = symbol_temp_make ();
  end_address = symbol_temp_make ();

  exp.X_op = O_subtract;
  exp.X_add_symbol = end_address;
  exp.X_op_symbol = after_size_address;
  exp.X_add_number = 0;
  if (eh_frame || fmt == dwarf2_format_32bit)
    offset_size = 4;
  else
    {
      if (fmt == dwarf2_format_64bit)
	out_four (-1);
      offset_size = 8;
    }
  emit_expr (&exp, offset_size);		/* Length.  */
  symbol_set_value_now (after_size_address);

  if (eh_frame)
    {
      exp.X_op = O_subtract;
      exp.X_add_symbol = after_size_address;
      exp.X_op_symbol = cie->start_address;
      exp.X_add_number = 0;
      emit_expr (&exp, offset_size);		/* CIE offset.  */
    }
  else
    {
      TC_DWARF2_EMIT_OFFSET (cie->start_address, offset_size);
    }

  if (eh_frame)
    {
      exp.X_op = O_subtract;
      exp.X_add_number = 0;
#if CFI_DIFF_EXPR_OK
      exp.X_add_symbol = fde->start_address;
      exp.X_op_symbol = symbol_temp_new_now ();
      emit_expr (&exp, DWARF2_FDE_RELOC_SIZE);	/* Code offset.  */
#else
      exp.X_op = O_symbol;
      exp.X_add_symbol = fde->start_address;
#ifdef tc_cfi_emit_pcrel_expr
      tc_cfi_emit_pcrel_expr (&exp, DWARF2_FDE_RELOC_SIZE);	 /* Code offset.  */
#else
      emit_expr (&exp, DWARF2_FDE_RELOC_SIZE);	/* Code offset.  */
#endif
#endif
      addr_size = DWARF2_FDE_RELOC_SIZE;
    }
  else
    {
      exp.X_op = O_symbol;
      exp.X_add_symbol = fde->start_address;
      exp.X_add_number = 0;
      addr_size = DWARF2_ADDR_SIZE (stdoutput);
      emit_expr (&exp, addr_size);
    }

  exp.X_op = O_subtract;
  exp.X_add_symbol = fde->end_address;
  exp.X_op_symbol = fde->start_address;		/* Code length.  */
  exp.X_add_number = 0;
  emit_expr (&exp, addr_size);

  augmentation_size = encoding_size (fde->lsda_encoding);
  if (eh_frame)
    out_uleb128 (augmentation_size);		/* Augmentation size.  */

  if (fde->lsda_encoding != DW_EH_PE_omit)
    {
      exp = fde->lsda;
      if ((fde->lsda_encoding & 0x70) == DW_EH_PE_pcrel)
	{
#if CFI_DIFF_LSDA_OK
	  exp.X_op = O_subtract;
	  exp.X_op_symbol = symbol_temp_new_now ();
	  emit_expr (&exp, augmentation_size);
#elif defined (tc_cfi_emit_pcrel_expr)
	  tc_cfi_emit_pcrel_expr (&exp, augmentation_size);
#else
	  abort ();
#endif
	}
      else
	emit_expr (&exp, augmentation_size);
    }

  for (; first; first = first->next)
    if (CUR_SEG (first) == CUR_SEG (fde))
      output_cfi_insn (first);

  frag_align (align, DW_CFA_nop, 0);
  symbol_set_value_now (end_address);
}
Пример #15
0
static void
output_cie (struct cie_entry *cie, bfd_boolean eh_frame, int align)
{
  symbolS *after_size_address, *end_address;
  expressionS exp;
  struct cfi_insn_data *i;
  offsetT augmentation_size;
  int enc;
  enum dwarf2_format fmt = DWARF2_FORMAT (now_seg);

  cie->start_address = symbol_temp_new_now ();
  after_size_address = symbol_temp_make ();
  end_address = symbol_temp_make ();

  exp.X_op = O_subtract;
  exp.X_add_symbol = end_address;
  exp.X_op_symbol = after_size_address;
  exp.X_add_number = 0;

  if (eh_frame || fmt == dwarf2_format_32bit)
    emit_expr (&exp, 4);			/* Length.  */
  else
    {
      if (fmt == dwarf2_format_64bit)
	out_four (-1);
      emit_expr (&exp, 8);			/* Length.  */
    }
  symbol_set_value_now (after_size_address);
  if (eh_frame)
    out_four (0);				/* CIE id.  */
  else
    {
      out_four (-1);				/* CIE id.  */
      if (fmt != dwarf2_format_32bit)
	out_four (-1);
    }
  out_one (DW_CIE_VERSION);			/* Version.  */
  if (eh_frame)
    {
      out_one ('z');				/* Augmentation.  */
      if (cie->per_encoding != DW_EH_PE_omit)
	out_one ('P');
      if (cie->lsda_encoding != DW_EH_PE_omit)
	out_one ('L');
      out_one ('R');
    }
  if (cie->signal_frame)
    out_one ('S');
  out_one (0);
  out_uleb128 (DWARF2_LINE_MIN_INSN_LENGTH);	/* Code alignment.  */
  out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT);	/* Data alignment.  */
  if (DW_CIE_VERSION == 1)			/* Return column.  */
    out_one (cie->return_column);
  else
    out_uleb128 (cie->return_column);
  if (eh_frame)
    {
      augmentation_size = 1 + (cie->lsda_encoding != DW_EH_PE_omit);
      if (cie->per_encoding != DW_EH_PE_omit)
	augmentation_size += 1 + encoding_size (cie->per_encoding);
      out_uleb128 (augmentation_size);		/* Augmentation size.  */

      if (cie->per_encoding != DW_EH_PE_omit)
	{
	  offsetT size = encoding_size (cie->per_encoding);
	  out_one (cie->per_encoding);
	  exp = cie->personality;
	  if ((cie->per_encoding & 0x70) == DW_EH_PE_pcrel)
	    {
#if CFI_DIFF_EXPR_OK
	      exp.X_op = O_subtract;
	      exp.X_op_symbol = symbol_temp_new_now ();
	      emit_expr (&exp, size);
#elif defined (tc_cfi_emit_pcrel_expr)
	      tc_cfi_emit_pcrel_expr (&exp, size);
#else
	      abort ();
#endif
	    }
	  else
	    emit_expr (&exp, size);
	}

      if (cie->lsda_encoding != DW_EH_PE_omit)
	out_one (cie->lsda_encoding);
    }

  switch (DWARF2_FDE_RELOC_SIZE)
    {
    case 2:
      enc = DW_EH_PE_sdata2;
      break;
    case 4:
      enc = DW_EH_PE_sdata4;
      break;
    case 8:
      enc = DW_EH_PE_sdata8;
      break;
    default:
      abort ();
    }
#if CFI_DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
  enc |= DW_EH_PE_pcrel;
#endif
  if (eh_frame)
    out_one (enc);

  if (cie->first)
    {
      for (i = cie->first; i != cie->last; i = i->next)
        {
	  if (CUR_SEG (i) != CUR_SEG (cie))
	    continue;
	  output_cfi_insn (i);
	}
    }

  frag_align (align, DW_CFA_nop, 0);
  symbol_set_value_now (end_address);
}
Пример #16
0
static void
output_cfi_insn (struct cfi_insn_data *insn)
{
  offsetT offset;
  unsigned int regno;

  switch (insn->insn)
    {
    case DW_CFA_advance_loc:
      {
	symbolS *from = insn->u.ll.lab1;
	symbolS *to = insn->u.ll.lab2;

	if (symbol_get_frag (to) == symbol_get_frag (from))
	  {
	    addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from);
	    addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH;

	    if (scaled <= 0x3F)
	      out_one (DW_CFA_advance_loc + scaled);
	    else if (scaled <= 0xFF)
	      {
		out_one (DW_CFA_advance_loc1);
		out_one (scaled);
	      }
	    else if (scaled <= 0xFFFF)
	      {
		out_one (DW_CFA_advance_loc2);
		out_two (scaled);
	      }
	    else
	      {
		out_one (DW_CFA_advance_loc4);
		out_four (scaled);
	      }
	  }
	else
	  {
	    expressionS exp;

	    exp.X_op = O_subtract;
	    exp.X_add_symbol = to;
	    exp.X_op_symbol = from;
	    exp.X_add_number = 0;

	    /* The code in ehopt.c expects that one byte of the encoding
	       is already allocated to the frag.  This comes from the way
	       that it scans the .eh_frame section looking first for the
	       .byte DW_CFA_advance_loc4.  */
	    *frag_more (1) = DW_CFA_advance_loc4;

	    frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3,
		      make_expr_symbol (&exp), frag_now_fix () - 1,
		      (char *) frag_now);
	  }
      }
      break;

    case DW_CFA_def_cfa:
      offset = insn->u.ri.offset;
      if (offset < 0)
	{
	  out_one (DW_CFA_def_cfa_sf);
	  out_uleb128 (insn->u.ri.reg);
	  out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
	}
      else
	{
	  out_one (DW_CFA_def_cfa);
	  out_uleb128 (insn->u.ri.reg);
	  out_uleb128 (offset);
	}
      break;

    case DW_CFA_def_cfa_register:
    case DW_CFA_undefined:
    case DW_CFA_same_value:
      out_one (insn->insn);
      out_uleb128 (insn->u.r);
      break;

    case DW_CFA_def_cfa_offset:
      offset = insn->u.i;
      if (offset < 0)
	{
	  out_one (DW_CFA_def_cfa_offset_sf);
	  out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
	}
      else
	{
	  out_one (DW_CFA_def_cfa_offset);
	  out_uleb128 (offset);
	}
      break;

    case DW_CFA_restore:
      regno = insn->u.r;
      if (regno <= 0x3F)
	{
	  out_one (DW_CFA_restore + regno);
	}
      else
	{
	  out_one (DW_CFA_restore_extended);
	  out_uleb128 (regno);
	}
      break;

    case DW_CFA_offset:
      regno = insn->u.ri.reg;
      offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT;
      if (offset < 0)
	{
	  out_one (DW_CFA_offset_extended_sf);
	  out_uleb128 (regno);
	  out_sleb128 (offset);
	}
      else if (regno <= 0x3F)
	{
	  out_one (DW_CFA_offset + regno);
	  out_uleb128 (offset);
	}
      else
	{
	  out_one (DW_CFA_offset_extended);
	  out_uleb128 (regno);
	  out_uleb128 (offset);
	}
      break;

    case DW_CFA_register:
      out_one (DW_CFA_register);
      out_uleb128 (insn->u.rr.reg1);
      out_uleb128 (insn->u.rr.reg2);
      break;

    case DW_CFA_remember_state:
    case DW_CFA_restore_state:
      out_one (insn->insn);
      break;

    case DW_CFA_GNU_window_save:
      out_one (DW_CFA_GNU_window_save);
      break;

    case CFI_escape:
      {
	struct cfi_escape_data *e;
	for (e = insn->u.esc; e ; e = e->next)
	  emit_expr (&e->exp, 1);
	break;
      }

    case CFI_val_encoded_addr:
      {
        unsigned encoding = insn->u.ea.encoding;
        offsetT encoding_size;

	if (encoding == DW_EH_PE_omit)
	  break;
	out_one (DW_CFA_val_expression);
	out_uleb128 (insn->u.ea.reg);

        switch (encoding & 0x7)
	  {
	  case DW_EH_PE_absptr:
	    encoding_size = DWARF2_ADDR_SIZE (stdoutput);
	    break;
	  case DW_EH_PE_udata2:
	    encoding_size = 2;
	    break;
	  case DW_EH_PE_udata4:
	    encoding_size = 4;
	    break;
	  case DW_EH_PE_udata8:
	    encoding_size = 8;
	    break;
	  default:
	    abort ();
	  }

	/* If the user has requested absolute encoding,
	   then use the smaller DW_OP_addr encoding.  */
	if (insn->u.ea.encoding == DW_EH_PE_absptr)
	  {
	    out_uleb128 (1 + encoding_size);
	    out_one (DW_OP_addr);
	  }
	else
	  {
	    out_uleb128 (1 + 1 + encoding_size);
	    out_one (DW_OP_GNU_encoded_addr);
	    out_one (encoding);

	    if ((encoding & 0x70) == DW_EH_PE_pcrel)
	      {
#if CFI_DIFF_EXPR_OK
		insn->u.ea.exp.X_op = O_subtract;
		insn->u.ea.exp.X_op_symbol = symbol_temp_new_now ();
#elif defined (tc_cfi_emit_pcrel_expr)
		tc_cfi_emit_pcrel_expr (&insn->u.ea.exp, encoding_size);
		break;
#else
		abort ();
#endif
	      }
	  }
	emit_expr (&insn->u.ea.exp, encoding_size);
      }
      break;

    default:
      abort ();
    }
}