160484Sobrien/* dwarf2dbg.c - DWARF2 debug support
2218822Sdim   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
3218822Sdim   Free Software Foundation, Inc.
460484Sobrien   Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
560484Sobrien
660484Sobrien   This file is part of GAS, the GNU Assembler.
760484Sobrien
860484Sobrien   GAS is free software; you can redistribute it and/or modify
960484Sobrien   it under the terms of the GNU General Public License as published by
1060484Sobrien   the Free Software Foundation; either version 2, or (at your option)
1160484Sobrien   any later version.
1260484Sobrien
1360484Sobrien   GAS is distributed in the hope that it will be useful,
1460484Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1560484Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1660484Sobrien   GNU General Public License for more details.
1760484Sobrien
1860484Sobrien   You should have received a copy of the GNU General Public License
1960484Sobrien   along with GAS; see the file COPYING.  If not, write to the Free
20218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
21218822Sdim   02110-1301, USA.  */
2260484Sobrien
2360484Sobrien/* Logical line numbers can be controlled by the compiler via the
24218822Sdim   following directives:
2560484Sobrien
2660484Sobrien	.file FILENO "file.c"
27218822Sdim	.loc  FILENO LINENO [COLUMN] [basic_block] [prologue_end] \
28218822Sdim	      [epilogue_begin] [is_stmt VALUE] [isa VALUE]
29218822Sdim*/
3060484Sobrien
3177298Sobrien#include "as.h"
32218822Sdim#include "safe-ctype.h"
3360484Sobrien
3477298Sobrien#ifdef HAVE_LIMITS_H
3577298Sobrien#include <limits.h>
3677298Sobrien#else
3777298Sobrien#ifdef HAVE_SYS_PARAM_H
3877298Sobrien#include <sys/param.h>
3977298Sobrien#endif
4077298Sobrien#ifndef INT_MAX
4177298Sobrien#define INT_MAX (int) (((unsigned) (-1)) >> 1)
4277298Sobrien#endif
4377298Sobrien#endif
4477298Sobrien
45130561Sobrien#include "dwarf2dbg.h"
46130561Sobrien#include <filenames.h>
47130561Sobrien
48218822Sdim#ifdef HAVE_DOS_BASED_FILE_SYSTEM
49218822Sdim/* We need to decide which character to use as a directory separator.
50218822Sdim   Just because HAVE_DOS_BASED_FILE_SYSTEM is defined, it does not
51218822Sdim   necessarily mean that the backslash character is the one to use.
52218822Sdim   Some environments, eg Cygwin, can support both naming conventions.
53218822Sdim   So we use the heuristic that we only need to use the backslash if
54218822Sdim   the path is an absolute path starting with a DOS style drive
55218822Sdim   selector.  eg C: or D:  */
56218822Sdim# define INSERT_DIR_SEPARATOR(string, offset) \
57218822Sdim  do \
58218822Sdim    { \
59218822Sdim      if (offset > 1 \
60218822Sdim          && string[0] != 0 \
61218822Sdim          && string[1] == ':') \
62218822Sdim       string [offset] = '\\'; \
63218822Sdim      else \
64218822Sdim       string [offset] = '/'; \
65218822Sdim    } \
66218822Sdim  while (0)
67218822Sdim#else
68218822Sdim# define INSERT_DIR_SEPARATOR(string, offset) string[offset] = '/'
69218822Sdim#endif
70218822Sdim
71130561Sobrien#ifndef DWARF2_FORMAT
72130561Sobrien# define DWARF2_FORMAT() dwarf2_format_32bit
73130561Sobrien#endif
74130561Sobrien
75130561Sobrien#ifndef DWARF2_ADDR_SIZE
76130561Sobrien# define DWARF2_ADDR_SIZE(bfd) (bfd_arch_bits_per_address (bfd) / 8)
77130561Sobrien#endif
78130561Sobrien
7960484Sobrien#include "subsegs.h"
8060484Sobrien
8160484Sobrien#include "elf/dwarf2.h"
8260484Sobrien
8360484Sobrien/* Since we can't generate the prolog until the body is complete, we
8460484Sobrien   use three different subsegments for .debug_line: one holding the
8560484Sobrien   prolog, one for the directory and filename info, and one for the
8660484Sobrien   body ("statement program").  */
8760484Sobrien#define DL_PROLOG	0
8860484Sobrien#define DL_FILES	1
8960484Sobrien#define DL_BODY		2
9060484Sobrien
91218822Sdim/* If linker relaxation might change offsets in the code, the DWARF special
92218822Sdim   opcodes and variable-length operands cannot be used.  If this macro is
93218822Sdim   nonzero, use the DW_LNS_fixed_advance_pc opcode instead.  */
94218822Sdim#ifndef DWARF2_USE_FIXED_ADVANCE_PC
95218822Sdim# define DWARF2_USE_FIXED_ADVANCE_PC	0
96218822Sdim#endif
97218822Sdim
9860484Sobrien/* First special line opcde - leave room for the standard opcodes.
9960484Sobrien   Note: If you want to change this, you'll have to update the
10060484Sobrien   "standard_opcode_lengths" table that is emitted below in
101218822Sdim   out_debug_line().  */
102218822Sdim#define DWARF2_LINE_OPCODE_BASE		13
10360484Sobrien
10460484Sobrien#ifndef DWARF2_LINE_BASE
10560484Sobrien  /* Minimum line offset in a special line info. opcode.  This value
10660484Sobrien     was chosen to give a reasonable range of values.  */
10760484Sobrien# define DWARF2_LINE_BASE		-5
10860484Sobrien#endif
10960484Sobrien
11060484Sobrien/* Range of line offsets in a special line info. opcode.  */
11160484Sobrien#ifndef DWARF2_LINE_RANGE
11260484Sobrien# define DWARF2_LINE_RANGE		14
11360484Sobrien#endif
11460484Sobrien
11560484Sobrien#ifndef DWARF2_LINE_MIN_INSN_LENGTH
11660484Sobrien  /* Define the architecture-dependent minimum instruction length (in
11760484Sobrien     bytes).  This value should be rather too small than too big.  */
11877298Sobrien# define DWARF2_LINE_MIN_INSN_LENGTH	1
11960484Sobrien#endif
12060484Sobrien
121218822Sdim/* Flag that indicates the initial value of the is_stmt_start flag.  */
12260484Sobrien#define	DWARF2_LINE_DEFAULT_IS_STMT	1
12360484Sobrien
12460484Sobrien/* Given a special op, return the line skip amount.  */
12560484Sobrien#define SPECIAL_LINE(op) \
12660484Sobrien	(((op) - DWARF2_LINE_OPCODE_BASE)%DWARF2_LINE_RANGE + DWARF2_LINE_BASE)
12760484Sobrien
12860484Sobrien/* Given a special op, return the address skip amount (in units of
12960484Sobrien   DWARF2_LINE_MIN_INSN_LENGTH.  */
13060484Sobrien#define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE)
13160484Sobrien
13260484Sobrien/* The maximum address skip amount that can be encoded with a special op.  */
13360484Sobrien#define MAX_SPECIAL_ADDR_DELTA		SPECIAL_ADDR(255)
13460484Sobrien
13577298Sobrienstruct line_entry {
13677298Sobrien  struct line_entry *next;
137218822Sdim  symbolS *label;
13877298Sobrien  struct dwarf2_line_info loc;
13977298Sobrien};
14060484Sobrien
14177298Sobrienstruct line_subseg {
14277298Sobrien  struct line_subseg *next;
14377298Sobrien  subsegT subseg;
14477298Sobrien  struct line_entry *head;
14577298Sobrien  struct line_entry **ptail;
14677298Sobrien};
14760484Sobrien
14877298Sobrienstruct line_seg {
14977298Sobrien  struct line_seg *next;
15077298Sobrien  segT seg;
15177298Sobrien  struct line_subseg *head;
15277298Sobrien  symbolS *text_start;
15377298Sobrien  symbolS *text_end;
15477298Sobrien};
15560484Sobrien
15677298Sobrien/* Collects data for all line table entries during assembly.  */
15777298Sobrienstatic struct line_seg *all_segs;
15860484Sobrien
15977298Sobrienstruct file_entry {
160130561Sobrien  const char *filename;
16177298Sobrien  unsigned int dir;
16277298Sobrien};
16360484Sobrien
16477298Sobrien/* Table of files used by .debug_line.  */
16577298Sobrienstatic struct file_entry *files;
16677298Sobrienstatic unsigned int files_in_use;
16777298Sobrienstatic unsigned int files_allocated;
16877298Sobrien
169130561Sobrien/* Table of directories used by .debug_line.  */
170130561Sobrienstatic char **dirs;
171130561Sobrienstatic unsigned int dirs_in_use;
172130561Sobrienstatic unsigned int dirs_allocated;
173130561Sobrien
174130561Sobrien/* TRUE when we've seen a .loc directive recently.  Used to avoid
17577298Sobrien   doing work when there's nothing to do.  */
176130561Sobrienstatic bfd_boolean loc_directive_seen;
17777298Sobrien
178218822Sdim/* TRUE when we're supposed to set the basic block mark whenever a
179218822Sdim   label is seen.  */
180218822Sdimbfd_boolean dwarf2_loc_mark_labels;
181218822Sdim
18277298Sobrien/* Current location as indicated by the most recent .loc directive.  */
183218822Sdimstatic struct dwarf2_line_info current = {
184218822Sdim  1, 1, 0, 0,
185218822Sdim  DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0
186218822Sdim};
18777298Sobrien
18877298Sobrien/* The size of an address on the target.  */
18977298Sobrienstatic unsigned int sizeof_address;
19077298Sobrien
191130561Sobrienstatic struct line_subseg *get_line_subseg (segT, subsegT);
192130561Sobrienstatic unsigned int get_filenum (const char *, unsigned int);
193130561Sobrienstatic struct frag *first_frag_for_seg (segT);
194130561Sobrienstatic struct frag *last_frag_for_seg (segT);
195130561Sobrienstatic void out_byte (int);
196130561Sobrienstatic void out_opcode (int);
197130561Sobrienstatic void out_two (int);
198130561Sobrienstatic void out_four (int);
199130561Sobrienstatic void out_abbrev (int, int);
200130561Sobrienstatic void out_uleb128 (addressT);
201218822Sdimstatic void out_sleb128 (addressT);
202218822Sdimstatic offsetT get_frag_fix (fragS *, segT);
203218822Sdimstatic void out_set_addr (symbolS *);
204130561Sobrienstatic int size_inc_line_addr (int, addressT);
205130561Sobrienstatic void emit_inc_line_addr (int, addressT, char *, int);
206130561Sobrienstatic void out_inc_line_addr (int, addressT);
207218822Sdimstatic void out_fixed_inc_line_addr (int, symbolS *, symbolS *);
208218822Sdimstatic void relax_inc_line_addr (int, symbolS *, symbolS *);
209130561Sobrienstatic void process_entries (segT, struct line_entry *);
210130561Sobrienstatic void out_file_list (void);
211130561Sobrienstatic void out_debug_line (segT);
212130561Sobrienstatic void out_debug_aranges (segT, segT);
213130561Sobrienstatic void out_debug_abbrev (segT);
21477298Sobrien
215130561Sobrien#ifndef TC_DWARF2_EMIT_OFFSET
216218822Sdim#define TC_DWARF2_EMIT_OFFSET  generic_dwarf2_emit_offset
217130561Sobrien
218130561Sobrien/* Create an offset to .dwarf2_*.  */
219130561Sobrien
220130561Sobrienstatic void
221130561Sobriengeneric_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
222130561Sobrien{
223130561Sobrien  expressionS expr;
224130561Sobrien
225130561Sobrien  expr.X_op = O_symbol;
226130561Sobrien  expr.X_add_symbol = symbol;
227130561Sobrien  expr.X_add_number = 0;
228130561Sobrien  emit_expr (&expr, size);
229130561Sobrien}
230130561Sobrien#endif
231130561Sobrien
23277298Sobrien/* Find or create an entry for SEG+SUBSEG in ALL_SEGS.  */
23377298Sobrien
23477298Sobrienstatic struct line_subseg *
235130561Sobrienget_line_subseg (segT seg, subsegT subseg)
23677298Sobrien{
23777298Sobrien  static segT last_seg;
23877298Sobrien  static subsegT last_subseg;
23977298Sobrien  static struct line_subseg *last_line_subseg;
24077298Sobrien
241218822Sdim  struct line_seg **ps, *s;
24277298Sobrien  struct line_subseg **pss, *ss;
24377298Sobrien
24477298Sobrien  if (seg == last_seg && subseg == last_subseg)
24577298Sobrien    return last_line_subseg;
24677298Sobrien
247218822Sdim  for (ps = &all_segs; (s = *ps) != NULL; ps = &s->next)
24877298Sobrien    if (s->seg == seg)
24977298Sobrien      goto found_seg;
25077298Sobrien
25177298Sobrien  s = (struct line_seg *) xmalloc (sizeof (*s));
252218822Sdim  s->next = NULL;
25377298Sobrien  s->seg = seg;
25477298Sobrien  s->head = NULL;
255218822Sdim  *ps = s;
25677298Sobrien
25777298Sobrien found_seg:
25877298Sobrien  for (pss = &s->head; (ss = *pss) != NULL ; pss = &ss->next)
25960484Sobrien    {
26077298Sobrien      if (ss->subseg == subseg)
26177298Sobrien	goto found_subseg;
26277298Sobrien      if (ss->subseg > subseg)
26377298Sobrien	break;
26460484Sobrien    }
26560484Sobrien
26677298Sobrien  ss = (struct line_subseg *) xmalloc (sizeof (*ss));
26777298Sobrien  ss->next = *pss;
26877298Sobrien  ss->subseg = subseg;
26977298Sobrien  ss->head = NULL;
27077298Sobrien  ss->ptail = &ss->head;
27177298Sobrien  *pss = ss;
27260484Sobrien
27377298Sobrien found_subseg:
27477298Sobrien  last_seg = seg;
27577298Sobrien  last_subseg = subseg;
27677298Sobrien  last_line_subseg = ss;
27760484Sobrien
27877298Sobrien  return ss;
27977298Sobrien}
28060484Sobrien
281218822Sdim/* Record an entry for LOC occurring at LABEL.  */
282218822Sdim
283218822Sdimstatic void
284218822Sdimdwarf2_gen_line_info_1 (symbolS *label, struct dwarf2_line_info *loc)
285218822Sdim{
286218822Sdim  struct line_subseg *ss;
287218822Sdim  struct line_entry *e;
288218822Sdim
289218822Sdim  e = (struct line_entry *) xmalloc (sizeof (*e));
290218822Sdim  e->next = NULL;
291218822Sdim  e->label = label;
292218822Sdim  e->loc = *loc;
293218822Sdim
294218822Sdim  ss = get_line_subseg (now_seg, now_subseg);
295218822Sdim  *ss->ptail = e;
296218822Sdim  ss->ptail = &e->next;
297218822Sdim}
298218822Sdim
299130561Sobrien/* Record an entry for LOC occurring at OFS within the current fragment.  */
30060484Sobrien
30177298Sobrienvoid
302130561Sobriendwarf2_gen_line_info (addressT ofs, struct dwarf2_line_info *loc)
30360484Sobrien{
30489857Sobrien  static unsigned int line = -1;
30589857Sobrien  static unsigned int filenum = -1;
30660484Sobrien
307218822Sdim  symbolS *sym;
308218822Sdim
30977298Sobrien  /* Early out for as-yet incomplete location information.  */
31077298Sobrien  if (loc->filenum == 0 || loc->line == 0)
31177298Sobrien    return;
31277298Sobrien
313104834Sobrien  /* Don't emit sequences of line symbols for the same line when the
314104834Sobrien     symbols apply to assembler code.  It is necessary to emit
315104834Sobrien     duplicate line symbols when a compiler asks for them, because GDB
316104834Sobrien     uses them to determine the end of the prologue.  */
317104834Sobrien  if (debug_type == DEBUG_DWARF2
318104834Sobrien      && line == loc->line && filenum == loc->filenum)
31989857Sobrien    return;
32089857Sobrien
32189857Sobrien  line = loc->line;
32289857Sobrien  filenum = loc->filenum;
32389857Sobrien
324218822Sdim  sym = symbol_temp_new (now_seg, ofs, frag_now);
325218822Sdim  dwarf2_gen_line_info_1 (sym, loc);
32677298Sobrien}
32777298Sobrien
328218822Sdim/* Returns the current source information.  If .file directives have
329218822Sdim   been encountered, the info for the corresponding source file is
330218822Sdim   returned.  Otherwise, the info for the assembly source file is
331218822Sdim   returned.  */
332218822Sdim
33377298Sobrienvoid
334130561Sobriendwarf2_where (struct dwarf2_line_info *line)
33577298Sobrien{
33677298Sobrien  if (debug_type == DEBUG_DWARF2)
33760484Sobrien    {
33877298Sobrien      char *filename;
33977298Sobrien      as_where (&filename, &line->line);
340130561Sobrien      line->filenum = get_filenum (filename, 0);
34177298Sobrien      line->column = 0;
342218822Sdim      line->flags = DWARF2_FLAG_IS_STMT;
343218822Sdim      line->isa = current.isa;
34460484Sobrien    }
34577298Sobrien  else
34677298Sobrien    *line = current;
34760484Sobrien}
34860484Sobrien
349218822Sdim/* A hook to allow the target backend to inform the line number state
350218822Sdim   machine of isa changes when assembler debug info is enabled.  */
351218822Sdim
352218822Sdimvoid
353218822Sdimdwarf2_set_isa (unsigned int isa)
354218822Sdim{
355218822Sdim  current.isa = isa;
356218822Sdim}
357218822Sdim
35877298Sobrien/* Called for each machine instruction, or relatively atomic group of
35977298Sobrien   machine instructions (ie built-in macro).  The instruction or group
36077298Sobrien   is SIZE bytes in length.  If dwarf2 line number generation is called
36177298Sobrien   for, emit a line statement appropriately.  */
36277298Sobrien
36377298Sobrienvoid
364130561Sobriendwarf2_emit_insn (int size)
36560484Sobrien{
36677298Sobrien  struct dwarf2_line_info loc;
36760484Sobrien
368104834Sobrien  if (loc_directive_seen)
369104834Sobrien    {
370104834Sobrien      /* Use the last location established by a .loc directive, not
371104834Sobrien	 the value returned by dwarf2_where().  That calls as_where()
372104834Sobrien	 which will return either the logical input file name (foo.c)
373104834Sobrien	or the physical input file name (foo.s) and not the file name
374104834Sobrien	specified in the most recent .loc directive (eg foo.h).  */
375104834Sobrien      loc = current;
376104834Sobrien
377104834Sobrien      /* Unless we generate DWARF2 debugging information for each
378104834Sobrien	 assembler line, we only emit one line symbol for one LOC.  */
379104834Sobrien      if (debug_type != DEBUG_DWARF2)
380130561Sobrien	loc_directive_seen = FALSE;
381104834Sobrien    }
382104834Sobrien  else if (debug_type != DEBUG_DWARF2)
38377298Sobrien    return;
384104834Sobrien  else
385218822Sdim    dwarf2_where (&loc);
38677298Sobrien
38777298Sobrien  dwarf2_gen_line_info (frag_now_fix () - size, &loc);
388218822Sdim
389218822Sdim  current.flags &= ~(DWARF2_FLAG_BASIC_BLOCK
390218822Sdim		     | DWARF2_FLAG_PROLOGUE_END
391218822Sdim		     | DWARF2_FLAG_EPILOGUE_BEGIN);
39277298Sobrien}
39377298Sobrien
394218822Sdim/* Called for each (preferably code) label.  If dwarf2_loc_mark_labels
395218822Sdim   is enabled, emit a basic block marker.  */
396218822Sdim
397218822Sdimvoid
398218822Sdimdwarf2_emit_label (symbolS *label)
399218822Sdim{
400218822Sdim  struct dwarf2_line_info loc;
401218822Sdim
402218822Sdim  if (!dwarf2_loc_mark_labels)
403218822Sdim    return;
404218822Sdim  if (S_GET_SEGMENT (label) != now_seg)
405218822Sdim    return;
406218822Sdim  if (!(bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE))
407218822Sdim    return;
408218822Sdim
409218822Sdim  if (debug_type == DEBUG_DWARF2)
410218822Sdim    dwarf2_where (&loc);
411218822Sdim  else
412218822Sdim    {
413218822Sdim      loc = current;
414218822Sdim      loc_directive_seen = FALSE;
415218822Sdim    }
416218822Sdim
417218822Sdim  loc.flags |= DWARF2_FLAG_BASIC_BLOCK;
418218822Sdim
419218822Sdim  current.flags &= ~(DWARF2_FLAG_BASIC_BLOCK
420218822Sdim		     | DWARF2_FLAG_PROLOGUE_END
421218822Sdim		     | DWARF2_FLAG_EPILOGUE_BEGIN);
422218822Sdim
423218822Sdim  dwarf2_gen_line_info_1 (label, &loc);
424218822Sdim}
425218822Sdim
426130561Sobrien/* Get a .debug_line file number for FILENAME.  If NUM is nonzero,
427130561Sobrien   allocate it on that file table slot, otherwise return the first
428130561Sobrien   empty one.  */
42977298Sobrien
43077298Sobrienstatic unsigned int
431130561Sobrienget_filenum (const char *filename, unsigned int num)
43277298Sobrien{
433130561Sobrien  static unsigned int last_used, last_used_dir_len;
434130561Sobrien  const char *file;
435130561Sobrien  size_t dir_len;
436130561Sobrien  unsigned int i, dir;
43777298Sobrien
438130561Sobrien  if (num == 0 && last_used)
439130561Sobrien    {
440130561Sobrien      if (! files[last_used].dir
441130561Sobrien	  && strcmp (filename, files[last_used].filename) == 0)
442130561Sobrien	return last_used;
443130561Sobrien      if (files[last_used].dir
444130561Sobrien	  && strncmp (filename, dirs[files[last_used].dir],
445130561Sobrien		      last_used_dir_len) == 0
446130561Sobrien	  && IS_DIR_SEPARATOR (filename [last_used_dir_len])
447130561Sobrien	  && strcmp (filename + last_used_dir_len + 1,
448130561Sobrien		     files[last_used].filename) == 0)
449130561Sobrien	return last_used;
450130561Sobrien    }
45177298Sobrien
452130561Sobrien  file = lbasename (filename);
453130561Sobrien  /* Don't make empty string from / or A: from A:/ .  */
454130561Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
455130561Sobrien  if (file <= filename + 3)
456130561Sobrien    file = filename;
457130561Sobrien#else
458130561Sobrien  if (file == filename + 1)
459130561Sobrien    file = filename;
460130561Sobrien#endif
461130561Sobrien  dir_len = file - filename;
46277298Sobrien
463130561Sobrien  dir = 0;
464130561Sobrien  if (dir_len)
465130561Sobrien    {
466130561Sobrien      --dir_len;
467130561Sobrien      for (dir = 1; dir < dirs_in_use; ++dir)
468130561Sobrien	if (strncmp (filename, dirs[dir], dir_len) == 0
469130561Sobrien	    && dirs[dir][dir_len] == '\0')
470130561Sobrien	  break;
471130561Sobrien
472130561Sobrien      if (dir >= dirs_in_use)
473130561Sobrien	{
474130561Sobrien	  if (dir >= dirs_allocated)
475130561Sobrien	    {
476130561Sobrien	      dirs_allocated = dir + 32;
477130561Sobrien	      dirs = (char **)
478130561Sobrien		     xrealloc (dirs, (dir + 32) * sizeof (const char *));
479130561Sobrien	    }
480130561Sobrien
481130561Sobrien	  dirs[dir] = xmalloc (dir_len + 1);
482130561Sobrien	  memcpy (dirs[dir], filename, dir_len);
483130561Sobrien	  dirs[dir][dir_len] = '\0';
484130561Sobrien	  dirs_in_use = dir + 1;
485130561Sobrien	}
486130561Sobrien    }
487130561Sobrien
488130561Sobrien  if (num == 0)
489130561Sobrien    {
490130561Sobrien      for (i = 1; i < files_in_use; ++i)
491130561Sobrien	if (files[i].dir == dir
492130561Sobrien	    && files[i].filename
493130561Sobrien	    && strcmp (file, files[i].filename) == 0)
494130561Sobrien	  {
495130561Sobrien	    last_used = i;
496130561Sobrien	    last_used_dir_len = dir_len;
497130561Sobrien	    return i;
498130561Sobrien	  }
499130561Sobrien    }
500130561Sobrien  else
501130561Sobrien    i = num;
502130561Sobrien
50377298Sobrien  if (i >= files_allocated)
50460484Sobrien    {
50577298Sobrien      unsigned int old = files_allocated;
50677298Sobrien
50777298Sobrien      files_allocated = i + 32;
50877298Sobrien      files = (struct file_entry *)
50977298Sobrien	xrealloc (files, (i + 32) * sizeof (struct file_entry));
51077298Sobrien
51177298Sobrien      memset (files + old, 0, (i + 32 - old) * sizeof (struct file_entry));
51260484Sobrien    }
51377298Sobrien
514130561Sobrien  files[i].filename = num ? file : xstrdup (file);
515130561Sobrien  files[i].dir = dir;
516218822Sdim  if (files_in_use < i + 1)
517218822Sdim    files_in_use = i + 1;
51877298Sobrien  last_used = i;
519130561Sobrien  last_used_dir_len = dir_len;
52077298Sobrien
52177298Sobrien  return i;
52260484Sobrien}
52360484Sobrien
524104834Sobrien/* Handle two forms of .file directive:
525104834Sobrien   - Pass .file "source.c" to s_app_file
526104834Sobrien   - Handle .file 1 "source.c" by adding an entry to the DWARF-2 file table
52777298Sobrien
528104834Sobrien   If an entry is added to the file table, return a pointer to the filename. */
529104834Sobrien
530104834Sobrienchar *
531130561Sobriendwarf2_directive_file (int dummy ATTRIBUTE_UNUSED)
53260484Sobrien{
53377298Sobrien  offsetT num;
53478828Sobrien  char *filename;
53577298Sobrien  int filename_len;
53660484Sobrien
53777298Sobrien  /* Continue to accept a bare string and pass it off.  */
53877298Sobrien  SKIP_WHITESPACE ();
53977298Sobrien  if (*input_line_pointer == '"')
54060484Sobrien    {
54177298Sobrien      s_app_file (0);
542104834Sobrien      return NULL;
54360484Sobrien    }
54460484Sobrien
54577298Sobrien  num = get_absolute_expression ();
54677298Sobrien  filename = demand_copy_C_string (&filename_len);
547218822Sdim  if (filename == NULL)
548218822Sdim    return NULL;
54977298Sobrien  demand_empty_rest_of_line ();
55060484Sobrien
55177298Sobrien  if (num < 1)
55260484Sobrien    {
55389857Sobrien      as_bad (_("file number less than one"));
554104834Sobrien      return NULL;
55560484Sobrien    }
55660484Sobrien
55789857Sobrien  if (num < (int) files_in_use && files[num].filename != 0)
55860484Sobrien    {
55989857Sobrien      as_bad (_("file number %ld already allocated"), (long) num);
560104834Sobrien      return NULL;
56160484Sobrien    }
56260484Sobrien
563130561Sobrien  get_filenum (filename, num);
56460484Sobrien
565104834Sobrien  return filename;
56660484Sobrien}
56760484Sobrien
56877298Sobrienvoid
569130561Sobriendwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED)
57077298Sobrien{
571218822Sdim  offsetT filenum, line;
57277298Sobrien
57377298Sobrien  filenum = get_absolute_expression ();
57477298Sobrien  SKIP_WHITESPACE ();
57577298Sobrien  line = get_absolute_expression ();
57677298Sobrien
57777298Sobrien  if (filenum < 1)
57877298Sobrien    {
57989857Sobrien      as_bad (_("file number less than one"));
58077298Sobrien      return;
58177298Sobrien    }
58277298Sobrien  if (filenum >= (int) files_in_use || files[filenum].filename == 0)
58377298Sobrien    {
58489857Sobrien      as_bad (_("unassigned file number %ld"), (long) filenum);
58577298Sobrien      return;
58677298Sobrien    }
58777298Sobrien
58877298Sobrien  current.filenum = filenum;
58977298Sobrien  current.line = line;
59077298Sobrien
59177298Sobrien#ifndef NO_LISTING
59277298Sobrien  if (listing)
593104834Sobrien    {
594130561Sobrien      if (files[filenum].dir)
595130561Sobrien	{
596130561Sobrien	  size_t dir_len = strlen (dirs[files[filenum].dir]);
597130561Sobrien	  size_t file_len = strlen (files[filenum].filename);
598130561Sobrien	  char *cp = (char *) alloca (dir_len + 1 + file_len + 1);
599130561Sobrien
600130561Sobrien	  memcpy (cp, dirs[files[filenum].dir], dir_len);
601218822Sdim	  INSERT_DIR_SEPARATOR (cp, dir_len);
602130561Sobrien	  memcpy (cp + dir_len + 1, files[filenum].filename, file_len);
603130561Sobrien	  cp[dir_len + file_len + 1] = '\0';
604130561Sobrien	  listing_source_file (cp);
605130561Sobrien	}
606130561Sobrien      else
607130561Sobrien	listing_source_file (files[filenum].filename);
608104834Sobrien      listing_source_line (line);
609104834Sobrien    }
61077298Sobrien#endif
611218822Sdim
612218822Sdim  SKIP_WHITESPACE ();
613218822Sdim  if (ISDIGIT (*input_line_pointer))
614218822Sdim    {
615218822Sdim      current.column = get_absolute_expression ();
616218822Sdim      SKIP_WHITESPACE ();
617218822Sdim    }
618218822Sdim
619218822Sdim  while (ISALPHA (*input_line_pointer))
620218822Sdim    {
621218822Sdim      char *p, c;
622218822Sdim      offsetT value;
623218822Sdim
624218822Sdim      p = input_line_pointer;
625218822Sdim      c = get_symbol_end ();
626218822Sdim
627218822Sdim      if (strcmp (p, "basic_block") == 0)
628218822Sdim	{
629218822Sdim	  current.flags |= DWARF2_FLAG_BASIC_BLOCK;
630218822Sdim	  *input_line_pointer = c;
631218822Sdim	}
632218822Sdim      else if (strcmp (p, "prologue_end") == 0)
633218822Sdim	{
634218822Sdim	  current.flags |= DWARF2_FLAG_PROLOGUE_END;
635218822Sdim	  *input_line_pointer = c;
636218822Sdim	}
637218822Sdim      else if (strcmp (p, "epilogue_begin") == 0)
638218822Sdim	{
639218822Sdim	  current.flags |= DWARF2_FLAG_EPILOGUE_BEGIN;
640218822Sdim	  *input_line_pointer = c;
641218822Sdim	}
642218822Sdim      else if (strcmp (p, "is_stmt") == 0)
643218822Sdim	{
644218822Sdim	  *input_line_pointer = c;
645218822Sdim	  value = get_absolute_expression ();
646218822Sdim	  if (value == 0)
647218822Sdim	    current.flags &= ~DWARF2_FLAG_IS_STMT;
648218822Sdim	  else if (value == 1)
649218822Sdim	    current.flags |= DWARF2_FLAG_IS_STMT;
650218822Sdim	  else
651218822Sdim	    {
652218822Sdim	      as_bad (_("is_stmt value not 0 or 1"));
653218822Sdim	      return;
654218822Sdim	    }
655218822Sdim	}
656218822Sdim      else if (strcmp (p, "isa") == 0)
657218822Sdim	{
658218822Sdim          *input_line_pointer = c;
659218822Sdim	  value = get_absolute_expression ();
660218822Sdim	  if (value >= 0)
661218822Sdim	    current.isa = value;
662218822Sdim	  else
663218822Sdim	    {
664218822Sdim	      as_bad (_("isa number less than zero"));
665218822Sdim	      return;
666218822Sdim	    }
667218822Sdim	}
668218822Sdim      else
669218822Sdim	{
670218822Sdim	  as_bad (_("unknown .loc sub-directive `%s'"), p);
671218822Sdim          *input_line_pointer = c;
672218822Sdim	  return;
673218822Sdim	}
674218822Sdim
675218822Sdim      SKIP_WHITESPACE ();
676218822Sdim    }
677218822Sdim
678218822Sdim  demand_empty_rest_of_line ();
679218822Sdim  loc_directive_seen = TRUE;
68077298Sobrien}
681218822Sdim
682218822Sdimvoid
683218822Sdimdwarf2_directive_loc_mark_labels (int dummy ATTRIBUTE_UNUSED)
684218822Sdim{
685218822Sdim  offsetT value = get_absolute_expression ();
686218822Sdim
687218822Sdim  if (value != 0 && value != 1)
688218822Sdim    {
689218822Sdim      as_bad (_("expected 0 or 1"));
690218822Sdim      ignore_rest_of_line ();
691218822Sdim    }
692218822Sdim  else
693218822Sdim    {
694218822Sdim      dwarf2_loc_mark_labels = value != 0;
695218822Sdim      demand_empty_rest_of_line ();
696218822Sdim    }
697218822Sdim}
69877298Sobrien
69977298Sobrienstatic struct frag *
700130561Sobrienfirst_frag_for_seg (segT seg)
70177298Sobrien{
702218822Sdim  return seg_info (seg)->frchainP->frch_root;
70377298Sobrien}
70477298Sobrien
70577298Sobrienstatic struct frag *
706130561Sobrienlast_frag_for_seg (segT seg)
70777298Sobrien{
708218822Sdim  frchainS *f = seg_info (seg)->frchainP;
70977298Sobrien
710218822Sdim  while (f->frch_next != NULL)
711218822Sdim    f = f->frch_next;
71277298Sobrien
713218822Sdim  return f->frch_last;
71477298Sobrien}
71577298Sobrien
71677298Sobrien/* Emit a single byte into the current segment.  */
71777298Sobrien
71877298Sobrienstatic inline void
719130561Sobrienout_byte (int byte)
72077298Sobrien{
72177298Sobrien  FRAG_APPEND_1_CHAR (byte);
72277298Sobrien}
72377298Sobrien
72477298Sobrien/* Emit a statement program opcode into the current segment.  */
72577298Sobrien
72677298Sobrienstatic inline void
727130561Sobrienout_opcode (int opc)
72877298Sobrien{
72977298Sobrien  out_byte (opc);
73077298Sobrien}
73177298Sobrien
73277298Sobrien/* Emit a two-byte word into the current segment.  */
73377298Sobrien
73477298Sobrienstatic inline void
735130561Sobrienout_two (int data)
73677298Sobrien{
73777298Sobrien  md_number_to_chars (frag_more (2), data, 2);
73877298Sobrien}
73977298Sobrien
74077298Sobrien/* Emit a four byte word into the current segment.  */
74177298Sobrien
74277298Sobrienstatic inline void
743130561Sobrienout_four (int data)
74477298Sobrien{
74577298Sobrien  md_number_to_chars (frag_more (4), data, 4);
74677298Sobrien}
74777298Sobrien
74877298Sobrien/* Emit an unsigned "little-endian base 128" number.  */
74977298Sobrien
75060484Sobrienstatic void
751130561Sobrienout_uleb128 (addressT value)
75260484Sobrien{
75377298Sobrien  output_leb128 (frag_more (sizeof_leb128 (value, 0)), value, 0);
75477298Sobrien}
75560484Sobrien
756218822Sdim/* Emit a signed "little-endian base 128" number.  */
757218822Sdim
758218822Sdimstatic void
759218822Sdimout_sleb128 (addressT value)
760218822Sdim{
761218822Sdim  output_leb128 (frag_more (sizeof_leb128 (value, 1)), value, 1);
762218822Sdim}
763218822Sdim
76477298Sobrien/* Emit a tuple for .debug_abbrev.  */
76577298Sobrien
76677298Sobrienstatic inline void
767130561Sobrienout_abbrev (int name, int form)
76877298Sobrien{
76977298Sobrien  out_uleb128 (name);
77077298Sobrien  out_uleb128 (form);
77160484Sobrien}
77260484Sobrien
77377298Sobrien/* Get the size of a fragment.  */
77460484Sobrien
77577298Sobrienstatic offsetT
776218822Sdimget_frag_fix (fragS *frag, segT seg)
77777298Sobrien{
77877298Sobrien  frchainS *fr;
77960484Sobrien
78077298Sobrien  if (frag->fr_next)
78177298Sobrien    return frag->fr_fix;
78260484Sobrien
78377298Sobrien  /* If a fragment is the last in the chain, special measures must be
78477298Sobrien     taken to find its size before relaxation, since it may be pending
78577298Sobrien     on some subsegment chain.  */
786218822Sdim  for (fr = seg_info (seg)->frchainP; fr; fr = fr->frch_next)
78777298Sobrien    if (fr->frch_last == frag)
788130561Sobrien      return (char *) obstack_next_free (&fr->frch_obstack) - frag->fr_literal;
78960484Sobrien
79077298Sobrien  abort ();
79177298Sobrien}
79277298Sobrien
79377298Sobrien/* Set an absolute address (may result in a relocation entry).  */
79477298Sobrien
79577298Sobrienstatic void
796218822Sdimout_set_addr (symbolS *sym)
79777298Sobrien{
79877298Sobrien  expressionS expr;
79977298Sobrien
80060484Sobrien  out_opcode (DW_LNS_extended_op);
80177298Sobrien  out_uleb128 (sizeof_address + 1);
80260484Sobrien
80360484Sobrien  out_opcode (DW_LNE_set_address);
80460484Sobrien  expr.X_op = O_symbol;
80560484Sobrien  expr.X_add_symbol = sym;
80660484Sobrien  expr.X_add_number = 0;
80777298Sobrien  emit_expr (&expr, sizeof_address);
80860484Sobrien}
80960484Sobrien
810130561Sobrien#if DWARF2_LINE_MIN_INSN_LENGTH > 1
811130561Sobrienstatic void scale_addr_delta (addressT *);
812130561Sobrien
813130561Sobrienstatic void
814130561Sobrienscale_addr_delta (addressT *addr_delta)
815130561Sobrien{
816130561Sobrien  static int printed_this = 0;
817130561Sobrien  if (*addr_delta % DWARF2_LINE_MIN_INSN_LENGTH != 0)
818130561Sobrien    {
819130561Sobrien      if (!printed_this)
820130561Sobrien	as_bad("unaligned opcodes detected in executable segment");
821130561Sobrien      printed_this = 1;
822130561Sobrien    }
823130561Sobrien  *addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH;
824130561Sobrien}
825130561Sobrien#else
826130561Sobrien#define scale_addr_delta(A)
827130561Sobrien#endif
828130561Sobrien
82977298Sobrien/* Encode a pair of line and address skips as efficiently as possible.
83077298Sobrien   Note that the line skip is signed, whereas the address skip is unsigned.
83177298Sobrien
83277298Sobrien   The following two routines *must* be kept in sync.  This is
83377298Sobrien   enforced by making emit_inc_line_addr abort if we do not emit
83477298Sobrien   exactly the expected number of bytes.  */
83577298Sobrien
83677298Sobrienstatic int
837130561Sobriensize_inc_line_addr (int line_delta, addressT addr_delta)
83860484Sobrien{
83977298Sobrien  unsigned int tmp, opcode;
84077298Sobrien  int len = 0;
84160484Sobrien
84277298Sobrien  /* Scale the address delta by the minimum instruction length.  */
843130561Sobrien  scale_addr_delta (&addr_delta);
84477298Sobrien
84577298Sobrien  /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence.
84677298Sobrien     We cannot use special opcodes here, since we want the end_sequence
84777298Sobrien     to emit the matrix entry.  */
84877298Sobrien  if (line_delta == INT_MAX)
84960484Sobrien    {
85077298Sobrien      if (addr_delta == MAX_SPECIAL_ADDR_DELTA)
85177298Sobrien	len = 1;
85260484Sobrien      else
85377298Sobrien	len = 1 + sizeof_leb128 (addr_delta, 0);
85477298Sobrien      return len + 3;
85560484Sobrien    }
85660484Sobrien
85777298Sobrien  /* Bias the line delta by the base.  */
85877298Sobrien  tmp = line_delta - DWARF2_LINE_BASE;
85960484Sobrien
86077298Sobrien  /* If the line increment is out of range of a special opcode, we
86177298Sobrien     must encode it with DW_LNS_advance_line.  */
86277298Sobrien  if (tmp >= DWARF2_LINE_RANGE)
86377298Sobrien    {
86477298Sobrien      len = 1 + sizeof_leb128 (line_delta, 1);
86577298Sobrien      line_delta = 0;
86677298Sobrien      tmp = 0 - DWARF2_LINE_BASE;
86777298Sobrien    }
86877298Sobrien
86977298Sobrien  /* Bias the opcode by the special opcode base.  */
87077298Sobrien  tmp += DWARF2_LINE_OPCODE_BASE;
87177298Sobrien
87277298Sobrien  /* Avoid overflow when addr_delta is large.  */
87377298Sobrien  if (addr_delta < 256 + MAX_SPECIAL_ADDR_DELTA)
87477298Sobrien    {
87577298Sobrien      /* Try using a special opcode.  */
87677298Sobrien      opcode = tmp + addr_delta * DWARF2_LINE_RANGE;
87777298Sobrien      if (opcode <= 255)
87877298Sobrien	return len + 1;
87977298Sobrien
88077298Sobrien      /* Try using DW_LNS_const_add_pc followed by special op.  */
88177298Sobrien      opcode = tmp + (addr_delta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE;
88277298Sobrien      if (opcode <= 255)
88377298Sobrien	return len + 2;
88477298Sobrien    }
88577298Sobrien
88677298Sobrien  /* Otherwise use DW_LNS_advance_pc.  */
88777298Sobrien  len += 1 + sizeof_leb128 (addr_delta, 0);
88877298Sobrien
88977298Sobrien  /* DW_LNS_copy or special opcode.  */
89077298Sobrien  len += 1;
89177298Sobrien
89277298Sobrien  return len;
89360484Sobrien}
89460484Sobrien
89577298Sobrienstatic void
896130561Sobrienemit_inc_line_addr (int line_delta, addressT addr_delta, char *p, int len)
89760484Sobrien{
89877298Sobrien  unsigned int tmp, opcode;
89977298Sobrien  int need_copy = 0;
90077298Sobrien  char *end = p + len;
90160484Sobrien
902218822Sdim  /* Line number sequences cannot go backward in addresses.  This means
903218822Sdim     we've incorrectly ordered the statements in the sequence.  */
904218822Sdim  assert ((offsetT) addr_delta >= 0);
905218822Sdim
90677298Sobrien  /* Scale the address delta by the minimum instruction length.  */
907130561Sobrien  scale_addr_delta (&addr_delta);
908130561Sobrien
90977298Sobrien  /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence.
91077298Sobrien     We cannot use special opcodes here, since we want the end_sequence
91177298Sobrien     to emit the matrix entry.  */
91277298Sobrien  if (line_delta == INT_MAX)
91360484Sobrien    {
91477298Sobrien      if (addr_delta == MAX_SPECIAL_ADDR_DELTA)
91577298Sobrien	*p++ = DW_LNS_const_add_pc;
91677298Sobrien      else
91760484Sobrien	{
91877298Sobrien	  *p++ = DW_LNS_advance_pc;
91977298Sobrien	  p += output_leb128 (p, addr_delta, 0);
92060484Sobrien	}
92177298Sobrien
92277298Sobrien      *p++ = DW_LNS_extended_op;
92377298Sobrien      *p++ = 1;
92477298Sobrien      *p++ = DW_LNE_end_sequence;
92577298Sobrien      goto done;
92660484Sobrien    }
92760484Sobrien
92877298Sobrien  /* Bias the line delta by the base.  */
92977298Sobrien  tmp = line_delta - DWARF2_LINE_BASE;
93077298Sobrien
93177298Sobrien  /* If the line increment is out of range of a special opcode, we
93277298Sobrien     must encode it with DW_LNS_advance_line.  */
93377298Sobrien  if (tmp >= DWARF2_LINE_RANGE)
93460484Sobrien    {
93577298Sobrien      *p++ = DW_LNS_advance_line;
93677298Sobrien      p += output_leb128 (p, line_delta, 1);
93760484Sobrien
93877298Sobrien      line_delta = 0;
93977298Sobrien      tmp = 0 - DWARF2_LINE_BASE;
94077298Sobrien      need_copy = 1;
94177298Sobrien    }
94260484Sobrien
943218822Sdim  /* Prettier, I think, to use DW_LNS_copy instead of a "line +0, addr +0"
944218822Sdim     special opcode.  */
945218822Sdim  if (line_delta == 0 && addr_delta == 0)
946218822Sdim    {
947218822Sdim      *p++ = DW_LNS_copy;
948218822Sdim      goto done;
949218822Sdim    }
950218822Sdim
95177298Sobrien  /* Bias the opcode by the special opcode base.  */
95277298Sobrien  tmp += DWARF2_LINE_OPCODE_BASE;
95360484Sobrien
95477298Sobrien  /* Avoid overflow when addr_delta is large.  */
95577298Sobrien  if (addr_delta < 256 + MAX_SPECIAL_ADDR_DELTA)
95660484Sobrien    {
95777298Sobrien      /* Try using a special opcode.  */
95877298Sobrien      opcode = tmp + addr_delta * DWARF2_LINE_RANGE;
95977298Sobrien      if (opcode <= 255)
96060484Sobrien	{
96177298Sobrien	  *p++ = opcode;
96277298Sobrien	  goto done;
96360484Sobrien	}
96477298Sobrien
96577298Sobrien      /* Try using DW_LNS_const_add_pc followed by special op.  */
96677298Sobrien      opcode = tmp + (addr_delta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE;
96777298Sobrien      if (opcode <= 255)
96877298Sobrien	{
96977298Sobrien	  *p++ = DW_LNS_const_add_pc;
97077298Sobrien	  *p++ = opcode;
97177298Sobrien	  goto done;
97277298Sobrien	}
97360484Sobrien    }
97477298Sobrien
97577298Sobrien  /* Otherwise use DW_LNS_advance_pc.  */
97677298Sobrien  *p++ = DW_LNS_advance_pc;
97777298Sobrien  p += output_leb128 (p, addr_delta, 0);
97877298Sobrien
97977298Sobrien  if (need_copy)
98077298Sobrien    *p++ = DW_LNS_copy;
98160484Sobrien  else
98277298Sobrien    *p++ = tmp;
98360484Sobrien
98477298Sobrien done:
98577298Sobrien  assert (p == end);
98677298Sobrien}
98760484Sobrien
98877298Sobrien/* Handy routine to combine calls to the above two routines.  */
98960484Sobrien
99077298Sobrienstatic void
991130561Sobrienout_inc_line_addr (int line_delta, addressT addr_delta)
99277298Sobrien{
99377298Sobrien  int len = size_inc_line_addr (line_delta, addr_delta);
99477298Sobrien  emit_inc_line_addr (line_delta, addr_delta, frag_more (len), len);
99577298Sobrien}
99660484Sobrien
997218822Sdim/* Write out an alternative form of line and address skips using
998218822Sdim   DW_LNS_fixed_advance_pc opcodes.  This uses more space than the default
999218822Sdim   line and address information, but it helps support linker relaxation that
1000218822Sdim   changes the code offsets.  */
1001218822Sdim
1002218822Sdimstatic void
1003218822Sdimout_fixed_inc_line_addr (int line_delta, symbolS *to_sym, symbolS *from_sym)
1004218822Sdim{
1005218822Sdim  expressionS expr;
1006218822Sdim
1007218822Sdim  /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence.  */
1008218822Sdim  if (line_delta == INT_MAX)
1009218822Sdim    {
1010218822Sdim      out_opcode (DW_LNS_fixed_advance_pc);
1011218822Sdim      expr.X_op = O_subtract;
1012218822Sdim      expr.X_add_symbol = to_sym;
1013218822Sdim      expr.X_op_symbol = from_sym;
1014218822Sdim      expr.X_add_number = 0;
1015218822Sdim      emit_expr (&expr, 2);
1016218822Sdim
1017218822Sdim      out_opcode (DW_LNS_extended_op);
1018218822Sdim      out_byte (1);
1019218822Sdim      out_opcode (DW_LNE_end_sequence);
1020218822Sdim      return;
1021218822Sdim    }
1022218822Sdim
1023218822Sdim  out_opcode (DW_LNS_advance_line);
1024218822Sdim  out_sleb128 (line_delta);
1025218822Sdim
1026218822Sdim  out_opcode (DW_LNS_fixed_advance_pc);
1027218822Sdim  expr.X_op = O_subtract;
1028218822Sdim  expr.X_add_symbol = to_sym;
1029218822Sdim  expr.X_op_symbol = from_sym;
1030218822Sdim  expr.X_add_number = 0;
1031218822Sdim  emit_expr (&expr, 2);
1032218822Sdim
1033218822Sdim  out_opcode (DW_LNS_copy);
1034218822Sdim}
1035218822Sdim
103677298Sobrien/* Generate a variant frag that we can use to relax address/line
103777298Sobrien   increments between fragments of the target segment.  */
103860484Sobrien
103977298Sobrienstatic void
1040218822Sdimrelax_inc_line_addr (int line_delta, symbolS *to_sym, symbolS *from_sym)
104177298Sobrien{
104277298Sobrien  expressionS expr;
104377298Sobrien  int max_chars;
104460484Sobrien
104577298Sobrien  expr.X_op = O_subtract;
104677298Sobrien  expr.X_add_symbol = to_sym;
104777298Sobrien  expr.X_op_symbol = from_sym;
104877298Sobrien  expr.X_add_number = 0;
104960484Sobrien
105077298Sobrien  /* The maximum size of the frag is the line delta with a maximum
105177298Sobrien     sized address delta.  */
105277298Sobrien  max_chars = size_inc_line_addr (line_delta, -DWARF2_LINE_MIN_INSN_LENGTH);
105360484Sobrien
105477298Sobrien  frag_var (rs_dwarf2dbg, max_chars, max_chars, 1,
105577298Sobrien	    make_expr_symbol (&expr), line_delta, NULL);
105677298Sobrien}
105760484Sobrien
105877298Sobrien/* The function estimates the size of a rs_dwarf2dbg variant frag
105977298Sobrien   based on the current values of the symbols.  It is called before
106077298Sobrien   the relaxation loop.  We set fr_subtype to the expected length.  */
106160484Sobrien
106277298Sobrienint
1063130561Sobriendwarf2dbg_estimate_size_before_relax (fragS *frag)
106477298Sobrien{
106577298Sobrien  offsetT addr_delta;
106677298Sobrien  int size;
106760484Sobrien
106889857Sobrien  addr_delta = resolve_symbol_value (frag->fr_symbol);
106977298Sobrien  size = size_inc_line_addr (frag->fr_offset, addr_delta);
107060484Sobrien
107177298Sobrien  frag->fr_subtype = size;
107260484Sobrien
107377298Sobrien  return size;
107460484Sobrien}
107560484Sobrien
107677298Sobrien/* This function relaxes a rs_dwarf2dbg variant frag based on the
107777298Sobrien   current values of the symbols.  fr_subtype is the current length
107877298Sobrien   of the frag.  This returns the change in frag length.  */
107977298Sobrien
108077298Sobrienint
1081130561Sobriendwarf2dbg_relax_frag (fragS *frag)
108277298Sobrien{
108377298Sobrien  int old_size, new_size;
108477298Sobrien
108577298Sobrien  old_size = frag->fr_subtype;
108677298Sobrien  new_size = dwarf2dbg_estimate_size_before_relax (frag);
108777298Sobrien
108877298Sobrien  return new_size - old_size;
108977298Sobrien}
109077298Sobrien
109177298Sobrien/* This function converts a rs_dwarf2dbg variant frag into a normal
109277298Sobrien   fill frag.  This is called after all relaxation has been done.
109377298Sobrien   fr_subtype will be the desired length of the frag.  */
109477298Sobrien
109577298Sobrienvoid
1096130561Sobriendwarf2dbg_convert_frag (fragS *frag)
109777298Sobrien{
109877298Sobrien  offsetT addr_diff;
109977298Sobrien
110089857Sobrien  addr_diff = resolve_symbol_value (frag->fr_symbol);
110177298Sobrien
110277298Sobrien  /* fr_var carries the max_chars that we created the fragment with.
110377298Sobrien     fr_subtype carries the current expected length.  We must, of
110477298Sobrien     course, have allocated enough memory earlier.  */
110577298Sobrien  assert (frag->fr_var >= (int) frag->fr_subtype);
110677298Sobrien
110777298Sobrien  emit_inc_line_addr (frag->fr_offset, addr_diff,
110877298Sobrien		      frag->fr_literal + frag->fr_fix, frag->fr_subtype);
110977298Sobrien
111077298Sobrien  frag->fr_fix += frag->fr_subtype;
111177298Sobrien  frag->fr_type = rs_fill;
111277298Sobrien  frag->fr_var = 0;
111377298Sobrien  frag->fr_offset = 0;
111477298Sobrien}
111577298Sobrien
111677298Sobrien/* Generate .debug_line content for the chain of line number entries
111777298Sobrien   beginning at E, for segment SEG.  */
111877298Sobrien
111960484Sobrienstatic void
1120130561Sobrienprocess_entries (segT seg, struct line_entry *e)
112160484Sobrien{
112277298Sobrien  unsigned filenum = 1;
112377298Sobrien  unsigned line = 1;
112477298Sobrien  unsigned column = 0;
1125218822Sdim  unsigned isa = 0;
1126218822Sdim  unsigned flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
1127218822Sdim  fragS *last_frag = NULL, *frag;
1128218822Sdim  addressT last_frag_ofs = 0, frag_ofs;
1129218822Sdim  symbolS *last_lab = NULL, *lab;
113077298Sobrien  struct line_entry *next;
113160484Sobrien
1132218822Sdim  do
113377298Sobrien    {
1134218822Sdim      int line_delta;
113560484Sobrien
113677298Sobrien      if (filenum != e->loc.filenum)
113760484Sobrien	{
113877298Sobrien	  filenum = e->loc.filenum;
113977298Sobrien	  out_opcode (DW_LNS_set_file);
114077298Sobrien	  out_uleb128 (filenum);
114177298Sobrien	}
114277298Sobrien
114377298Sobrien      if (column != e->loc.column)
114477298Sobrien	{
114577298Sobrien	  column = e->loc.column;
114677298Sobrien	  out_opcode (DW_LNS_set_column);
114777298Sobrien	  out_uleb128 (column);
114877298Sobrien	}
114977298Sobrien
1150218822Sdim      if (isa != e->loc.isa)
115177298Sobrien	{
1152218822Sdim	  isa = e->loc.isa;
1153218822Sdim	  out_opcode (DW_LNS_set_isa);
1154218822Sdim	  out_uleb128 (isa);
115577298Sobrien	}
115677298Sobrien
1157218822Sdim      if ((e->loc.flags ^ flags) & DWARF2_FLAG_IS_STMT)
115877298Sobrien	{
1159218822Sdim	  flags = e->loc.flags;
1160218822Sdim	  out_opcode (DW_LNS_negate_stmt);
116177298Sobrien	}
116277298Sobrien
1163218822Sdim      if (e->loc.flags & DWARF2_FLAG_BASIC_BLOCK)
1164218822Sdim	out_opcode (DW_LNS_set_basic_block);
1165218822Sdim
1166218822Sdim      if (e->loc.flags & DWARF2_FLAG_PROLOGUE_END)
1167218822Sdim	out_opcode (DW_LNS_set_prologue_end);
1168218822Sdim
1169218822Sdim      if (e->loc.flags & DWARF2_FLAG_EPILOGUE_BEGIN)
1170218822Sdim	out_opcode (DW_LNS_set_epilogue_begin);
1171218822Sdim
117278828Sobrien      /* Don't try to optimize away redundant entries; gdb wants two
117378828Sobrien	 entries for a function where the code starts on the same line as
117478828Sobrien	 the {, and there's no way to identify that case here.  Trust gcc
117578828Sobrien	 to optimize appropriately.  */
1176218822Sdim      line_delta = e->loc.line - line;
1177218822Sdim      lab = e->label;
1178218822Sdim      frag = symbol_get_frag (lab);
1179218822Sdim      frag_ofs = S_GET_VALUE (lab);
118077298Sobrien
1181218822Sdim      if (last_frag == NULL)
118277298Sobrien	{
1183218822Sdim	  out_set_addr (lab);
1184218822Sdim	  out_inc_line_addr (line_delta, 0);
118577298Sobrien	}
1186218822Sdim      else if (DWARF2_USE_FIXED_ADVANCE_PC)
1187218822Sdim	out_fixed_inc_line_addr (line_delta, lab, last_lab);
1188218822Sdim      else if (frag == last_frag)
1189218822Sdim	out_inc_line_addr (line_delta, frag_ofs - last_frag_ofs);
1190218822Sdim      else
1191218822Sdim	relax_inc_line_addr (line_delta, lab, last_lab);
119277298Sobrien
1193218822Sdim      line = e->loc.line;
1194218822Sdim      last_lab = lab;
1195218822Sdim      last_frag = frag;
1196218822Sdim      last_frag_ofs = frag_ofs;
1197218822Sdim
119877298Sobrien      next = e->next;
119977298Sobrien      free (e);
120077298Sobrien      e = next;
120160484Sobrien    }
1202218822Sdim  while (e);
120377298Sobrien
120477298Sobrien  /* Emit a DW_LNE_end_sequence for the end of the section.  */
1205218822Sdim  frag = last_frag_for_seg (seg);
1206218822Sdim  frag_ofs = get_frag_fix (frag, seg);
1207218822Sdim  if (DWARF2_USE_FIXED_ADVANCE_PC)
1208218822Sdim    {
1209218822Sdim      lab = symbol_temp_new (seg, frag_ofs, frag);
1210218822Sdim      out_fixed_inc_line_addr (INT_MAX, lab, last_lab);
1211218822Sdim    }
1212218822Sdim  else if (frag == last_frag)
1213218822Sdim    out_inc_line_addr (INT_MAX, frag_ofs - last_frag_ofs);
121477298Sobrien  else
1215218822Sdim    {
1216218822Sdim      lab = symbol_temp_new (seg, frag_ofs, frag);
1217218822Sdim      relax_inc_line_addr (INT_MAX, lab, last_lab);
1218218822Sdim    }
121960484Sobrien}
122060484Sobrien
122177298Sobrien/* Emit the directory and file tables for .debug_line.  */
122277298Sobrien
122360484Sobrienstatic void
1224130561Sobrienout_file_list (void)
122560484Sobrien{
122660484Sobrien  size_t size;
122760484Sobrien  char *cp;
122877298Sobrien  unsigned int i;
122960484Sobrien
1230130561Sobrien  /* Emit directory list.  */
1231130561Sobrien  for (i = 1; i < dirs_in_use; ++i)
1232130561Sobrien    {
1233130561Sobrien      size = strlen (dirs[i]) + 1;
1234130561Sobrien      cp = frag_more (size);
1235130561Sobrien      memcpy (cp, dirs[i], size);
1236130561Sobrien    }
1237130561Sobrien  /* Terminate it.  */
123877298Sobrien  out_byte ('\0');
123977298Sobrien
124077298Sobrien  for (i = 1; i < files_in_use; ++i)
124160484Sobrien    {
124277298Sobrien      if (files[i].filename == NULL)
124377298Sobrien	{
124489857Sobrien	  as_bad (_("unassigned file number %ld"), (long) i);
1245130561Sobrien	  /* Prevent a crash later, particularly for file 1.  */
1246130561Sobrien	  files[i].filename = "";
124777298Sobrien	  continue;
124877298Sobrien	}
124977298Sobrien
125077298Sobrien      size = strlen (files[i].filename) + 1;
125160484Sobrien      cp = frag_more (size);
125277298Sobrien      memcpy (cp, files[i].filename, size);
125360484Sobrien
125477298Sobrien      out_uleb128 (files[i].dir);	/* directory number */
125560484Sobrien      out_uleb128 (0);			/* last modification timestamp */
125660484Sobrien      out_uleb128 (0);			/* filesize */
125760484Sobrien    }
125877298Sobrien
125977298Sobrien  /* Terminate filename list.  */
126077298Sobrien  out_byte (0);
126160484Sobrien}
126260484Sobrien
126377298Sobrien/* Emit the collected .debug_line data.  */
126477298Sobrien
126560484Sobrienstatic void
1266130561Sobrienout_debug_line (segT line_seg)
126760484Sobrien{
126877298Sobrien  expressionS expr;
126977298Sobrien  symbolS *line_start;
127077298Sobrien  symbolS *prologue_end;
127177298Sobrien  symbolS *line_end;
127277298Sobrien  struct line_seg *s;
1273130561Sobrien  enum dwarf2_format d2f;
1274256692Semaste  int sizeof_initial_length;
1275130561Sobrien  int sizeof_offset;
127677298Sobrien
127777298Sobrien  subseg_set (line_seg, 0);
127877298Sobrien
1279130561Sobrien  line_start = symbol_temp_new_now ();
1280130561Sobrien  prologue_end = symbol_temp_make ();
1281130561Sobrien  line_end = symbol_temp_make ();
128277298Sobrien
128377298Sobrien  /* Total length of the information for this compilation unit.  */
128477298Sobrien  expr.X_op = O_subtract;
128577298Sobrien  expr.X_add_symbol = line_end;
128677298Sobrien  expr.X_op_symbol = line_start;
128777298Sobrien
1288130561Sobrien  d2f = DWARF2_FORMAT ();
1289130561Sobrien  if (d2f == dwarf2_format_32bit)
1290130561Sobrien    {
1291256692Semaste      sizeof_initial_length = sizeof_offset = 4;
1292130561Sobrien    }
1293130561Sobrien  else if (d2f == dwarf2_format_64bit)
1294130561Sobrien    {
1295256692Semaste      sizeof_initial_length = 12;
1296256692Semaste      sizeof_offset = 8;
1297130561Sobrien      out_four (-1);
1298130561Sobrien    }
1299130561Sobrien  else if (d2f == dwarf2_format_64bit_irix)
1300130561Sobrien    {
1301256692Semaste      sizeof_initial_length = sizeof_offset = 8;
1302130561Sobrien    }
1303130561Sobrien  else
1304130561Sobrien    {
1305130561Sobrien      as_fatal (_("internal error: unknown dwarf2 format"));
1306130561Sobrien    }
1307256692Semaste  expr.X_add_number = -sizeof_initial_length;
1308256692Semaste  emit_expr (&expr, sizeof_offset);
1309130561Sobrien
131077298Sobrien  /* Version.  */
131177298Sobrien  out_two (2);
131277298Sobrien
131377298Sobrien  /* Length of the prologue following this length.  */
131477298Sobrien  expr.X_op = O_subtract;
131577298Sobrien  expr.X_add_symbol = prologue_end;
131677298Sobrien  expr.X_op_symbol = line_start;
1317256692Semaste  expr.X_add_number = - (sizeof_initial_length + 2 + sizeof_offset);
1318130561Sobrien  emit_expr (&expr, sizeof_offset);
131977298Sobrien
132077298Sobrien  /* Parameters of the state machine.  */
132177298Sobrien  out_byte (DWARF2_LINE_MIN_INSN_LENGTH);
132277298Sobrien  out_byte (DWARF2_LINE_DEFAULT_IS_STMT);
132377298Sobrien  out_byte (DWARF2_LINE_BASE);
132477298Sobrien  out_byte (DWARF2_LINE_RANGE);
132577298Sobrien  out_byte (DWARF2_LINE_OPCODE_BASE);
132677298Sobrien
132777298Sobrien  /* Standard opcode lengths.  */
132877298Sobrien  out_byte (0);			/* DW_LNS_copy */
132977298Sobrien  out_byte (1);			/* DW_LNS_advance_pc */
133077298Sobrien  out_byte (1);			/* DW_LNS_advance_line */
133177298Sobrien  out_byte (1);			/* DW_LNS_set_file */
133277298Sobrien  out_byte (1);			/* DW_LNS_set_column */
133377298Sobrien  out_byte (0);			/* DW_LNS_negate_stmt */
133477298Sobrien  out_byte (0);			/* DW_LNS_set_basic_block */
133577298Sobrien  out_byte (0);			/* DW_LNS_const_add_pc */
133677298Sobrien  out_byte (1);			/* DW_LNS_fixed_advance_pc */
1337218822Sdim  out_byte (0);			/* DW_LNS_set_prologue_end */
1338218822Sdim  out_byte (0);			/* DW_LNS_set_epilogue_begin */
1339218822Sdim  out_byte (1);			/* DW_LNS_set_isa */
134077298Sobrien
134177298Sobrien  out_file_list ();
134277298Sobrien
1343130561Sobrien  symbol_set_value_now (prologue_end);
134477298Sobrien
134577298Sobrien  /* For each section, emit a statement program.  */
134677298Sobrien  for (s = all_segs; s; s = s->next)
134777298Sobrien    process_entries (s->seg, s->head->head);
134877298Sobrien
1349130561Sobrien  symbol_set_value_now (line_end);
135077298Sobrien}
135177298Sobrien
1352218822Sdimstatic void
1353218822Sdimout_debug_ranges (segT ranges_seg)
1354218822Sdim{
1355218822Sdim  unsigned int addr_size = sizeof_address;
1356218822Sdim  struct line_seg *s;
1357218822Sdim  expressionS expr;
1358218822Sdim  unsigned int i;
1359218822Sdim
1360218822Sdim  subseg_set (ranges_seg, 0);
1361218822Sdim
1362218822Sdim  /* Base Address Entry.  */
1363218822Sdim  for (i = 0; i < addr_size; i++)
1364218822Sdim    out_byte (0xff);
1365218822Sdim  for (i = 0; i < addr_size; i++)
1366218822Sdim    out_byte (0);
1367218822Sdim
1368218822Sdim  /* Range List Entry.  */
1369218822Sdim  for (s = all_segs; s; s = s->next)
1370218822Sdim    {
1371218822Sdim      fragS *frag;
1372218822Sdim      symbolS *beg, *end;
1373218822Sdim
1374218822Sdim      frag = first_frag_for_seg (s->seg);
1375218822Sdim      beg = symbol_temp_new (s->seg, 0, frag);
1376218822Sdim      s->text_start = beg;
1377218822Sdim
1378218822Sdim      frag = last_frag_for_seg (s->seg);
1379218822Sdim      end = symbol_temp_new (s->seg, get_frag_fix (frag, s->seg), frag);
1380218822Sdim      s->text_end = end;
1381218822Sdim
1382218822Sdim      expr.X_op = O_symbol;
1383218822Sdim      expr.X_add_symbol = beg;
1384218822Sdim      expr.X_add_number = 0;
1385218822Sdim      emit_expr (&expr, addr_size);
1386218822Sdim
1387218822Sdim      expr.X_op = O_symbol;
1388218822Sdim      expr.X_add_symbol = end;
1389218822Sdim      expr.X_add_number = 0;
1390218822Sdim      emit_expr (&expr, addr_size);
1391218822Sdim    }
1392218822Sdim
1393218822Sdim  /* End of Range Entry.   */
1394218822Sdim  for (i = 0; i < addr_size; i++)
1395218822Sdim    out_byte (0);
1396218822Sdim  for (i = 0; i < addr_size; i++)
1397218822Sdim    out_byte (0);
1398218822Sdim}
1399218822Sdim
140077298Sobrien/* Emit data for .debug_aranges.  */
140177298Sobrien
140277298Sobrienstatic void
1403130561Sobrienout_debug_aranges (segT aranges_seg, segT info_seg)
140477298Sobrien{
140577298Sobrien  unsigned int addr_size = sizeof_address;
140677298Sobrien  addressT size, skip;
140777298Sobrien  struct line_seg *s;
140877298Sobrien  expressionS expr;
140977298Sobrien  char *p;
141077298Sobrien
141177298Sobrien  size = 4 + 2 + 4 + 1 + 1;
141277298Sobrien
141377298Sobrien  skip = 2 * addr_size - (size & (2 * addr_size - 1));
141477298Sobrien  if (skip == 2 * addr_size)
141577298Sobrien    skip = 0;
141677298Sobrien  size += skip;
141777298Sobrien
141877298Sobrien  for (s = all_segs; s; s = s->next)
141977298Sobrien    size += 2 * addr_size;
142077298Sobrien
142177298Sobrien  size += 2 * addr_size;
142277298Sobrien
142377298Sobrien  subseg_set (aranges_seg, 0);
142477298Sobrien
142577298Sobrien  /* Length of the compilation unit.  */
142677298Sobrien  out_four (size - 4);
142777298Sobrien
142877298Sobrien  /* Version.  */
142977298Sobrien  out_two (2);
143077298Sobrien
143177298Sobrien  /* Offset to .debug_info.  */
1432130561Sobrien  /* ??? sizeof_offset */
1433130561Sobrien  TC_DWARF2_EMIT_OFFSET (section_symbol (info_seg), 4);
143477298Sobrien
143577298Sobrien  /* Size of an address (offset portion).  */
143677298Sobrien  out_byte (addr_size);
143777298Sobrien
143877298Sobrien  /* Size of a segment descriptor.  */
143977298Sobrien  out_byte (0);
144077298Sobrien
144177298Sobrien  /* Align the header.  */
144277298Sobrien  if (skip)
144377298Sobrien    frag_align (ffs (2 * addr_size) - 1, 0, 0);
144477298Sobrien
144577298Sobrien  for (s = all_segs; s; s = s->next)
144660484Sobrien    {
144777298Sobrien      fragS *frag;
144877298Sobrien      symbolS *beg, *end;
144960484Sobrien
145077298Sobrien      frag = first_frag_for_seg (s->seg);
1451130561Sobrien      beg = symbol_temp_new (s->seg, 0, frag);
145277298Sobrien      s->text_start = beg;
145360484Sobrien
145477298Sobrien      frag = last_frag_for_seg (s->seg);
1455218822Sdim      end = symbol_temp_new (s->seg, get_frag_fix (frag, s->seg), frag);
145677298Sobrien      s->text_end = end;
145760484Sobrien
145877298Sobrien      expr.X_op = O_symbol;
145977298Sobrien      expr.X_add_symbol = beg;
146077298Sobrien      expr.X_add_number = 0;
146177298Sobrien      emit_expr (&expr, addr_size);
146277298Sobrien
146377298Sobrien      expr.X_op = O_subtract;
146477298Sobrien      expr.X_add_symbol = end;
146577298Sobrien      expr.X_op_symbol = beg;
146677298Sobrien      expr.X_add_number = 0;
146777298Sobrien      emit_expr (&expr, addr_size);
146860484Sobrien    }
146960484Sobrien
147077298Sobrien  p = frag_more (2 * addr_size);
147177298Sobrien  md_number_to_chars (p, 0, addr_size);
147277298Sobrien  md_number_to_chars (p + addr_size, 0, addr_size);
147377298Sobrien}
147460484Sobrien
147577298Sobrien/* Emit data for .debug_abbrev.  Note that this must be kept in
147677298Sobrien   sync with out_debug_info below.  */
147760484Sobrien
147877298Sobrienstatic void
1479130561Sobrienout_debug_abbrev (segT abbrev_seg)
148077298Sobrien{
148177298Sobrien  subseg_set (abbrev_seg, 0);
148277298Sobrien
148377298Sobrien  out_uleb128 (1);
148477298Sobrien  out_uleb128 (DW_TAG_compile_unit);
148577298Sobrien  out_byte (DW_CHILDREN_no);
148677298Sobrien  out_abbrev (DW_AT_stmt_list, DW_FORM_data4);
148777298Sobrien  if (all_segs->next == NULL)
148860484Sobrien    {
148977298Sobrien      out_abbrev (DW_AT_low_pc, DW_FORM_addr);
149077298Sobrien      out_abbrev (DW_AT_high_pc, DW_FORM_addr);
149160484Sobrien    }
1492218822Sdim  else
1493218822Sdim    {
1494218822Sdim      if (DWARF2_FORMAT () == dwarf2_format_32bit)
1495218822Sdim	out_abbrev (DW_AT_ranges, DW_FORM_data4);
1496218822Sdim      else
1497218822Sdim	out_abbrev (DW_AT_ranges, DW_FORM_data8);
1498218822Sdim    }
1499104834Sobrien  out_abbrev (DW_AT_name, DW_FORM_string);
150077298Sobrien  out_abbrev (DW_AT_comp_dir, DW_FORM_string);
150177298Sobrien  out_abbrev (DW_AT_producer, DW_FORM_string);
150277298Sobrien  out_abbrev (DW_AT_language, DW_FORM_data2);
150377298Sobrien  out_abbrev (0, 0);
150477298Sobrien
150577298Sobrien  /* Terminate the abbreviations for this compilation unit.  */
150677298Sobrien  out_byte (0);
150760484Sobrien}
150860484Sobrien
150977298Sobrien/* Emit a description of this compilation unit for .debug_info.  */
151077298Sobrien
151177298Sobrienstatic void
1512218822Sdimout_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg)
151360484Sobrien{
151477298Sobrien  char producer[128];
151577298Sobrien  char *comp_dir;
151677298Sobrien  expressionS expr;
151777298Sobrien  symbolS *info_start;
151877298Sobrien  symbolS *info_end;
151977298Sobrien  char *p;
152077298Sobrien  int len;
1521130561Sobrien  enum dwarf2_format d2f;
1522130561Sobrien  int sizeof_offset;
152360484Sobrien
152477298Sobrien  subseg_set (info_seg, 0);
152560484Sobrien
1526130561Sobrien  info_start = symbol_temp_new_now ();
1527130561Sobrien  info_end = symbol_temp_make ();
152860484Sobrien
152977298Sobrien  /* Compilation Unit length.  */
153077298Sobrien  expr.X_op = O_subtract;
153177298Sobrien  expr.X_add_symbol = info_end;
153277298Sobrien  expr.X_op_symbol = info_start;
153360484Sobrien
1534130561Sobrien  d2f = DWARF2_FORMAT ();
1535130561Sobrien  if (d2f == dwarf2_format_32bit)
1536130561Sobrien    {
1537130561Sobrien      expr.X_add_number = -4;
1538130561Sobrien      emit_expr (&expr, 4);
1539130561Sobrien      sizeof_offset = 4;
1540130561Sobrien    }
1541130561Sobrien  else if (d2f == dwarf2_format_64bit)
1542130561Sobrien    {
1543130561Sobrien      expr.X_add_number = -12;
1544130561Sobrien      out_four (-1);
1545130561Sobrien      emit_expr (&expr, 8);
1546130561Sobrien      sizeof_offset = 8;
1547130561Sobrien    }
1548130561Sobrien  else if (d2f == dwarf2_format_64bit_irix)
1549130561Sobrien    {
1550130561Sobrien      expr.X_add_number = -8;
1551130561Sobrien      emit_expr (&expr, 8);
1552130561Sobrien      sizeof_offset = 8;
1553130561Sobrien    }
1554130561Sobrien  else
1555130561Sobrien    {
1556130561Sobrien      as_fatal (_("internal error: unknown dwarf2 format"));
1557130561Sobrien    }
1558130561Sobrien
155977298Sobrien  /* DWARF version.  */
156077298Sobrien  out_two (2);
156160484Sobrien
156277298Sobrien  /* .debug_abbrev offset */
1563130561Sobrien  TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset);
156460484Sobrien
156577298Sobrien  /* Target address size.  */
156677298Sobrien  out_byte (sizeof_address);
156760484Sobrien
156877298Sobrien  /* DW_TAG_compile_unit DIE abbrev */
156977298Sobrien  out_uleb128 (1);
157060484Sobrien
157177298Sobrien  /* DW_AT_stmt_list */
1572130561Sobrien  /* ??? sizeof_offset */
1573130561Sobrien  TC_DWARF2_EMIT_OFFSET (section_symbol (line_seg), 4);
157460484Sobrien
1575218822Sdim  /* These two attributes are emitted if all of the code is contiguous.  */
157677298Sobrien  if (all_segs->next == NULL)
157777298Sobrien    {
157877298Sobrien      /* DW_AT_low_pc */
157977298Sobrien      expr.X_op = O_symbol;
158077298Sobrien      expr.X_add_symbol = all_segs->text_start;
158177298Sobrien      expr.X_add_number = 0;
158277298Sobrien      emit_expr (&expr, sizeof_address);
158360484Sobrien
158477298Sobrien      /* DW_AT_high_pc */
158577298Sobrien      expr.X_op = O_symbol;
158677298Sobrien      expr.X_add_symbol = all_segs->text_end;
158777298Sobrien      expr.X_add_number = 0;
158877298Sobrien      emit_expr (&expr, sizeof_address);
158977298Sobrien    }
1590218822Sdim  else
1591218822Sdim    {
1592218822Sdim      /* This attribute is emitted if the code is disjoint.  */
1593218822Sdim      /* DW_AT_ranges.  */
1594218822Sdim      TC_DWARF2_EMIT_OFFSET (section_symbol (ranges_seg), sizeof_offset);
1595218822Sdim    }
159660484Sobrien
1597104834Sobrien  /* DW_AT_name.  We don't have the actual file name that was present
1598104834Sobrien     on the command line, so assume files[1] is the main input file.
1599104834Sobrien     We're not supposed to get called unless at least one line number
1600104834Sobrien     entry was emitted, so this should always be defined.  */
1601104834Sobrien  if (!files || files_in_use < 1)
1602104834Sobrien    abort ();
1603130561Sobrien  if (files[1].dir)
1604130561Sobrien    {
1605130561Sobrien      len = strlen (dirs[files[1].dir]);
1606130561Sobrien      p = frag_more (len + 1);
1607130561Sobrien      memcpy (p, dirs[files[1].dir], len);
1608218822Sdim      INSERT_DIR_SEPARATOR (p, len);
1609130561Sobrien    }
1610104834Sobrien  len = strlen (files[1].filename) + 1;
1611104834Sobrien  p = frag_more (len);
1612104834Sobrien  memcpy (p, files[1].filename, len);
1613104834Sobrien
161477298Sobrien  /* DW_AT_comp_dir */
161577298Sobrien  comp_dir = getpwd ();
161677298Sobrien  len = strlen (comp_dir) + 1;
161777298Sobrien  p = frag_more (len);
161877298Sobrien  memcpy (p, comp_dir, len);
161977298Sobrien
162077298Sobrien  /* DW_AT_producer */
162177298Sobrien  sprintf (producer, "GNU AS %s", VERSION);
162277298Sobrien  len = strlen (producer) + 1;
162377298Sobrien  p = frag_more (len);
162477298Sobrien  memcpy (p, producer, len);
162577298Sobrien
162677298Sobrien  /* DW_AT_language.  Yes, this is probably not really MIPS, but the
162777298Sobrien     dwarf2 draft has no standard code for assembler.  */
162877298Sobrien  out_two (DW_LANG_Mips_Assembler);
162977298Sobrien
1630130561Sobrien  symbol_set_value_now (info_end);
163160484Sobrien}
163260484Sobrien
1633218822Sdim/* Finish the dwarf2 debug sections.  We emit .debug.line if there
1634218822Sdim   were any .file/.loc directives, or --gdwarf2 was given, or if the
1635218822Sdim   file has a non-empty .debug_info section.  If we emit .debug_line,
1636218822Sdim   and the .debug_info section is empty, we also emit .debug_info,
1637218822Sdim   .debug_aranges and .debug_abbrev.  ALL_SEGS will be non-null if
1638218822Sdim   there were any .file/.loc directives, or --gdwarf2 was given and
1639218822Sdim   there were any located instructions emitted.  */
1640218822Sdim
164160484Sobrienvoid
1642130561Sobriendwarf2_finish (void)
164360484Sobrien{
164477298Sobrien  segT line_seg;
164577298Sobrien  struct line_seg *s;
1646218822Sdim  segT info_seg;
1647218822Sdim  int emit_other_sections = 0;
164860484Sobrien
1649218822Sdim  info_seg = bfd_get_section_by_name (stdoutput, ".debug_info");
1650218822Sdim  emit_other_sections = info_seg == NULL || !seg_not_empty_p (info_seg);
1651218822Sdim
1652218822Sdim  if (!all_segs && emit_other_sections)
1653218822Sdim    /* There is no line information and no non-empty .debug_info
1654218822Sdim       section.  */
165577298Sobrien    return;
165677298Sobrien
165777298Sobrien  /* Calculate the size of an address for the target machine.  */
1658130561Sobrien  sizeof_address = DWARF2_ADDR_SIZE (stdoutput);
165977298Sobrien
166077298Sobrien  /* Create and switch to the line number section.  */
166177298Sobrien  line_seg = subseg_new (".debug_line", 0);
1662218822Sdim  bfd_set_section_flags (stdoutput, line_seg, SEC_READONLY | SEC_DEBUGGING);
166377298Sobrien
166477298Sobrien  /* For each subsection, chain the debug entries together.  */
166577298Sobrien  for (s = all_segs; s; s = s->next)
166660484Sobrien    {
166777298Sobrien      struct line_subseg *ss = s->head;
166877298Sobrien      struct line_entry **ptail = ss->ptail;
166977298Sobrien
167077298Sobrien      while ((ss = ss->next) != NULL)
167177298Sobrien	{
167277298Sobrien	  *ptail = ss->head;
167377298Sobrien	  ptail = ss->ptail;
167477298Sobrien	}
167560484Sobrien    }
167660484Sobrien
167777298Sobrien  out_debug_line (line_seg);
167860484Sobrien
1679218822Sdim  /* If this is assembler generated line info, and there is no
1680218822Sdim     debug_info already, we need .debug_info and .debug_abbrev
1681218822Sdim     sections as well.  */
1682218822Sdim  if (emit_other_sections)
168377298Sobrien    {
168477298Sobrien      segT abbrev_seg;
168577298Sobrien      segT aranges_seg;
1686218822Sdim      segT ranges_seg;
168760484Sobrien
1688218822Sdim      assert (all_segs);
1689218822Sdim
169077298Sobrien      info_seg = subseg_new (".debug_info", 0);
169177298Sobrien      abbrev_seg = subseg_new (".debug_abbrev", 0);
169277298Sobrien      aranges_seg = subseg_new (".debug_aranges", 0);
169360484Sobrien
1694218822Sdim      bfd_set_section_flags (stdoutput, info_seg,
1695218822Sdim			     SEC_READONLY | SEC_DEBUGGING);
1696218822Sdim      bfd_set_section_flags (stdoutput, abbrev_seg,
1697218822Sdim			     SEC_READONLY | SEC_DEBUGGING);
1698218822Sdim      bfd_set_section_flags (stdoutput, aranges_seg,
1699218822Sdim			     SEC_READONLY | SEC_DEBUGGING);
170077298Sobrien
170177298Sobrien      record_alignment (aranges_seg, ffs (2 * sizeof_address) - 1);
170277298Sobrien
1703218822Sdim      if (all_segs->next == NULL)
1704218822Sdim	ranges_seg = NULL;
1705218822Sdim      else
1706218822Sdim	{
1707218822Sdim	  ranges_seg = subseg_new (".debug_ranges", 0);
1708218822Sdim	  bfd_set_section_flags (stdoutput, ranges_seg,
1709218822Sdim				 SEC_READONLY | SEC_DEBUGGING);
1710218822Sdim	  record_alignment (ranges_seg, ffs (2 * sizeof_address) - 1);
1711218822Sdim	  out_debug_ranges (ranges_seg);
1712218822Sdim	}
1713218822Sdim
171477298Sobrien      out_debug_aranges (aranges_seg, info_seg);
171577298Sobrien      out_debug_abbrev (abbrev_seg);
1716218822Sdim      out_debug_info (info_seg, abbrev_seg, line_seg, ranges_seg);
171777298Sobrien    }
171860484Sobrien}
1719