dwarf2dbg.c revision 60484
160484Sobrien/* dwarf2dbg.c - DWARF2 debug support
260484Sobrien   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
360484Sobrien   Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
460484Sobrien
560484Sobrien   This file is part of GAS, the GNU Assembler.
660484Sobrien
760484Sobrien   GAS is free software; you can redistribute it and/or modify
860484Sobrien   it under the terms of the GNU General Public License as published by
960484Sobrien   the Free Software Foundation; either version 2, or (at your option)
1060484Sobrien   any later version.
1160484Sobrien
1260484Sobrien   GAS is distributed in the hope that it will be useful,
1360484Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1460484Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1560484Sobrien   GNU General Public License for more details.
1660484Sobrien
1760484Sobrien   You should have received a copy of the GNU General Public License
1860484Sobrien   along with GAS; see the file COPYING.  If not, write to the Free
1960484Sobrien   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2060484Sobrien   02111-1307, USA.  */
2160484Sobrien
2260484Sobrien/* Logical line numbers can be controlled by the compiler via the
2360484Sobrien   following two directives:
2460484Sobrien
2560484Sobrien	.file FILENO "file.c"
2660484Sobrien	.loc  FILENO LINENO [COLUMN]
2760484Sobrien
2860484Sobrien   FILENO is the filenumber.  */
2960484Sobrien
3060484Sobrien#include "ansidecl.h"
3160484Sobrien
3260484Sobrien#include "as.h"
3360484Sobrien#include "dwarf2dbg.h"
3460484Sobrien#include "subsegs.h"
3560484Sobrien
3660484Sobrien#include "elf/dwarf2.h"
3760484Sobrien
3860484Sobrien/* Since we can't generate the prolog until the body is complete, we
3960484Sobrien   use three different subsegments for .debug_line: one holding the
4060484Sobrien   prolog, one for the directory and filename info, and one for the
4160484Sobrien   body ("statement program").  */
4260484Sobrien#define DL_PROLOG	0
4360484Sobrien#define DL_FILES	1
4460484Sobrien#define DL_BODY		2
4560484Sobrien
4660484Sobrien/* First special line opcde - leave room for the standard opcodes.
4760484Sobrien   Note: If you want to change this, you'll have to update the
4860484Sobrien   "standard_opcode_lengths" table that is emitted below in
4960484Sobrien   dwarf2_finish().  */
5060484Sobrien#define DWARF2_LINE_OPCODE_BASE		10
5160484Sobrien
5260484Sobrien#ifndef DWARF2_LINE_BASE
5360484Sobrien  /* Minimum line offset in a special line info. opcode.  This value
5460484Sobrien     was chosen to give a reasonable range of values.  */
5560484Sobrien# define DWARF2_LINE_BASE		-5
5660484Sobrien#endif
5760484Sobrien
5860484Sobrien/* Range of line offsets in a special line info. opcode.  */
5960484Sobrien#ifndef DWARF2_LINE_RANGE
6060484Sobrien# define DWARF2_LINE_RANGE		14
6160484Sobrien#endif
6260484Sobrien
6360484Sobrien#ifndef DWARF2_LINE_MIN_INSN_LENGTH
6460484Sobrien  /* Define the architecture-dependent minimum instruction length (in
6560484Sobrien     bytes).  This value should be rather too small than too big.  */
6660484Sobrien# define DWARF2_LINE_MIN_INSN_LENGTH	4
6760484Sobrien#endif
6860484Sobrien
6960484Sobrien/* Flag that indicates the initial value of the is_stmt_start flag.
7060484Sobrien   In the present implementation, we do not mark any lines as
7160484Sobrien   the beginning of a source statement, because that information
7260484Sobrien   is not made available by the GCC front-end.  */
7360484Sobrien#define	DWARF2_LINE_DEFAULT_IS_STMT	1
7460484Sobrien
7560484Sobrien/* Flag that indicates the initial value of the is_stmt_start flag.
7660484Sobrien   In the present implementation, we do not mark any lines as
7760484Sobrien   the beginning of a source statement, because that information
7860484Sobrien   is not made available by the GCC front-end.  */
7960484Sobrien#define	DWARF2_LINE_DEFAULT_IS_STMT	1
8060484Sobrien
8160484Sobrien/* Given a special op, return the line skip amount.  */
8260484Sobrien#define SPECIAL_LINE(op) \
8360484Sobrien	(((op) - DWARF2_LINE_OPCODE_BASE)%DWARF2_LINE_RANGE + DWARF2_LINE_BASE)
8460484Sobrien
8560484Sobrien/* Given a special op, return the address skip amount (in units of
8660484Sobrien   DWARF2_LINE_MIN_INSN_LENGTH.  */
8760484Sobrien#define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE)
8860484Sobrien
8960484Sobrien/* The maximum address skip amount that can be encoded with a special op.  */
9060484Sobrien#define MAX_SPECIAL_ADDR_DELTA		SPECIAL_ADDR(255)
9160484Sobrien
9260484Sobrien#define INITIAL_STATE						\
9360484Sobrien  /* Initialize as per DWARF2.0 standard.  */			\
9460484Sobrien  0,					/* address */		\
9560484Sobrien  1,					/* file */		\
9660484Sobrien  1,					/* line */		\
9760484Sobrien  0,					/* column */		\
9860484Sobrien  DWARF2_LINE_DEFAULT_IS_STMT,		/* is_stmt */		\
9960484Sobrien  0,					/* basic_block */	\
10060484Sobrien  1					/* empty_sequence */
10160484Sobrien
10260484Sobrienstatic struct
10360484Sobrien  {
10460484Sobrien    /* state machine state as per DWARF2 manual: */
10560484Sobrien    struct dwarf2_sm
10660484Sobrien      {
10760484Sobrien	addressT addr;
10860484Sobrien	unsigned int filenum;
10960484Sobrien	unsigned int line;
11060484Sobrien	unsigned int column;
11160484Sobrien	unsigned int
11260484Sobrien	  is_stmt : 1,
11360484Sobrien	  basic_block : 1,
11460484Sobrien	  empty_sequence : 1;		/* current code sequence has no DWARF2 directives? */
11560484Sobrien      }
11660484Sobrien    sm;
11760484Sobrien
11860484Sobrien    unsigned int
11960484Sobrien      any_dwarf2_directives : 1;	/* did we emit any DWARF2 line debug directives? */
12060484Sobrien
12160484Sobrien    fragS * frag;	/* frag that "addr" is relative to */
12260484Sobrien    segT text_seg;	/* text segment "addr" is relative to */
12360484Sobrien    subsegT text_subseg;
12460484Sobrien    segT line_seg;	/* ".debug_line" segment */
12560484Sobrien    int last_filename;	/* index of last filename that was used */
12660484Sobrien    int num_filenames;	/* index of last filename in use */
12760484Sobrien    int filename_len;	/* length of the filename array */
12860484Sobrien    struct
12960484Sobrien      {
13060484Sobrien	int dir;	/* valid after gen_dir_list() only */
13160484Sobrien	char *name; /* full path before gen_dir_list(), filename afterwards */
13260484Sobrien      }
13360484Sobrien    *file;
13460484Sobrien
13560484Sobrien    struct dwarf2_line_info current;	/* current source info: */
13660484Sobrien
13760484Sobrien    /* counters for statistical purposes: */
13860484Sobrien    unsigned int num_line_entries;
13960484Sobrien    unsigned int opcode_hist[256];	/* histogram of opcode frequencies */
14060484Sobrien  }
14160484Sobrienls =
14260484Sobrien  {
14360484Sobrien    {
14460484Sobrien      INITIAL_STATE
14560484Sobrien    },
14660484Sobrien    0,
14760484Sobrien    0,
14860484Sobrien    0,
14960484Sobrien    0,
15060484Sobrien    0,
15160484Sobrien    0,
15260484Sobrien    0,
15360484Sobrien    0,
15460484Sobrien    NULL,
15560484Sobrien    { NULL, 0, 0, 0, 0 },
15660484Sobrien    0,
15760484Sobrien    {
15860484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
15960484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16060484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16160484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16260484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16360484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16460484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16560484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16660484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16760484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16860484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16960484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17060484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17160484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17260484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17360484Sobrien      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
17460484Sobrien    }
17560484Sobrien  };
17660484Sobrien
17760484Sobrien
17860484Sobrien/* Function prototypes: */
17960484Sobrienstatic void out_uleb128 PARAMS ((addressT));
18060484Sobrienstatic void out_sleb128 PARAMS ((offsetT));
18160484Sobrienstatic void gen_addr_line PARAMS ((int, addressT));
18260484Sobrienstatic void reset_state_machine PARAMS ((void));
18360484Sobrienstatic void out_set_addr PARAMS ((addressT));
18460484Sobrienstatic void out_end_sequence PARAMS ((void));
18560484Sobrienstatic int get_filenum PARAMS ((int, char *));
18660484Sobrienstatic void gen_dir_list PARAMS ((void));
18760484Sobrienstatic void gen_file_list PARAMS ((void));
18860484Sobrienstatic void print_stats PARAMS ((unsigned long));
18960484Sobrien
19060484Sobrien
19160484Sobrien#define out_byte(byte)	FRAG_APPEND_1_CHAR(byte)
19260484Sobrien#define out_opcode(opc)	(out_byte ((opc)), ++ls.opcode_hist[(opc) & 0xff])
19360484Sobrien
19460484Sobrien/* Output an unsigned "little-endian base 128" number.  */
19560484Sobrienstatic void
19660484Sobrienout_uleb128 (value)
19760484Sobrien     addressT value;
19860484Sobrien{
19960484Sobrien  unsigned char byte, more = 0x80;
20060484Sobrien
20160484Sobrien  do
20260484Sobrien    {
20360484Sobrien      byte = value & 0x7f;
20460484Sobrien      value >>= 7;
20560484Sobrien      if (value == 0)
20660484Sobrien	more = 0;
20760484Sobrien      out_byte (more | byte);
20860484Sobrien    }
20960484Sobrien  while (more);
21060484Sobrien}
21160484Sobrien
21260484Sobrien/* Output a signed "little-endian base 128" number.  */
21360484Sobrienstatic void
21460484Sobrienout_sleb128 (value)
21560484Sobrien     offsetT value;
21660484Sobrien{
21760484Sobrien  unsigned char byte, more = 0x80;
21860484Sobrien
21960484Sobrien  do
22060484Sobrien    {
22160484Sobrien      byte = value & 0x7f;
22260484Sobrien      value >>= 7;
22360484Sobrien      if (((value == 0) && ((byte & 0x40) == 0))
22460484Sobrien	  || ((value == -1) && ((byte & 0x40) != 0)))
22560484Sobrien	more = 0;
22660484Sobrien      out_byte (more | byte);
22760484Sobrien    }
22860484Sobrien  while (more);
22960484Sobrien}
23060484Sobrien
23160484Sobrien/* Encode a pair of line and address skips as efficiently as possible.
23260484Sobrien   Note that the line skip is signed, whereas the address skip is
23360484Sobrien   unsigned.  */
23460484Sobrienstatic void
23560484Sobriengen_addr_line (line_delta, addr_delta)
23660484Sobrien     int line_delta;
23760484Sobrien     addressT addr_delta;
23860484Sobrien{
23960484Sobrien  unsigned int tmp, opcode;
24060484Sobrien
24160484Sobrien  tmp = line_delta - DWARF2_LINE_BASE;
24260484Sobrien
24360484Sobrien  if (tmp >= DWARF2_LINE_RANGE)
24460484Sobrien    {
24560484Sobrien      out_opcode (DW_LNS_advance_line);
24660484Sobrien      out_sleb128 (line_delta);
24760484Sobrien      tmp = 0 - DWARF2_LINE_BASE;
24860484Sobrien      line_delta = 0;
24960484Sobrien    }
25060484Sobrien
25160484Sobrien  tmp += DWARF2_LINE_OPCODE_BASE;
25260484Sobrien
25360484Sobrien  /* try using a special opcode: */
25460484Sobrien  opcode = tmp + addr_delta*DWARF2_LINE_RANGE;
25560484Sobrien  if (opcode <= 255)
25660484Sobrien    {
25760484Sobrien      out_opcode (opcode);
25860484Sobrien      return;
25960484Sobrien    }
26060484Sobrien
26160484Sobrien  /* try using DW_LNS_const_add_pc followed by special op: */
26260484Sobrien  opcode = tmp + (addr_delta - MAX_SPECIAL_ADDR_DELTA)*DWARF2_LINE_RANGE;
26360484Sobrien  if (opcode <= 255)
26460484Sobrien    {
26560484Sobrien      out_opcode (DW_LNS_const_add_pc);
26660484Sobrien      out_opcode (opcode);
26760484Sobrien      return;
26860484Sobrien    }
26960484Sobrien
27060484Sobrien  out_opcode (DW_LNS_advance_pc);
27160484Sobrien  out_uleb128 (addr_delta);
27260484Sobrien
27360484Sobrien  if (line_delta)
27460484Sobrien    out_opcode (tmp);		/* output line-delta */
27560484Sobrien  else
27660484Sobrien    out_opcode (DW_LNS_copy);	/* append new row with current info */
27760484Sobrien}
27860484Sobrien
27960484Sobrienstatic void
28060484Sobrienreset_state_machine ()
28160484Sobrien{
28260484Sobrien  static const struct dwarf2_sm initial_state = { INITIAL_STATE };
28360484Sobrien
28460484Sobrien  ls.sm = initial_state;
28560484Sobrien}
28660484Sobrien
28760484Sobrien/* Set an absolute address (may results in a relocation entry): */
28860484Sobrienstatic void
28960484Sobrienout_set_addr (addr)
29060484Sobrien     addressT addr;
29160484Sobrien{
29260484Sobrien  subsegT saved_subseg;
29360484Sobrien  segT saved_seg;
29460484Sobrien  expressionS expr;
29560484Sobrien  symbolS *sym;
29660484Sobrien  int bytes_per_address;
29760484Sobrien
29860484Sobrien  saved_seg = now_seg;
29960484Sobrien  saved_subseg = now_subseg;
30060484Sobrien
30160484Sobrien  subseg_set (ls.text_seg, ls.text_subseg);
30260484Sobrien  sym = symbol_new (".L0\001", now_seg, addr, frag_now);
30360484Sobrien
30460484Sobrien  subseg_set (saved_seg, saved_subseg);
30560484Sobrien
30660484Sobrien#ifdef BFD_ASSEMBLER
30760484Sobrien  bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
30860484Sobrien#else
30960484Sobrien  /* FIXME.  */
31060484Sobrien  bytes_per_address = 4;
31160484Sobrien#endif
31260484Sobrien
31360484Sobrien  out_opcode (DW_LNS_extended_op);
31460484Sobrien  out_uleb128 (bytes_per_address + 1);
31560484Sobrien
31660484Sobrien  out_opcode (DW_LNE_set_address);
31760484Sobrien  expr.X_op = O_symbol;
31860484Sobrien  expr.X_add_symbol = sym;
31960484Sobrien  expr.X_add_number = 0;
32060484Sobrien  emit_expr (&expr, bytes_per_address);
32160484Sobrien}
32260484Sobrien
32360484Sobrien/* Emit DW_LNS_end_sequence and reset state machine.  Does not
32460484Sobrien   preserve the current segment/sub-segment!  */
32560484Sobrienstatic void
32660484Sobrienout_end_sequence ()
32760484Sobrien{
32860484Sobrien  addressT addr, delta;
32960484Sobrien  fragS *text_frag;
33060484Sobrien
33160484Sobrien  if (ls.text_seg)
33260484Sobrien    {
33360484Sobrien      subseg_set (ls.text_seg, ls.text_subseg);
33460484Sobrien#ifdef md_current_text_addr
33560484Sobrien      addr = md_current_text_addr ();
33660484Sobrien#else
33760484Sobrien      addr = frag_now_fix ();
33860484Sobrien#endif
33960484Sobrien      text_frag = frag_now;
34060484Sobrien      subseg_set (ls.line_seg, DL_BODY);
34160484Sobrien      if (text_frag != ls.frag)
34260484Sobrien	{
34360484Sobrien	  out_set_addr (addr);
34460484Sobrien	  ls.sm.addr = addr;
34560484Sobrien	  ls.frag = text_frag;
34660484Sobrien	}
34760484Sobrien      else
34860484Sobrien	{
34960484Sobrien	  delta = (addr - ls.sm.addr) / DWARF2_LINE_MIN_INSN_LENGTH;
35060484Sobrien	  if (delta > 0)
35160484Sobrien	    {
35260484Sobrien	      /* Advance address without updating the line-debug
35360484Sobrien		 matrix---the end_sequence entry is used only to tell
35460484Sobrien		 the debugger the end of the sequence.*/
35560484Sobrien	      out_opcode (DW_LNS_advance_pc);
35660484Sobrien	      out_uleb128 (delta);
35760484Sobrien	    }
35860484Sobrien	}
35960484Sobrien    }
36060484Sobrien  else
36160484Sobrien    subseg_set (ls.line_seg, DL_BODY);
36260484Sobrien
36360484Sobrien  out_opcode (DW_LNS_extended_op);
36460484Sobrien  out_uleb128 (1);
36560484Sobrien  out_byte (DW_LNE_end_sequence);
36660484Sobrien
36760484Sobrien  reset_state_machine ();
36860484Sobrien}
36960484Sobrien
37060484Sobrien/* Look up a filenumber either by filename or by filenumber.  If both
37160484Sobrien   a filenumber and a filename are specified, lookup by filename takes
37260484Sobrien   precedence.  If the filename cannot be found, it is added to the
37360484Sobrien   filetable and the filenumber for the new entry is returned.  */
37460484Sobrienstatic int
37560484Sobrienget_filenum (filenum, file)
37660484Sobrien     int filenum;
37760484Sobrien     char *file;
37860484Sobrien{
37960484Sobrien  int i, last = filenum - 1;
38060484Sobrien  char char0 = file[0];
38160484Sobrien
38260484Sobrien  /* If filenum is out of range of the filename table, then try using the
38360484Sobrien     table entry returned from the previous call.  */
38460484Sobrien  if (last >= ls.num_filenames || last < 0)
38560484Sobrien    last = ls.last_filename;
38660484Sobrien
38760484Sobrien  /* Do a quick check against the specified or previously used filenum.  */
38860484Sobrien  if (ls.num_filenames > 0 && ls.file[last].name[0] == char0
38960484Sobrien      && strcmp (ls.file[last].name + 1, file + 1) == 0)
39060484Sobrien    return last + 1;
39160484Sobrien
39260484Sobrien  /* no match, fall back to simple linear scan: */
39360484Sobrien  for (i = 0; i < ls.num_filenames; ++i)
39460484Sobrien    {
39560484Sobrien      if (ls.file[i].name[0] == char0
39660484Sobrien	  && strcmp (ls.file[i].name + 1, file + 1) == 0)
39760484Sobrien	{
39860484Sobrien	  ls.last_filename = i;
39960484Sobrien	  return i + 1;
40060484Sobrien	}
40160484Sobrien    }
40260484Sobrien
40360484Sobrien  /* no match: enter new filename */
40460484Sobrien  if (ls.num_filenames >= ls.filename_len)
40560484Sobrien    {
40660484Sobrien      ls.filename_len += 13;
40760484Sobrien      ls.file = xrealloc (ls.file, ls.filename_len * sizeof (ls.file[0]));
40860484Sobrien    }
40960484Sobrien  ls.file[ls.num_filenames].dir = 0;
41060484Sobrien  ls.file[ls.num_filenames].name = file;
41160484Sobrien  ls.last_filename = ls.num_filenames;
41260484Sobrien  return ++ls.num_filenames;
41360484Sobrien}
41460484Sobrien
41560484Sobrien/* Emit an entry in the line number table if the address or line has changed.
41660484Sobrien   ADDR is relative to the current frag in the text section.  */
41760484Sobrien
41860484Sobrienvoid
41960484Sobriendwarf2_gen_line_info (addr, l)
42060484Sobrien     addressT addr;
42160484Sobrien     struct dwarf2_line_info *l;
42260484Sobrien{
42360484Sobrien  unsigned int filenum = l->filenum;
42460484Sobrien  unsigned int any_output = 0;
42560484Sobrien  subsegT saved_subseg;
42660484Sobrien  segT saved_seg;
42760484Sobrien  fragS *saved_frag;
42860484Sobrien
42960484Sobrien  if (flag_debug)
43060484Sobrien    fprintf (stderr, "line: addr %lx file `%s' line %u col %u flags %x\n",
43160484Sobrien	     (unsigned long) addr, l->filename, l->line, l->column, l->flags);
43260484Sobrien
43360484Sobrien  if (filenum > 0 && !l->filename)
43460484Sobrien    {
43560484Sobrien      if (filenum >= (unsigned int) ls.num_filenames)
43660484Sobrien	{
43760484Sobrien	  as_warn ("Encountered bad file number in line number debug info!");
43860484Sobrien	  return;
43960484Sobrien	}
44060484Sobrien    }
44160484Sobrien  else if (l->filename)
44260484Sobrien    filenum = get_filenum (filenum, l->filename);
44360484Sobrien  else
44460484Sobrien    return;	/* no filename, no filnum => no play */
44560484Sobrien
44660484Sobrien  /* Must save these before the subseg_new call, as that call will change
44760484Sobrien     them.  */
44860484Sobrien  saved_seg = now_seg;
44960484Sobrien  saved_subseg = now_subseg;
45060484Sobrien  saved_frag = frag_now;
45160484Sobrien
45260484Sobrien  if (!ls.line_seg)
45360484Sobrien    {
45460484Sobrien#ifdef BFD_ASSEMBLER
45560484Sobrien      symbolS *secsym;
45660484Sobrien#endif
45760484Sobrien
45860484Sobrien      ls.line_seg = subseg_new (".debug_line", 0);
45960484Sobrien
46060484Sobrien#ifdef BFD_ASSEMBLER
46160484Sobrien      bfd_set_section_flags (stdoutput, ls.line_seg, SEC_READONLY);
46260484Sobrien
46360484Sobrien      /* We're going to need this symbol.  */
46460484Sobrien      secsym = symbol_find (".debug_line");
46560484Sobrien      if (secsym != NULL)
46660484Sobrien        symbol_set_bfdsym (secsym, ls.line_seg->symbol);
46760484Sobrien      else
46860484Sobrien        symbol_table_insert (section_symbol (ls.line_seg));
46960484Sobrien#endif
47060484Sobrien    }
47160484Sobrien
47260484Sobrien  subseg_set (ls.line_seg, DL_BODY);
47360484Sobrien
47460484Sobrien  if (ls.text_seg != saved_seg || ls.text_subseg != saved_subseg)
47560484Sobrien    {
47660484Sobrien      if (!ls.sm.empty_sequence)
47760484Sobrien	{
47860484Sobrien	  out_end_sequence ();		/* terminate previous sequence */
47960484Sobrien	  ls.sm.empty_sequence = 1;
48060484Sobrien	}
48160484Sobrien      any_output = 1;
48260484Sobrien      ls.text_seg = saved_seg;
48360484Sobrien      ls.text_subseg = saved_subseg;
48460484Sobrien      out_set_addr (addr);
48560484Sobrien      ls.sm.addr = addr;
48660484Sobrien      ls.frag = saved_frag;
48760484Sobrien    }
48860484Sobrien
48960484Sobrien  if (ls.sm.filenum != filenum)
49060484Sobrien    {
49160484Sobrien      any_output = 1;
49260484Sobrien      out_opcode (DW_LNS_set_file);
49360484Sobrien      out_uleb128 (filenum);
49460484Sobrien      ls.sm.filenum = filenum;
49560484Sobrien    }
49660484Sobrien
49760484Sobrien  if (ls.sm.column != l->column)
49860484Sobrien    {
49960484Sobrien      any_output = 1;
50060484Sobrien      out_opcode (DW_LNS_set_column);
50160484Sobrien      out_uleb128 (l->column);
50260484Sobrien      ls.sm.column = l->column;
50360484Sobrien    }
50460484Sobrien
50560484Sobrien  if (((l->flags & DWARF2_FLAG_BEGIN_STMT) != 0) != ls.sm.is_stmt)
50660484Sobrien    {
50760484Sobrien      any_output = 1;
50860484Sobrien      out_opcode (DW_LNS_negate_stmt);
50960484Sobrien    }
51060484Sobrien
51160484Sobrien  if (l->flags & DWARF2_FLAG_BEGIN_BLOCK)
51260484Sobrien    {
51360484Sobrien      any_output = 1;
51460484Sobrien      out_opcode (DW_LNS_set_basic_block);
51560484Sobrien    }
51660484Sobrien
51760484Sobrien  if (ls.sm.line != l->line)
51860484Sobrien    {
51960484Sobrien      any_output = 1;
52060484Sobrien      if (saved_frag != ls.frag)
52160484Sobrien	{
52260484Sobrien	  /* If a new frag got allocated (for whatever reason), then
52360484Sobrien	     deal with it by generating a reference symbol.  Note: no
52460484Sobrien	     end_sequence needs to be generated because the address did
52560484Sobrien	     not really decrease (only the reference point changed).  */
52660484Sobrien	  out_set_addr (addr);
52760484Sobrien	  ls.sm.addr = addr;
52860484Sobrien	  ls.frag = saved_frag;
52960484Sobrien	}
53060484Sobrien      gen_addr_line (l->line - ls.sm.line,
53160484Sobrien		     (addr - ls.sm.addr) / DWARF2_LINE_MIN_INSN_LENGTH);
53260484Sobrien      ls.sm.basic_block = 0;
53360484Sobrien      ls.sm.line = l->line;
53460484Sobrien      ls.sm.addr = addr;
53560484Sobrien    }
53660484Sobrien
53760484Sobrien  subseg_set (saved_seg, saved_subseg);
53860484Sobrien
53960484Sobrien  ls.num_line_entries += any_output;
54060484Sobrien  if (any_output)
54160484Sobrien    ls.sm.empty_sequence = 0;
54260484Sobrien}
54360484Sobrien
54460484Sobrienstatic void
54560484Sobriengen_dir_list ()
54660484Sobrien{
54760484Sobrien  char *str, *slash, *dir_list, *dp, *cp;
54860484Sobrien  int i, j, num_dirs;
54960484Sobrien
55060484Sobrien  dir_list = frag_more (0);
55160484Sobrien  num_dirs = 0;
55260484Sobrien
55360484Sobrien  for (i = 0; i < ls.num_filenames; ++i)
55460484Sobrien    {
55560484Sobrien      str = ls.file[i].name;
55660484Sobrien      slash = strrchr (str, '/');
55760484Sobrien      if (slash)
55860484Sobrien	{
55960484Sobrien	  *slash = '\0';
56060484Sobrien	  for (j = 0, dp = dir_list; j < num_dirs; ++j)
56160484Sobrien	    {
56260484Sobrien	      if (strcmp (str, dp) == 0)
56360484Sobrien		{
56460484Sobrien		  ls.file[i].dir = j + 1;
56560484Sobrien		  break;
56660484Sobrien		}
56760484Sobrien	      dp += strlen (dp);
56860484Sobrien	    }
56960484Sobrien	  if (j >= num_dirs)
57060484Sobrien	    {
57160484Sobrien	      /* didn't find this directory: append it to the list */
57260484Sobrien	      size_t size = strlen (str) + 1;
57360484Sobrien	      cp = frag_more (size);
57460484Sobrien	      memcpy (cp, str, size);
57560484Sobrien	      ls.file[i].dir = ++num_dirs;
57660484Sobrien	    }
57760484Sobrien	  *slash = '/';
57860484Sobrien	  ls.file[i].name = slash + 1;
57960484Sobrien	}
58060484Sobrien    }
58160484Sobrien  out_byte ('\0');	/* terminate directory list */
58260484Sobrien}
58360484Sobrien
58460484Sobrienstatic void
58560484Sobriengen_file_list ()
58660484Sobrien{
58760484Sobrien  size_t size;
58860484Sobrien  char *cp;
58960484Sobrien  int i;
59060484Sobrien
59160484Sobrien  for (i = 0; i < ls.num_filenames; ++i)
59260484Sobrien    {
59360484Sobrien      size = strlen (ls.file[i].name) + 1;
59460484Sobrien      cp = frag_more (size);
59560484Sobrien      memcpy (cp, ls.file[i].name, size);
59660484Sobrien
59760484Sobrien      out_uleb128 (ls.file[i].dir);	/* directory number */
59860484Sobrien      out_uleb128 (0);			/* last modification timestamp */
59960484Sobrien      out_uleb128 (0);			/* filesize */
60060484Sobrien    }
60160484Sobrien  out_byte (0);		/* terminate filename list */
60260484Sobrien}
60360484Sobrien
60460484Sobrienstatic void
60560484Sobrienprint_stats (total_size)
60660484Sobrien     unsigned long total_size;
60760484Sobrien{
60860484Sobrien  static const char *opc_name[] =
60960484Sobrien    {
61060484Sobrien      "extended", "copy", "advance_pc", "advance_line", "set_file",
61160484Sobrien      "set_column", "negate_stmt", "set_basic_block", "const_add_pc",
61260484Sobrien      "fixed_advance_pc"
61360484Sobrien    };
61460484Sobrien  size_t i;
61560484Sobrien  int j;
61660484Sobrien
61760484Sobrien  fprintf (stderr, "Average size: %g bytes/line\n",
61860484Sobrien	   total_size / (double) ls.num_line_entries);
61960484Sobrien
62060484Sobrien  fprintf (stderr, "\nStandard opcode histogram:\n");
62160484Sobrien
62260484Sobrien  for (i = 0; i < sizeof (opc_name)/sizeof (opc_name[0]); ++i)
62360484Sobrien    {
62460484Sobrien      fprintf (stderr, "%s", opc_name[i]);
62560484Sobrien      for (j = strlen (opc_name[i]); j < 16; ++j)
62660484Sobrien	fprintf (stderr, " ");
62760484Sobrien      fprintf (stderr, ": %u\n", ls.opcode_hist[i]);
62860484Sobrien    }
62960484Sobrien
63060484Sobrien  fprintf (stderr, "\nSpecial opcodes:\naddr\t\t\t\tline skip\n");
63160484Sobrien
63260484Sobrien  fprintf (stderr, "skip: ");
63360484Sobrien  for (j = DWARF2_LINE_BASE; j < DWARF2_LINE_BASE + DWARF2_LINE_RANGE; ++j)
63460484Sobrien    fprintf (stderr, "%3d", j);
63560484Sobrien  fprintf (stderr, "\n-----");
63660484Sobrien
63760484Sobrien  for (; i < 256; ++i)
63860484Sobrien    {
63960484Sobrien      j = SPECIAL_LINE (i);
64060484Sobrien      if (j == DWARF2_LINE_BASE)
64160484Sobrien	fprintf (stderr, "\n%4u: ",
64260484Sobrien		 ((unsigned int)
64360484Sobrien		  DWARF2_LINE_MIN_INSN_LENGTH * SPECIAL_ADDR (i)));
64460484Sobrien      fprintf (stderr, " %2u", ls.opcode_hist[i]);
64560484Sobrien    }
64660484Sobrien  fprintf (stderr, "\n");
64760484Sobrien}
64860484Sobrien
64960484Sobrienvoid
65060484Sobriendwarf2_finish ()
65160484Sobrien{
65260484Sobrien  addressT body_size, total_size, prolog_size;
65360484Sobrien  subsegT saved_subseg;
65460484Sobrien  segT saved_seg;
65560484Sobrien  char *cp;
65660484Sobrien
65760484Sobrien  if (!ls.line_seg)
65860484Sobrien    /* no .debug_line segment, no work to do... */
65960484Sobrien    return;
66060484Sobrien
66160484Sobrien  saved_seg = now_seg;
66260484Sobrien  saved_subseg = now_subseg;
66360484Sobrien
66460484Sobrien  if (!ls.sm.empty_sequence)
66560484Sobrien    out_end_sequence ();
66660484Sobrien  total_size = body_size = frag_now_fix ();
66760484Sobrien
66860484Sobrien  /* now generate the directory and file lists: */
66960484Sobrien  subseg_set (ls.line_seg, DL_FILES);
67060484Sobrien  gen_dir_list ();
67160484Sobrien  gen_file_list ();
67260484Sobrien  total_size += frag_now_fix ();
67360484Sobrien
67460484Sobrien  /* and now the header ("statement program prolog", in DWARF2 lingo...) */
67560484Sobrien  subseg_set (ls.line_seg, DL_PROLOG);
67660484Sobrien
67760484Sobrien  cp = frag_more (15 + DWARF2_LINE_OPCODE_BASE - 1);
67860484Sobrien
67960484Sobrien  total_size += frag_now_fix ();
68060484Sobrien  prolog_size = total_size - body_size - 10;
68160484Sobrien
68260484Sobrien# define STUFF(val,size)	md_number_to_chars (cp, val, size); cp += size;
68360484Sobrien  STUFF (total_size - 4, 4);	/* length */
68460484Sobrien  STUFF (2, 2);			/* version */
68560484Sobrien  STUFF (prolog_size, 4);	/* prologue_length */
68660484Sobrien  STUFF (DWARF2_LINE_MIN_INSN_LENGTH, 1);
68760484Sobrien  STUFF (DWARF2_LINE_DEFAULT_IS_STMT, 1);
68860484Sobrien  STUFF (DWARF2_LINE_BASE, 1);
68960484Sobrien  STUFF (DWARF2_LINE_RANGE, 1);
69060484Sobrien  STUFF (DWARF2_LINE_OPCODE_BASE, 1);
69160484Sobrien
69260484Sobrien  /* standard_opcode_lengths: */
69360484Sobrien  STUFF (0, 1);			/* DW_LNS_copy */
69460484Sobrien  STUFF (1, 1);			/* DW_LNS_advance_pc */
69560484Sobrien  STUFF (1, 1);			/* DW_LNS_advance_line */
69660484Sobrien  STUFF (1, 1);			/* DW_LNS_set_file */
69760484Sobrien  STUFF (1, 1);			/* DW_LNS_set_column */
69860484Sobrien  STUFF (0, 1);			/* DW_LNS_negate_stmt */
69960484Sobrien  STUFF (0, 1);			/* DW_LNS_set_basic_block */
70060484Sobrien  STUFF (0, 1);			/* DW_LNS_const_add_pc */
70160484Sobrien  STUFF (1, 1);			/* DW_LNS_fixed_advance_pc */
70260484Sobrien
70360484Sobrien  subseg_set (saved_seg, saved_subseg);
70460484Sobrien
70560484Sobrien  if (flag_debug)
70660484Sobrien    print_stats (total_size);
70760484Sobrien}
70860484Sobrien
70960484Sobrienvoid
71060484Sobriendwarf2_directive_file (dummy)
71160484Sobrien     int dummy ATTRIBUTE_UNUSED;
71260484Sobrien{
71360484Sobrien  int len;
71460484Sobrien
71560484Sobrien  /* Continue to accept a bare string and pass it off.  */
71660484Sobrien  SKIP_WHITESPACE ();
71760484Sobrien  if (*input_line_pointer == '"')
71860484Sobrien    {
71960484Sobrien      s_app_file (0);
72060484Sobrien      return;
72160484Sobrien    }
72260484Sobrien
72360484Sobrien  ls.any_dwarf2_directives = 1;
72460484Sobrien
72560484Sobrien  if (debug_type == DEBUG_NONE)
72660484Sobrien    /* Automatically turn on DWARF2 debug info unless something else
72760484Sobrien       has been selected.  */
72860484Sobrien    debug_type = DEBUG_DWARF2;
72960484Sobrien
73060484Sobrien  ls.current.filenum = get_absolute_expression ();
73160484Sobrien  ls.current.filename = demand_copy_C_string (&len);
73260484Sobrien
73360484Sobrien  demand_empty_rest_of_line ();
73460484Sobrien}
73560484Sobrien
73660484Sobrienvoid
73760484Sobriendwarf2_directive_loc (dummy)
73860484Sobrien     int dummy ATTRIBUTE_UNUSED;
73960484Sobrien{
74060484Sobrien  ls.any_dwarf2_directives = 1;
74160484Sobrien
74260484Sobrien  ls.current.filenum = get_absolute_expression ();
74360484Sobrien  SKIP_WHITESPACE ();
74460484Sobrien  ls.current.line = get_absolute_expression ();
74560484Sobrien  SKIP_WHITESPACE ();
74660484Sobrien  ls.current.column = get_absolute_expression ();
74760484Sobrien  demand_empty_rest_of_line ();
74860484Sobrien
74960484Sobrien  ls.current.flags = DWARF2_FLAG_BEGIN_STMT;
75060484Sobrien
75160484Sobrien#ifndef NO_LISTING
75260484Sobrien  if (listing)
75360484Sobrien    listing_source_line (ls.current.line);
75460484Sobrien#endif
75560484Sobrien}
75660484Sobrien
75760484Sobrienvoid
75860484Sobriendwarf2_where (line)
75960484Sobrien     struct dwarf2_line_info *line;
76060484Sobrien{
76160484Sobrien  if (ls.any_dwarf2_directives)
76260484Sobrien    *line = ls.current;
76360484Sobrien  else
76460484Sobrien    {
76560484Sobrien      as_where (&line->filename, &line->line);
76660484Sobrien      line->filenum = 0;
76760484Sobrien      line->column = 0;
76860484Sobrien      line->flags = DWARF2_FLAG_BEGIN_STMT;
76960484Sobrien    }
77060484Sobrien}
771