dwarf2dbg.c revision 77298
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" 3177298Sobrien#include "as.h" 3260484Sobrien 3377298Sobrien#ifdef HAVE_LIMITS_H 3477298Sobrien#include <limits.h> 3577298Sobrien#else 3677298Sobrien#ifdef HAVE_SYS_PARAM_H 3777298Sobrien#include <sys/param.h> 3877298Sobrien#endif 3977298Sobrien#ifndef INT_MAX 4077298Sobrien#define INT_MAX (int) (((unsigned) (-1)) >> 1) 4177298Sobrien#endif 4277298Sobrien#endif 4377298Sobrien 4477298Sobrien#ifdef BFD_ASSEMBLER 4577298Sobrien 4660484Sobrien#include "dwarf2dbg.h" 4760484Sobrien#include "subsegs.h" 4860484Sobrien 4960484Sobrien#include "elf/dwarf2.h" 5060484Sobrien 5160484Sobrien/* Since we can't generate the prolog until the body is complete, we 5260484Sobrien use three different subsegments for .debug_line: one holding the 5360484Sobrien prolog, one for the directory and filename info, and one for the 5460484Sobrien body ("statement program"). */ 5560484Sobrien#define DL_PROLOG 0 5660484Sobrien#define DL_FILES 1 5760484Sobrien#define DL_BODY 2 5860484Sobrien 5960484Sobrien/* First special line opcde - leave room for the standard opcodes. 6060484Sobrien Note: If you want to change this, you'll have to update the 6160484Sobrien "standard_opcode_lengths" table that is emitted below in 6260484Sobrien dwarf2_finish(). */ 6360484Sobrien#define DWARF2_LINE_OPCODE_BASE 10 6460484Sobrien 6560484Sobrien#ifndef DWARF2_LINE_BASE 6660484Sobrien /* Minimum line offset in a special line info. opcode. This value 6760484Sobrien was chosen to give a reasonable range of values. */ 6860484Sobrien# define DWARF2_LINE_BASE -5 6960484Sobrien#endif 7060484Sobrien 7160484Sobrien/* Range of line offsets in a special line info. opcode. */ 7260484Sobrien#ifndef DWARF2_LINE_RANGE 7360484Sobrien# define DWARF2_LINE_RANGE 14 7460484Sobrien#endif 7560484Sobrien 7660484Sobrien#ifndef DWARF2_LINE_MIN_INSN_LENGTH 7760484Sobrien /* Define the architecture-dependent minimum instruction length (in 7860484Sobrien bytes). This value should be rather too small than too big. */ 7977298Sobrien# define DWARF2_LINE_MIN_INSN_LENGTH 1 8060484Sobrien#endif 8160484Sobrien 8260484Sobrien/* Flag that indicates the initial value of the is_stmt_start flag. 8360484Sobrien In the present implementation, we do not mark any lines as 8460484Sobrien the beginning of a source statement, because that information 8560484Sobrien is not made available by the GCC front-end. */ 8660484Sobrien#define DWARF2_LINE_DEFAULT_IS_STMT 1 8760484Sobrien 8860484Sobrien/* Given a special op, return the line skip amount. */ 8960484Sobrien#define SPECIAL_LINE(op) \ 9060484Sobrien (((op) - DWARF2_LINE_OPCODE_BASE)%DWARF2_LINE_RANGE + DWARF2_LINE_BASE) 9160484Sobrien 9260484Sobrien/* Given a special op, return the address skip amount (in units of 9360484Sobrien DWARF2_LINE_MIN_INSN_LENGTH. */ 9460484Sobrien#define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE) 9560484Sobrien 9660484Sobrien/* The maximum address skip amount that can be encoded with a special op. */ 9760484Sobrien#define MAX_SPECIAL_ADDR_DELTA SPECIAL_ADDR(255) 9860484Sobrien 9977298Sobrienstruct line_entry { 10077298Sobrien struct line_entry *next; 10177298Sobrien fragS *frag; 10277298Sobrien addressT frag_ofs; 10377298Sobrien struct dwarf2_line_info loc; 10477298Sobrien}; 10560484Sobrien 10677298Sobrienstruct line_subseg { 10777298Sobrien struct line_subseg *next; 10877298Sobrien subsegT subseg; 10977298Sobrien struct line_entry *head; 11077298Sobrien struct line_entry **ptail; 11177298Sobrien}; 11260484Sobrien 11377298Sobrienstruct line_seg { 11477298Sobrien struct line_seg *next; 11577298Sobrien segT seg; 11677298Sobrien struct line_subseg *head; 11777298Sobrien symbolS *text_start; 11877298Sobrien symbolS *text_end; 11977298Sobrien}; 12060484Sobrien 12177298Sobrien/* Collects data for all line table entries during assembly. */ 12277298Sobrienstatic struct line_seg *all_segs; 12360484Sobrien 12477298Sobrienstruct file_entry { 12577298Sobrien char *filename; 12677298Sobrien unsigned int dir; 12777298Sobrien}; 12860484Sobrien 12977298Sobrien/* Table of files used by .debug_line. */ 13077298Sobrienstatic struct file_entry *files; 13177298Sobrienstatic unsigned int files_in_use; 13277298Sobrienstatic unsigned int files_allocated; 13377298Sobrien 13477298Sobrien/* True when we've seen a .loc directive recently. Used to avoid 13577298Sobrien doing work when there's nothing to do. */ 13677298Sobrienstatic boolean loc_directive_seen; 13777298Sobrien 13877298Sobrien/* Current location as indicated by the most recent .loc directive. */ 13977298Sobrienstatic struct dwarf2_line_info current; 14077298Sobrien 14177298Sobrien/* Fake label name. */ 14277298Sobrienstatic char const fake_label_name[] = ".L0\001"; 14377298Sobrien 14477298Sobrien/* The size of an address on the target. */ 14577298Sobrienstatic unsigned int sizeof_address; 14677298Sobrien 14777298Sobrienstatic struct line_subseg *get_line_subseg PARAMS ((segT, subsegT)); 14877298Sobrienstatic unsigned int get_filenum PARAMS ((const char *)); 14977298Sobrienstatic struct frag *first_frag_for_seg PARAMS ((segT)); 15077298Sobrienstatic struct frag *last_frag_for_seg PARAMS ((segT)); 15177298Sobrienstatic void out_byte PARAMS ((int)); 15277298Sobrienstatic void out_opcode PARAMS ((int)); 15377298Sobrienstatic void out_two PARAMS ((int)); 15477298Sobrienstatic void out_four PARAMS ((int)); 15577298Sobrienstatic void out_abbrev PARAMS ((int, int)); 15677298Sobrienstatic void out_uleb128 PARAMS ((addressT)); 15777298Sobrienstatic symbolS *symbol_new_now PARAMS ((void)); 15877298Sobrienstatic void set_symbol_value_now PARAMS ((symbolS *)); 15977298Sobrienstatic offsetT get_frag_fix PARAMS ((fragS *)); 16077298Sobrienstatic void out_set_addr PARAMS ((segT, fragS *, addressT)); 16177298Sobrienstatic int size_inc_line_addr PARAMS ((int, addressT)); 16277298Sobrienstatic void emit_inc_line_addr PARAMS ((int, addressT, char *, int)); 16377298Sobrienstatic void out_inc_line_addr PARAMS ((int, addressT)); 16477298Sobrienstatic void relax_inc_line_addr PARAMS ((int, segT, fragS *, addressT, 16577298Sobrien fragS *, addressT)); 16677298Sobrienstatic void process_entries PARAMS ((segT, struct line_entry *)); 16777298Sobrienstatic void out_file_list PARAMS ((void)); 16877298Sobrienstatic void out_debug_line PARAMS ((segT)); 16977298Sobrienstatic void out_debug_aranges PARAMS ((segT, segT)); 17077298Sobrienstatic void out_debug_abbrev PARAMS ((segT)); 17177298Sobrienstatic void out_debug_info PARAMS ((segT, segT, segT)); 17277298Sobrien 17377298Sobrien/* Find or create an entry for SEG+SUBSEG in ALL_SEGS. */ 17477298Sobrien 17577298Sobrienstatic struct line_subseg * 17677298Sobrienget_line_subseg (seg, subseg) 17777298Sobrien segT seg; 17877298Sobrien subsegT subseg; 17977298Sobrien{ 18077298Sobrien static segT last_seg; 18177298Sobrien static subsegT last_subseg; 18277298Sobrien static struct line_subseg *last_line_subseg; 18377298Sobrien 18477298Sobrien struct line_seg *s; 18577298Sobrien struct line_subseg **pss, *ss; 18677298Sobrien 18777298Sobrien if (seg == last_seg && subseg == last_subseg) 18877298Sobrien return last_line_subseg; 18977298Sobrien 19077298Sobrien for (s = all_segs; s; s = s->next) 19177298Sobrien if (s->seg == seg) 19277298Sobrien goto found_seg; 19377298Sobrien 19477298Sobrien s = (struct line_seg *) xmalloc (sizeof (*s)); 19577298Sobrien s->next = all_segs; 19677298Sobrien s->seg = seg; 19777298Sobrien s->head = NULL; 19877298Sobrien all_segs = s; 19977298Sobrien 20077298Sobrien found_seg: 20177298Sobrien for (pss = &s->head; (ss = *pss) != NULL ; pss = &ss->next) 20260484Sobrien { 20377298Sobrien if (ss->subseg == subseg) 20477298Sobrien goto found_subseg; 20577298Sobrien if (ss->subseg > subseg) 20677298Sobrien break; 20760484Sobrien } 20860484Sobrien 20977298Sobrien ss = (struct line_subseg *) xmalloc (sizeof (*ss)); 21077298Sobrien ss->next = *pss; 21177298Sobrien ss->subseg = subseg; 21277298Sobrien ss->head = NULL; 21377298Sobrien ss->ptail = &ss->head; 21477298Sobrien *pss = ss; 21560484Sobrien 21677298Sobrien found_subseg: 21777298Sobrien last_seg = seg; 21877298Sobrien last_subseg = subseg; 21977298Sobrien last_line_subseg = ss; 22060484Sobrien 22177298Sobrien return ss; 22277298Sobrien} 22360484Sobrien 22477298Sobrien/* Record an entry for LOC ocurring at OFS within the current fragment. */ 22560484Sobrien 22677298Sobrienvoid 22777298Sobriendwarf2_gen_line_info (ofs, loc) 22877298Sobrien addressT ofs; 22977298Sobrien struct dwarf2_line_info *loc; 23060484Sobrien{ 23177298Sobrien struct line_subseg *ss; 23277298Sobrien struct line_entry *e; 23360484Sobrien 23477298Sobrien /* Early out for as-yet incomplete location information. */ 23577298Sobrien if (loc->filenum == 0 || loc->line == 0) 23677298Sobrien return; 23777298Sobrien 23877298Sobrien e = (struct line_entry *) xmalloc (sizeof (*e)); 23977298Sobrien e->next = NULL; 24077298Sobrien e->frag = frag_now; 24177298Sobrien e->frag_ofs = ofs; 24277298Sobrien e->loc = *loc; 24377298Sobrien 24477298Sobrien ss = get_line_subseg (now_seg, now_subseg); 24577298Sobrien *ss->ptail = e; 24677298Sobrien ss->ptail = &e->next; 24777298Sobrien} 24877298Sobrien 24977298Sobrienvoid 25077298Sobriendwarf2_where (line) 25177298Sobrien struct dwarf2_line_info *line; 25277298Sobrien{ 25377298Sobrien if (debug_type == DEBUG_DWARF2) 25460484Sobrien { 25577298Sobrien char *filename; 25677298Sobrien as_where (&filename, &line->line); 25777298Sobrien line->filenum = get_filenum (filename); 25877298Sobrien line->column = 0; 25977298Sobrien line->flags = DWARF2_FLAG_BEGIN_STMT; 26060484Sobrien } 26177298Sobrien else 26277298Sobrien *line = current; 26360484Sobrien} 26460484Sobrien 26577298Sobrien/* Called for each machine instruction, or relatively atomic group of 26677298Sobrien machine instructions (ie built-in macro). The instruction or group 26777298Sobrien is SIZE bytes in length. If dwarf2 line number generation is called 26877298Sobrien for, emit a line statement appropriately. */ 26977298Sobrien 27077298Sobrienvoid 27177298Sobriendwarf2_emit_insn (size) 27277298Sobrien int size; 27360484Sobrien{ 27477298Sobrien struct dwarf2_line_info loc; 27560484Sobrien 27677298Sobrien if (debug_type != DEBUG_DWARF2 && ! loc_directive_seen) 27777298Sobrien return; 27877298Sobrien loc_directive_seen = false; 27977298Sobrien 28077298Sobrien dwarf2_where (&loc); 28177298Sobrien dwarf2_gen_line_info (frag_now_fix () - size, &loc); 28277298Sobrien} 28377298Sobrien 28477298Sobrien/* Get a .debug_line file number for FILENAME. */ 28577298Sobrien 28677298Sobrienstatic unsigned int 28777298Sobrienget_filenum (filename) 28877298Sobrien const char *filename; 28977298Sobrien{ 29077298Sobrien static unsigned int last_used; 29177298Sobrien unsigned int i; 29277298Sobrien 29377298Sobrien if (last_used) 29477298Sobrien if (strcmp (filename, files[last_used].filename) == 0) 29577298Sobrien return last_used; 29677298Sobrien 29777298Sobrien for (i = 1; i < files_in_use; ++i) 29877298Sobrien if (strcmp (filename, files[i].filename) == 0) 29977298Sobrien return i; 30077298Sobrien 30177298Sobrien if (i >= files_allocated) 30260484Sobrien { 30377298Sobrien unsigned int old = files_allocated; 30477298Sobrien 30577298Sobrien files_allocated = i + 32; 30677298Sobrien files = (struct file_entry *) 30777298Sobrien xrealloc (files, (i + 32) * sizeof (struct file_entry)); 30877298Sobrien 30977298Sobrien memset (files + old, 0, (i + 32 - old) * sizeof (struct file_entry)); 31060484Sobrien } 31177298Sobrien 31277298Sobrien files[i].filename = xstrdup (filename); 31377298Sobrien files[i].dir = 0; 31477298Sobrien files_in_use = i + 1; 31577298Sobrien last_used = i; 31677298Sobrien 31777298Sobrien return i; 31860484Sobrien} 31960484Sobrien 32077298Sobrien/* Handle the .file directive. */ 32177298Sobrien 32277298Sobrienvoid 32377298Sobriendwarf2_directive_file (dummy) 32477298Sobrien int dummy ATTRIBUTE_UNUSED; 32560484Sobrien{ 32677298Sobrien offsetT num; 32777298Sobrien const char *filename; 32877298Sobrien int filename_len; 32960484Sobrien 33077298Sobrien /* Continue to accept a bare string and pass it off. */ 33177298Sobrien SKIP_WHITESPACE (); 33277298Sobrien if (*input_line_pointer == '"') 33360484Sobrien { 33477298Sobrien s_app_file (0); 33577298Sobrien return; 33660484Sobrien } 33760484Sobrien 33877298Sobrien num = get_absolute_expression (); 33977298Sobrien filename = demand_copy_C_string (&filename_len); 34077298Sobrien demand_empty_rest_of_line (); 34160484Sobrien 34277298Sobrien if (num < 1) 34360484Sobrien { 34477298Sobrien as_bad (_("File number less than one")); 34560484Sobrien return; 34660484Sobrien } 34760484Sobrien 34877298Sobrien if (num < files_in_use && files[num].filename != 0) 34960484Sobrien { 35077298Sobrien as_bad (_("File number %d already allocated"), num); 35160484Sobrien return; 35260484Sobrien } 35360484Sobrien 35477298Sobrien if (num >= (int) files_allocated) 35577298Sobrien { 35677298Sobrien unsigned int old = files_allocated; 35760484Sobrien 35877298Sobrien files_allocated = num + 16; 35977298Sobrien files = (struct file_entry *) 36077298Sobrien xrealloc (files, (num + 16) * sizeof (struct file_entry)); 36177298Sobrien 36277298Sobrien /* Zero the new memory. */ 36377298Sobrien memset (files + old, 0, (num + 16 - old) * sizeof (struct file_entry)); 36477298Sobrien } 36577298Sobrien 36677298Sobrien files[num].filename = filename; 36777298Sobrien files[num].dir = 0; 36877298Sobrien files_in_use = num + 1; 36960484Sobrien} 37060484Sobrien 37177298Sobrienvoid 37277298Sobriendwarf2_directive_loc (dummy) 37377298Sobrien int dummy ATTRIBUTE_UNUSED; 37477298Sobrien{ 37577298Sobrien offsetT filenum, line, column; 37677298Sobrien 37777298Sobrien filenum = get_absolute_expression (); 37877298Sobrien SKIP_WHITESPACE (); 37977298Sobrien line = get_absolute_expression (); 38077298Sobrien SKIP_WHITESPACE (); 38177298Sobrien column = get_absolute_expression (); 38277298Sobrien demand_empty_rest_of_line (); 38377298Sobrien 38477298Sobrien if (filenum < 1) 38577298Sobrien { 38677298Sobrien as_bad (_("File number less than one")); 38777298Sobrien return; 38877298Sobrien } 38977298Sobrien if (filenum >= (int) files_in_use || files[filenum].filename == 0) 39077298Sobrien { 39177298Sobrien as_bad (_("Unassigned file number %ld"), (long) filenum); 39277298Sobrien return; 39377298Sobrien } 39477298Sobrien 39577298Sobrien current.filenum = filenum; 39677298Sobrien current.line = line; 39777298Sobrien current.column = column; 39877298Sobrien current.flags = DWARF2_FLAG_BEGIN_STMT; 39977298Sobrien 40077298Sobrien loc_directive_seen = true; 40177298Sobrien 40277298Sobrien#ifndef NO_LISTING 40377298Sobrien if (listing) 40477298Sobrien listing_source_line (line); 40577298Sobrien#endif 40677298Sobrien} 40777298Sobrien 40877298Sobrienstatic struct frag * 40977298Sobrienfirst_frag_for_seg (seg) 41077298Sobrien segT seg; 41177298Sobrien{ 41277298Sobrien frchainS *f, *first = NULL; 41377298Sobrien 41477298Sobrien for (f = frchain_root; f; f = f->frch_next) 41577298Sobrien if (f->frch_seg == seg 41677298Sobrien && (! first || first->frch_subseg > f->frch_subseg)) 41777298Sobrien first = f; 41877298Sobrien 41977298Sobrien return first ? first->frch_root : NULL; 42077298Sobrien} 42177298Sobrien 42277298Sobrienstatic struct frag * 42377298Sobrienlast_frag_for_seg (seg) 42477298Sobrien segT seg; 42577298Sobrien{ 42677298Sobrien frchainS *f, *last = NULL; 42777298Sobrien 42877298Sobrien for (f = frchain_root; f; f = f->frch_next) 42977298Sobrien if (f->frch_seg == seg 43077298Sobrien && (! last || last->frch_subseg < f->frch_subseg)) 43177298Sobrien last= f; 43277298Sobrien 43377298Sobrien return last ? last->frch_last : NULL; 43477298Sobrien} 43577298Sobrien 43677298Sobrien/* Emit a single byte into the current segment. */ 43777298Sobrien 43877298Sobrienstatic inline void 43977298Sobrienout_byte (byte) 44077298Sobrien int byte; 44177298Sobrien{ 44277298Sobrien FRAG_APPEND_1_CHAR (byte); 44377298Sobrien} 44477298Sobrien 44577298Sobrien/* Emit a statement program opcode into the current segment. */ 44677298Sobrien 44777298Sobrienstatic inline void 44877298Sobrienout_opcode (opc) 44977298Sobrien int opc; 45077298Sobrien{ 45177298Sobrien out_byte (opc); 45277298Sobrien} 45377298Sobrien 45477298Sobrien/* Emit a two-byte word into the current segment. */ 45577298Sobrien 45677298Sobrienstatic inline void 45777298Sobrienout_two (data) 45877298Sobrien int data; 45977298Sobrien{ 46077298Sobrien md_number_to_chars (frag_more (2), data, 2); 46177298Sobrien} 46277298Sobrien 46377298Sobrien/* Emit a four byte word into the current segment. */ 46477298Sobrien 46577298Sobrienstatic inline void 46677298Sobrienout_four (data) 46777298Sobrien int data; 46877298Sobrien{ 46977298Sobrien md_number_to_chars (frag_more (4), data, 4); 47077298Sobrien} 47177298Sobrien 47277298Sobrien/* Emit an unsigned "little-endian base 128" number. */ 47377298Sobrien 47460484Sobrienstatic void 47577298Sobrienout_uleb128 (value) 47677298Sobrien addressT value; 47760484Sobrien{ 47877298Sobrien output_leb128 (frag_more (sizeof_leb128 (value, 0)), value, 0); 47977298Sobrien} 48060484Sobrien 48177298Sobrien/* Emit a tuple for .debug_abbrev. */ 48277298Sobrien 48377298Sobrienstatic inline void 48477298Sobrienout_abbrev (name, form) 48577298Sobrien int name, form; 48677298Sobrien{ 48777298Sobrien out_uleb128 (name); 48877298Sobrien out_uleb128 (form); 48960484Sobrien} 49060484Sobrien 49177298Sobrien/* Create a new fake symbol whose value is the current position. */ 49277298Sobrien 49377298Sobrienstatic symbolS * 49477298Sobriensymbol_new_now () 49577298Sobrien{ 49677298Sobrien return symbol_new (fake_label_name, now_seg, frag_now_fix (), frag_now); 49777298Sobrien} 49877298Sobrien 49977298Sobrien/* Set the value of SYM to the current position in the current segment. */ 50077298Sobrien 50160484Sobrienstatic void 50277298Sobrienset_symbol_value_now (sym) 50377298Sobrien symbolS *sym; 50460484Sobrien{ 50577298Sobrien S_SET_SEGMENT (sym, now_seg); 50677298Sobrien S_SET_VALUE (sym, frag_now_fix ()); 50777298Sobrien symbol_set_frag (sym, frag_now); 50877298Sobrien} 50960484Sobrien 51077298Sobrien/* Get the size of a fragment. */ 51160484Sobrien 51277298Sobrienstatic offsetT 51377298Sobrienget_frag_fix (frag) 51477298Sobrien fragS *frag; 51577298Sobrien{ 51677298Sobrien frchainS *fr; 51760484Sobrien 51877298Sobrien if (frag->fr_next) 51977298Sobrien return frag->fr_fix; 52060484Sobrien 52177298Sobrien /* If a fragment is the last in the chain, special measures must be 52277298Sobrien taken to find its size before relaxation, since it may be pending 52377298Sobrien on some subsegment chain. */ 52477298Sobrien for (fr = frchain_root; fr; fr = fr->frch_next) 52577298Sobrien if (fr->frch_last == frag) 52677298Sobrien { 52777298Sobrien return ((char *) obstack_next_free (&fr->frch_obstack) 52877298Sobrien - frag->fr_literal); 52977298Sobrien } 53060484Sobrien 53177298Sobrien abort (); 53277298Sobrien} 53377298Sobrien 53477298Sobrien/* Set an absolute address (may result in a relocation entry). */ 53577298Sobrien 53677298Sobrienstatic void 53777298Sobrienout_set_addr (seg, frag, ofs) 53877298Sobrien segT seg; 53977298Sobrien fragS *frag; 54077298Sobrien addressT ofs; 54177298Sobrien{ 54277298Sobrien expressionS expr; 54377298Sobrien symbolS *sym; 54477298Sobrien 54577298Sobrien sym = symbol_new (fake_label_name, seg, ofs, frag); 54677298Sobrien 54760484Sobrien out_opcode (DW_LNS_extended_op); 54877298Sobrien out_uleb128 (sizeof_address + 1); 54960484Sobrien 55060484Sobrien out_opcode (DW_LNE_set_address); 55160484Sobrien expr.X_op = O_symbol; 55260484Sobrien expr.X_add_symbol = sym; 55360484Sobrien expr.X_add_number = 0; 55477298Sobrien emit_expr (&expr, sizeof_address); 55560484Sobrien} 55660484Sobrien 55777298Sobrien/* Encode a pair of line and address skips as efficiently as possible. 55877298Sobrien Note that the line skip is signed, whereas the address skip is unsigned. 55977298Sobrien 56077298Sobrien The following two routines *must* be kept in sync. This is 56177298Sobrien enforced by making emit_inc_line_addr abort if we do not emit 56277298Sobrien exactly the expected number of bytes. */ 56377298Sobrien 56477298Sobrienstatic int 56577298Sobriensize_inc_line_addr (line_delta, addr_delta) 56677298Sobrien int line_delta; 56777298Sobrien addressT addr_delta; 56860484Sobrien{ 56977298Sobrien unsigned int tmp, opcode; 57077298Sobrien int len = 0; 57160484Sobrien 57277298Sobrien /* Scale the address delta by the minimum instruction length. */ 57377298Sobrien#if DWARF2_LINE_MIN_INSN_LENGTH > 1 57477298Sobrien assert (addr_delta % DWARF2_LINE_MIN_INSN_LENGTH == 0); 57577298Sobrien addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH; 57677298Sobrien#endif 57777298Sobrien 57877298Sobrien /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence. 57977298Sobrien We cannot use special opcodes here, since we want the end_sequence 58077298Sobrien to emit the matrix entry. */ 58177298Sobrien if (line_delta == INT_MAX) 58260484Sobrien { 58377298Sobrien if (addr_delta == MAX_SPECIAL_ADDR_DELTA) 58477298Sobrien len = 1; 58560484Sobrien else 58677298Sobrien len = 1 + sizeof_leb128 (addr_delta, 0); 58777298Sobrien return len + 3; 58860484Sobrien } 58960484Sobrien 59077298Sobrien /* Bias the line delta by the base. */ 59177298Sobrien tmp = line_delta - DWARF2_LINE_BASE; 59260484Sobrien 59377298Sobrien /* If the line increment is out of range of a special opcode, we 59477298Sobrien must encode it with DW_LNS_advance_line. */ 59577298Sobrien if (tmp >= DWARF2_LINE_RANGE) 59677298Sobrien { 59777298Sobrien len = 1 + sizeof_leb128 (line_delta, 1); 59877298Sobrien line_delta = 0; 59977298Sobrien tmp = 0 - DWARF2_LINE_BASE; 60077298Sobrien } 60177298Sobrien 60277298Sobrien /* Bias the opcode by the special opcode base. */ 60377298Sobrien tmp += DWARF2_LINE_OPCODE_BASE; 60477298Sobrien 60577298Sobrien /* Avoid overflow when addr_delta is large. */ 60677298Sobrien if (addr_delta < 256 + MAX_SPECIAL_ADDR_DELTA) 60777298Sobrien { 60877298Sobrien /* Try using a special opcode. */ 60977298Sobrien opcode = tmp + addr_delta * DWARF2_LINE_RANGE; 61077298Sobrien if (opcode <= 255) 61177298Sobrien return len + 1; 61277298Sobrien 61377298Sobrien /* Try using DW_LNS_const_add_pc followed by special op. */ 61477298Sobrien opcode = tmp + (addr_delta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE; 61577298Sobrien if (opcode <= 255) 61677298Sobrien return len + 2; 61777298Sobrien } 61877298Sobrien 61977298Sobrien /* Otherwise use DW_LNS_advance_pc. */ 62077298Sobrien len += 1 + sizeof_leb128 (addr_delta, 0); 62177298Sobrien 62277298Sobrien /* DW_LNS_copy or special opcode. */ 62377298Sobrien len += 1; 62477298Sobrien 62577298Sobrien return len; 62660484Sobrien} 62760484Sobrien 62877298Sobrienstatic void 62977298Sobrienemit_inc_line_addr (line_delta, addr_delta, p, len) 63077298Sobrien int line_delta; 63177298Sobrien addressT addr_delta; 63277298Sobrien char *p; 63377298Sobrien int len; 63460484Sobrien{ 63577298Sobrien unsigned int tmp, opcode; 63677298Sobrien int need_copy = 0; 63777298Sobrien char *end = p + len; 63860484Sobrien 63977298Sobrien#if DWARF2_LINE_MIN_INSN_LENGTH > 1 64077298Sobrien /* Scale the address delta by the minimum instruction length. */ 64177298Sobrien assert (addr_delta % DWARF2_LINE_MIN_INSN_LENGTH == 0); 64277298Sobrien addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH; 64377298Sobrien#endif 64477298Sobrien /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence. 64577298Sobrien We cannot use special opcodes here, since we want the end_sequence 64677298Sobrien to emit the matrix entry. */ 64777298Sobrien if (line_delta == INT_MAX) 64860484Sobrien { 64977298Sobrien if (addr_delta == MAX_SPECIAL_ADDR_DELTA) 65077298Sobrien *p++ = DW_LNS_const_add_pc; 65177298Sobrien else 65260484Sobrien { 65377298Sobrien *p++ = DW_LNS_advance_pc; 65477298Sobrien p += output_leb128 (p, addr_delta, 0); 65560484Sobrien } 65677298Sobrien 65777298Sobrien *p++ = DW_LNS_extended_op; 65877298Sobrien *p++ = 1; 65977298Sobrien *p++ = DW_LNE_end_sequence; 66077298Sobrien goto done; 66160484Sobrien } 66260484Sobrien 66377298Sobrien /* Bias the line delta by the base. */ 66477298Sobrien tmp = line_delta - DWARF2_LINE_BASE; 66577298Sobrien 66677298Sobrien /* If the line increment is out of range of a special opcode, we 66777298Sobrien must encode it with DW_LNS_advance_line. */ 66877298Sobrien if (tmp >= DWARF2_LINE_RANGE) 66960484Sobrien { 67077298Sobrien *p++ = DW_LNS_advance_line; 67177298Sobrien p += output_leb128 (p, line_delta, 1); 67260484Sobrien 67377298Sobrien /* Prettier, I think, to use DW_LNS_copy instead of a 67477298Sobrien "line +0, addr +0" special opcode. */ 67577298Sobrien if (addr_delta == 0) 67677298Sobrien { 67777298Sobrien *p++ = DW_LNS_copy; 67877298Sobrien goto done; 67977298Sobrien } 68060484Sobrien 68177298Sobrien line_delta = 0; 68277298Sobrien tmp = 0 - DWARF2_LINE_BASE; 68377298Sobrien need_copy = 1; 68477298Sobrien } 68560484Sobrien 68677298Sobrien /* Bias the opcode by the special opcode base. */ 68777298Sobrien tmp += DWARF2_LINE_OPCODE_BASE; 68860484Sobrien 68977298Sobrien /* Avoid overflow when addr_delta is large. */ 69077298Sobrien if (addr_delta < 256 + MAX_SPECIAL_ADDR_DELTA) 69160484Sobrien { 69277298Sobrien /* Try using a special opcode. */ 69377298Sobrien opcode = tmp + addr_delta * DWARF2_LINE_RANGE; 69477298Sobrien if (opcode <= 255) 69560484Sobrien { 69677298Sobrien *p++ = opcode; 69777298Sobrien goto done; 69860484Sobrien } 69977298Sobrien 70077298Sobrien /* Try using DW_LNS_const_add_pc followed by special op. */ 70177298Sobrien opcode = tmp + (addr_delta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE; 70277298Sobrien if (opcode <= 255) 70377298Sobrien { 70477298Sobrien *p++ = DW_LNS_const_add_pc; 70577298Sobrien *p++ = opcode; 70677298Sobrien goto done; 70777298Sobrien } 70860484Sobrien } 70977298Sobrien 71077298Sobrien /* Otherwise use DW_LNS_advance_pc. */ 71177298Sobrien *p++ = DW_LNS_advance_pc; 71277298Sobrien p += output_leb128 (p, addr_delta, 0); 71377298Sobrien 71477298Sobrien if (need_copy) 71577298Sobrien *p++ = DW_LNS_copy; 71660484Sobrien else 71777298Sobrien *p++ = tmp; 71860484Sobrien 71977298Sobrien done: 72077298Sobrien assert (p == end); 72177298Sobrien} 72260484Sobrien 72377298Sobrien/* Handy routine to combine calls to the above two routines. */ 72460484Sobrien 72577298Sobrienstatic void 72677298Sobrienout_inc_line_addr (line_delta, addr_delta) 72777298Sobrien int line_delta; 72877298Sobrien addressT addr_delta; 72977298Sobrien{ 73077298Sobrien int len = size_inc_line_addr (line_delta, addr_delta); 73177298Sobrien emit_inc_line_addr (line_delta, addr_delta, frag_more (len), len); 73277298Sobrien} 73360484Sobrien 73477298Sobrien/* Generate a variant frag that we can use to relax address/line 73577298Sobrien increments between fragments of the target segment. */ 73660484Sobrien 73777298Sobrienstatic void 73877298Sobrienrelax_inc_line_addr (line_delta, seg, to_frag, to_ofs, from_frag, from_ofs) 73977298Sobrien int line_delta; 74077298Sobrien segT seg; 74177298Sobrien fragS *to_frag, *from_frag; 74277298Sobrien addressT to_ofs, from_ofs; 74377298Sobrien{ 74477298Sobrien symbolS *to_sym, *from_sym; 74577298Sobrien expressionS expr; 74677298Sobrien int max_chars; 74760484Sobrien 74877298Sobrien to_sym = symbol_new (fake_label_name, seg, to_ofs, to_frag); 74977298Sobrien from_sym = symbol_new (fake_label_name, seg, from_ofs, from_frag); 75060484Sobrien 75177298Sobrien expr.X_op = O_subtract; 75277298Sobrien expr.X_add_symbol = to_sym; 75377298Sobrien expr.X_op_symbol = from_sym; 75477298Sobrien expr.X_add_number = 0; 75560484Sobrien 75677298Sobrien /* The maximum size of the frag is the line delta with a maximum 75777298Sobrien sized address delta. */ 75877298Sobrien max_chars = size_inc_line_addr (line_delta, -DWARF2_LINE_MIN_INSN_LENGTH); 75960484Sobrien 76077298Sobrien frag_var (rs_dwarf2dbg, max_chars, max_chars, 1, 76177298Sobrien make_expr_symbol (&expr), line_delta, NULL); 76277298Sobrien} 76360484Sobrien 76477298Sobrien/* The function estimates the size of a rs_dwarf2dbg variant frag 76577298Sobrien based on the current values of the symbols. It is called before 76677298Sobrien the relaxation loop. We set fr_subtype to the expected length. */ 76760484Sobrien 76877298Sobrienint 76977298Sobriendwarf2dbg_estimate_size_before_relax (frag) 77077298Sobrien fragS *frag; 77177298Sobrien{ 77277298Sobrien offsetT addr_delta; 77377298Sobrien int size; 77460484Sobrien 77577298Sobrien addr_delta = resolve_symbol_value (frag->fr_symbol, 0); 77677298Sobrien size = size_inc_line_addr (frag->fr_offset, addr_delta); 77760484Sobrien 77877298Sobrien frag->fr_subtype = size; 77960484Sobrien 78077298Sobrien return size; 78160484Sobrien} 78260484Sobrien 78377298Sobrien/* This function relaxes a rs_dwarf2dbg variant frag based on the 78477298Sobrien current values of the symbols. fr_subtype is the current length 78577298Sobrien of the frag. This returns the change in frag length. */ 78677298Sobrien 78777298Sobrienint 78877298Sobriendwarf2dbg_relax_frag (frag) 78977298Sobrien fragS *frag; 79077298Sobrien{ 79177298Sobrien int old_size, new_size; 79277298Sobrien 79377298Sobrien old_size = frag->fr_subtype; 79477298Sobrien new_size = dwarf2dbg_estimate_size_before_relax (frag); 79577298Sobrien 79677298Sobrien return new_size - old_size; 79777298Sobrien} 79877298Sobrien 79977298Sobrien/* This function converts a rs_dwarf2dbg variant frag into a normal 80077298Sobrien fill frag. This is called after all relaxation has been done. 80177298Sobrien fr_subtype will be the desired length of the frag. */ 80277298Sobrien 80377298Sobrienvoid 80477298Sobriendwarf2dbg_convert_frag (frag) 80577298Sobrien fragS *frag; 80677298Sobrien{ 80777298Sobrien offsetT addr_diff; 80877298Sobrien 80977298Sobrien addr_diff = resolve_symbol_value (frag->fr_symbol, 1); 81077298Sobrien 81177298Sobrien /* fr_var carries the max_chars that we created the fragment with. 81277298Sobrien fr_subtype carries the current expected length. We must, of 81377298Sobrien course, have allocated enough memory earlier. */ 81477298Sobrien assert (frag->fr_var >= (int) frag->fr_subtype); 81577298Sobrien 81677298Sobrien emit_inc_line_addr (frag->fr_offset, addr_diff, 81777298Sobrien frag->fr_literal + frag->fr_fix, frag->fr_subtype); 81877298Sobrien 81977298Sobrien frag->fr_fix += frag->fr_subtype; 82077298Sobrien frag->fr_type = rs_fill; 82177298Sobrien frag->fr_var = 0; 82277298Sobrien frag->fr_offset = 0; 82377298Sobrien} 82477298Sobrien 82577298Sobrien/* Generate .debug_line content for the chain of line number entries 82677298Sobrien beginning at E, for segment SEG. */ 82777298Sobrien 82860484Sobrienstatic void 82977298Sobrienprocess_entries (seg, e) 83077298Sobrien segT seg; 83177298Sobrien struct line_entry *e; 83260484Sobrien{ 83377298Sobrien unsigned filenum = 1; 83477298Sobrien unsigned line = 1; 83577298Sobrien unsigned column = 0; 83677298Sobrien unsigned flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_BEGIN_STMT : 0; 83777298Sobrien fragS *frag = NULL; 83877298Sobrien fragS *last_frag; 83977298Sobrien addressT frag_ofs = 0; 84077298Sobrien addressT last_frag_ofs; 84177298Sobrien struct line_entry *next; 84260484Sobrien 84377298Sobrien while (e) 84477298Sobrien { 84577298Sobrien int changed = 0; 84660484Sobrien 84777298Sobrien if (filenum != e->loc.filenum) 84860484Sobrien { 84977298Sobrien filenum = e->loc.filenum; 85077298Sobrien out_opcode (DW_LNS_set_file); 85177298Sobrien out_uleb128 (filenum); 85277298Sobrien changed = 1; 85377298Sobrien } 85477298Sobrien 85577298Sobrien if (column != e->loc.column) 85677298Sobrien { 85777298Sobrien column = e->loc.column; 85877298Sobrien out_opcode (DW_LNS_set_column); 85977298Sobrien out_uleb128 (column); 86077298Sobrien changed = 1; 86177298Sobrien } 86277298Sobrien 86377298Sobrien if ((e->loc.flags ^ flags) & DWARF2_FLAG_BEGIN_STMT) 86477298Sobrien { 86577298Sobrien flags = e->loc.flags; 86677298Sobrien out_opcode (DW_LNS_negate_stmt); 86777298Sobrien changed = 1; 86877298Sobrien } 86977298Sobrien 87077298Sobrien if (e->loc.flags & DWARF2_FLAG_BEGIN_BLOCK) 87177298Sobrien { 87277298Sobrien out_opcode (DW_LNS_set_basic_block); 87377298Sobrien changed = 1; 87477298Sobrien } 87577298Sobrien 87677298Sobrien if (line != e->loc.line || changed) 87777298Sobrien { 87877298Sobrien int line_delta = e->loc.line - line; 87977298Sobrien if (frag == NULL) 88060484Sobrien { 88177298Sobrien out_set_addr (seg, e->frag, e->frag_ofs); 88277298Sobrien out_inc_line_addr (line_delta, 0); 88360484Sobrien } 88477298Sobrien else if (frag == e->frag) 88577298Sobrien out_inc_line_addr (line_delta, e->frag_ofs - frag_ofs); 88677298Sobrien else 88777298Sobrien relax_inc_line_addr (line_delta, seg, e->frag, e->frag_ofs, 88877298Sobrien frag, frag_ofs); 88977298Sobrien 89077298Sobrien frag = e->frag; 89177298Sobrien frag_ofs = e->frag_ofs; 89277298Sobrien line = e->loc.line; 89360484Sobrien } 89477298Sobrien else if (frag == NULL) 89577298Sobrien { 89677298Sobrien out_set_addr (seg, e->frag, e->frag_ofs); 89777298Sobrien frag = e->frag; 89877298Sobrien frag_ofs = e->frag_ofs; 89977298Sobrien } 90077298Sobrien 90177298Sobrien next = e->next; 90277298Sobrien free (e); 90377298Sobrien e = next; 90460484Sobrien } 90577298Sobrien 90677298Sobrien /* Emit a DW_LNE_end_sequence for the end of the section. */ 90777298Sobrien last_frag = last_frag_for_seg (seg); 90877298Sobrien last_frag_ofs = get_frag_fix (last_frag); 90977298Sobrien if (frag == last_frag) 91077298Sobrien out_inc_line_addr (INT_MAX, last_frag_ofs - frag_ofs); 91177298Sobrien else 91277298Sobrien relax_inc_line_addr (INT_MAX, seg, last_frag, last_frag_ofs, 91377298Sobrien frag, frag_ofs); 91460484Sobrien} 91560484Sobrien 91677298Sobrien/* Emit the directory and file tables for .debug_line. */ 91777298Sobrien 91860484Sobrienstatic void 91977298Sobrienout_file_list () 92060484Sobrien{ 92160484Sobrien size_t size; 92260484Sobrien char *cp; 92377298Sobrien unsigned int i; 92460484Sobrien 92577298Sobrien /* Terminate directory list. */ 92677298Sobrien out_byte ('\0'); 92777298Sobrien 92877298Sobrien for (i = 1; i < files_in_use; ++i) 92960484Sobrien { 93077298Sobrien if (files[i].filename == NULL) 93177298Sobrien { 93277298Sobrien as_bad (_("Unassigned file number %u"), i); 93377298Sobrien continue; 93477298Sobrien } 93577298Sobrien 93677298Sobrien size = strlen (files[i].filename) + 1; 93760484Sobrien cp = frag_more (size); 93877298Sobrien memcpy (cp, files[i].filename, size); 93960484Sobrien 94077298Sobrien out_uleb128 (files[i].dir); /* directory number */ 94160484Sobrien out_uleb128 (0); /* last modification timestamp */ 94260484Sobrien out_uleb128 (0); /* filesize */ 94360484Sobrien } 94477298Sobrien 94577298Sobrien /* Terminate filename list. */ 94677298Sobrien out_byte (0); 94760484Sobrien} 94860484Sobrien 94977298Sobrien/* Emit the collected .debug_line data. */ 95077298Sobrien 95160484Sobrienstatic void 95277298Sobrienout_debug_line (line_seg) 95377298Sobrien segT line_seg; 95460484Sobrien{ 95577298Sobrien expressionS expr; 95677298Sobrien symbolS *line_start; 95777298Sobrien symbolS *prologue_end; 95877298Sobrien symbolS *line_end; 95977298Sobrien struct line_seg *s; 96077298Sobrien 96177298Sobrien subseg_set (line_seg, 0); 96277298Sobrien 96377298Sobrien line_start = symbol_new_now (); 96477298Sobrien prologue_end = symbol_make (fake_label_name); 96577298Sobrien line_end = symbol_make (fake_label_name); 96677298Sobrien 96777298Sobrien /* Total length of the information for this compilation unit. */ 96877298Sobrien expr.X_op = O_subtract; 96977298Sobrien expr.X_add_symbol = line_end; 97077298Sobrien expr.X_op_symbol = line_start; 97177298Sobrien expr.X_add_number = -4; 97277298Sobrien emit_expr (&expr, 4); 97377298Sobrien 97477298Sobrien /* Version. */ 97577298Sobrien out_two (2); 97677298Sobrien 97777298Sobrien /* Length of the prologue following this length. */ 97877298Sobrien expr.X_op = O_subtract; 97977298Sobrien expr.X_add_symbol = prologue_end; 98077298Sobrien expr.X_op_symbol = line_start; 98177298Sobrien expr.X_add_number = - (4 + 2 + 4); 98277298Sobrien emit_expr (&expr, 4); 98377298Sobrien 98477298Sobrien /* Parameters of the state machine. */ 98577298Sobrien out_byte (DWARF2_LINE_MIN_INSN_LENGTH); 98677298Sobrien out_byte (DWARF2_LINE_DEFAULT_IS_STMT); 98777298Sobrien out_byte (DWARF2_LINE_BASE); 98877298Sobrien out_byte (DWARF2_LINE_RANGE); 98977298Sobrien out_byte (DWARF2_LINE_OPCODE_BASE); 99077298Sobrien 99177298Sobrien /* Standard opcode lengths. */ 99277298Sobrien out_byte (0); /* DW_LNS_copy */ 99377298Sobrien out_byte (1); /* DW_LNS_advance_pc */ 99477298Sobrien out_byte (1); /* DW_LNS_advance_line */ 99577298Sobrien out_byte (1); /* DW_LNS_set_file */ 99677298Sobrien out_byte (1); /* DW_LNS_set_column */ 99777298Sobrien out_byte (0); /* DW_LNS_negate_stmt */ 99877298Sobrien out_byte (0); /* DW_LNS_set_basic_block */ 99977298Sobrien out_byte (0); /* DW_LNS_const_add_pc */ 100077298Sobrien out_byte (1); /* DW_LNS_fixed_advance_pc */ 100177298Sobrien 100277298Sobrien out_file_list (); 100377298Sobrien 100477298Sobrien set_symbol_value_now (prologue_end); 100577298Sobrien 100677298Sobrien /* For each section, emit a statement program. */ 100777298Sobrien for (s = all_segs; s; s = s->next) 100877298Sobrien process_entries (s->seg, s->head->head); 100977298Sobrien 101077298Sobrien set_symbol_value_now (line_end); 101177298Sobrien} 101277298Sobrien 101377298Sobrien/* Emit data for .debug_aranges. */ 101477298Sobrien 101577298Sobrienstatic void 101677298Sobrienout_debug_aranges (aranges_seg, info_seg) 101777298Sobrien segT aranges_seg; 101877298Sobrien segT info_seg; 101977298Sobrien{ 102077298Sobrien unsigned int addr_size = sizeof_address; 102177298Sobrien addressT size, skip; 102277298Sobrien struct line_seg *s; 102377298Sobrien expressionS expr; 102477298Sobrien char *p; 102577298Sobrien 102677298Sobrien size = 4 + 2 + 4 + 1 + 1; 102777298Sobrien 102877298Sobrien skip = 2 * addr_size - (size & (2 * addr_size - 1)); 102977298Sobrien if (skip == 2 * addr_size) 103077298Sobrien skip = 0; 103177298Sobrien size += skip; 103277298Sobrien 103377298Sobrien for (s = all_segs; s; s = s->next) 103477298Sobrien size += 2 * addr_size; 103577298Sobrien 103677298Sobrien size += 2 * addr_size; 103777298Sobrien 103877298Sobrien subseg_set (aranges_seg, 0); 103977298Sobrien 104077298Sobrien /* Length of the compilation unit. */ 104177298Sobrien out_four (size - 4); 104277298Sobrien 104377298Sobrien /* Version. */ 104477298Sobrien out_two (2); 104577298Sobrien 104677298Sobrien /* Offset to .debug_info. */ 104777298Sobrien expr.X_op = O_symbol; 104877298Sobrien expr.X_add_symbol = section_symbol (info_seg); 104977298Sobrien expr.X_add_number = 0; 105077298Sobrien emit_expr (&expr, 4); 105177298Sobrien 105277298Sobrien /* Size of an address (offset portion). */ 105377298Sobrien out_byte (addr_size); 105477298Sobrien 105577298Sobrien /* Size of a segment descriptor. */ 105677298Sobrien out_byte (0); 105777298Sobrien 105877298Sobrien /* Align the header. */ 105977298Sobrien if (skip) 106077298Sobrien frag_align (ffs (2 * addr_size) - 1, 0, 0); 106177298Sobrien 106277298Sobrien for (s = all_segs; s; s = s->next) 106360484Sobrien { 106477298Sobrien fragS *frag; 106577298Sobrien symbolS *beg, *end; 106660484Sobrien 106777298Sobrien frag = first_frag_for_seg (s->seg); 106877298Sobrien beg = symbol_new (fake_label_name, s->seg, 0, frag); 106977298Sobrien s->text_start = beg; 107060484Sobrien 107177298Sobrien frag = last_frag_for_seg (s->seg); 107277298Sobrien end = symbol_new (fake_label_name, s->seg, get_frag_fix (frag), frag); 107377298Sobrien s->text_end = end; 107460484Sobrien 107577298Sobrien expr.X_op = O_symbol; 107677298Sobrien expr.X_add_symbol = beg; 107777298Sobrien expr.X_add_number = 0; 107877298Sobrien emit_expr (&expr, addr_size); 107977298Sobrien 108077298Sobrien expr.X_op = O_subtract; 108177298Sobrien expr.X_add_symbol = end; 108277298Sobrien expr.X_op_symbol = beg; 108377298Sobrien expr.X_add_number = 0; 108477298Sobrien emit_expr (&expr, addr_size); 108560484Sobrien } 108660484Sobrien 108777298Sobrien p = frag_more (2 * addr_size); 108877298Sobrien md_number_to_chars (p, 0, addr_size); 108977298Sobrien md_number_to_chars (p + addr_size, 0, addr_size); 109077298Sobrien} 109160484Sobrien 109277298Sobrien/* Emit data for .debug_abbrev. Note that this must be kept in 109377298Sobrien sync with out_debug_info below. */ 109460484Sobrien 109577298Sobrienstatic void 109677298Sobrienout_debug_abbrev (abbrev_seg) 109777298Sobrien segT abbrev_seg; 109877298Sobrien{ 109977298Sobrien subseg_set (abbrev_seg, 0); 110077298Sobrien 110177298Sobrien out_uleb128 (1); 110277298Sobrien out_uleb128 (DW_TAG_compile_unit); 110377298Sobrien out_byte (DW_CHILDREN_no); 110477298Sobrien out_abbrev (DW_AT_stmt_list, DW_FORM_data4); 110577298Sobrien if (all_segs->next == NULL) 110660484Sobrien { 110777298Sobrien out_abbrev (DW_AT_low_pc, DW_FORM_addr); 110877298Sobrien out_abbrev (DW_AT_high_pc, DW_FORM_addr); 110960484Sobrien } 111077298Sobrien out_abbrev (DW_AT_comp_dir, DW_FORM_string); 111177298Sobrien out_abbrev (DW_AT_producer, DW_FORM_string); 111277298Sobrien out_abbrev (DW_AT_language, DW_FORM_data2); 111377298Sobrien out_abbrev (0, 0); 111477298Sobrien 111577298Sobrien /* Terminate the abbreviations for this compilation unit. */ 111677298Sobrien out_byte (0); 111760484Sobrien} 111860484Sobrien 111977298Sobrien/* Emit a description of this compilation unit for .debug_info. */ 112077298Sobrien 112177298Sobrienstatic void 112277298Sobrienout_debug_info (info_seg, abbrev_seg, line_seg) 112377298Sobrien segT info_seg; 112477298Sobrien segT abbrev_seg; 112577298Sobrien segT line_seg; 112660484Sobrien{ 112777298Sobrien char producer[128]; 112877298Sobrien char *comp_dir; 112977298Sobrien expressionS expr; 113077298Sobrien symbolS *info_start; 113177298Sobrien symbolS *info_end; 113277298Sobrien char *p; 113377298Sobrien int len; 113460484Sobrien 113577298Sobrien subseg_set (info_seg, 0); 113660484Sobrien 113777298Sobrien info_start = symbol_new_now (); 113877298Sobrien info_end = symbol_make (fake_label_name); 113960484Sobrien 114077298Sobrien /* Compilation Unit length. */ 114177298Sobrien expr.X_op = O_subtract; 114277298Sobrien expr.X_add_symbol = info_end; 114377298Sobrien expr.X_op_symbol = info_start; 114477298Sobrien expr.X_add_number = -4; 114577298Sobrien emit_expr (&expr, 4); 114660484Sobrien 114777298Sobrien /* DWARF version. */ 114877298Sobrien out_two (2); 114960484Sobrien 115077298Sobrien /* .debug_abbrev offset */ 115177298Sobrien expr.X_op = O_symbol; 115277298Sobrien expr.X_add_symbol = section_symbol (abbrev_seg); 115377298Sobrien expr.X_add_number = 0; 115477298Sobrien emit_expr (&expr, 4); 115560484Sobrien 115677298Sobrien /* Target address size. */ 115777298Sobrien out_byte (sizeof_address); 115860484Sobrien 115977298Sobrien /* DW_TAG_compile_unit DIE abbrev */ 116077298Sobrien out_uleb128 (1); 116160484Sobrien 116277298Sobrien /* DW_AT_stmt_list */ 116377298Sobrien expr.X_op = O_symbol; 116477298Sobrien expr.X_add_symbol = section_symbol (line_seg); 116577298Sobrien expr.X_add_number = 0; 116677298Sobrien emit_expr (&expr, 4); 116760484Sobrien 116877298Sobrien /* These two attributes may only be emitted if all of the code is 116977298Sobrien contiguous. Multiple sections are not that. */ 117077298Sobrien if (all_segs->next == NULL) 117177298Sobrien { 117277298Sobrien /* DW_AT_low_pc */ 117377298Sobrien expr.X_op = O_symbol; 117477298Sobrien expr.X_add_symbol = all_segs->text_start; 117577298Sobrien expr.X_add_number = 0; 117677298Sobrien emit_expr (&expr, sizeof_address); 117760484Sobrien 117877298Sobrien /* DW_AT_high_pc */ 117977298Sobrien expr.X_op = O_symbol; 118077298Sobrien expr.X_add_symbol = all_segs->text_end; 118177298Sobrien expr.X_add_number = 0; 118277298Sobrien emit_expr (&expr, sizeof_address); 118377298Sobrien } 118460484Sobrien 118577298Sobrien /* DW_AT_comp_dir */ 118677298Sobrien comp_dir = getpwd (); 118777298Sobrien len = strlen (comp_dir) + 1; 118877298Sobrien p = frag_more (len); 118977298Sobrien memcpy (p, comp_dir, len); 119077298Sobrien 119177298Sobrien /* DW_AT_producer */ 119277298Sobrien sprintf (producer, "GNU AS %s", VERSION); 119377298Sobrien len = strlen (producer) + 1; 119477298Sobrien p = frag_more (len); 119577298Sobrien memcpy (p, producer, len); 119677298Sobrien 119777298Sobrien /* DW_AT_language. Yes, this is probably not really MIPS, but the 119877298Sobrien dwarf2 draft has no standard code for assembler. */ 119977298Sobrien out_two (DW_LANG_Mips_Assembler); 120077298Sobrien 120177298Sobrien set_symbol_value_now (info_end); 120260484Sobrien} 120360484Sobrien 120460484Sobrienvoid 120577298Sobriendwarf2_finish () 120660484Sobrien{ 120777298Sobrien segT line_seg; 120877298Sobrien struct line_seg *s; 120960484Sobrien 121077298Sobrien /* If no debug information was recorded, nothing to do. */ 121177298Sobrien if (all_segs == NULL) 121277298Sobrien return; 121377298Sobrien 121477298Sobrien /* Calculate the size of an address for the target machine. */ 121577298Sobrien sizeof_address = bfd_arch_bits_per_address (stdoutput) / 8; 121677298Sobrien 121777298Sobrien /* Create and switch to the line number section. */ 121877298Sobrien line_seg = subseg_new (".debug_line", 0); 121977298Sobrien bfd_set_section_flags (stdoutput, line_seg, SEC_READONLY); 122077298Sobrien 122177298Sobrien /* For each subsection, chain the debug entries together. */ 122277298Sobrien for (s = all_segs; s; s = s->next) 122360484Sobrien { 122477298Sobrien struct line_subseg *ss = s->head; 122577298Sobrien struct line_entry **ptail = ss->ptail; 122677298Sobrien 122777298Sobrien while ((ss = ss->next) != NULL) 122877298Sobrien { 122977298Sobrien *ptail = ss->head; 123077298Sobrien ptail = ss->ptail; 123177298Sobrien } 123260484Sobrien } 123360484Sobrien 123477298Sobrien out_debug_line (line_seg); 123560484Sobrien 123677298Sobrien /* If this is assembler generated line info, we need .debug_info 123777298Sobrien and .debug_abbrev sections as well. */ 123877298Sobrien if (debug_type == DEBUG_DWARF2) 123977298Sobrien { 124077298Sobrien segT abbrev_seg; 124177298Sobrien segT info_seg; 124277298Sobrien segT aranges_seg; 124360484Sobrien 124477298Sobrien info_seg = subseg_new (".debug_info", 0); 124577298Sobrien abbrev_seg = subseg_new (".debug_abbrev", 0); 124677298Sobrien aranges_seg = subseg_new (".debug_aranges", 0); 124760484Sobrien 124877298Sobrien bfd_set_section_flags (stdoutput, info_seg, SEC_READONLY); 124977298Sobrien bfd_set_section_flags (stdoutput, abbrev_seg, SEC_READONLY); 125077298Sobrien bfd_set_section_flags (stdoutput, aranges_seg, SEC_READONLY); 125177298Sobrien 125277298Sobrien record_alignment (aranges_seg, ffs (2 * sizeof_address) - 1); 125377298Sobrien 125477298Sobrien out_debug_aranges (aranges_seg, info_seg); 125577298Sobrien out_debug_abbrev (abbrev_seg); 125677298Sobrien out_debug_info (info_seg, abbrev_seg, line_seg); 125777298Sobrien } 125860484Sobrien} 125960484Sobrien 126077298Sobrien#else 126160484Sobrienvoid 126277298Sobriendwarf2_finish () 126360484Sobrien{ 126477298Sobrien} 126560484Sobrien 126677298Sobrienint 126777298Sobriendwarf2dbg_estimate_size_before_relax (frag) 126877298Sobrien fragS *frag ATTRIBUTE_UNUSED; 126977298Sobrien{ 127077298Sobrien as_fatal (_("dwarf2 is not supported for this object file format")); 127177298Sobrien return 0; 127277298Sobrien} 127360484Sobrien 127477298Sobrienint 127577298Sobriendwarf2dbg_relax_frag (frag) 127677298Sobrien fragS *frag ATTRIBUTE_UNUSED; 127777298Sobrien{ 127877298Sobrien as_fatal (_("dwarf2 is not supported for this object file format")); 127977298Sobrien return 0; 128077298Sobrien} 128160484Sobrien 128277298Sobrienvoid 128377298Sobriendwarf2dbg_convert_frag (frag) 128477298Sobrien fragS *frag ATTRIBUTE_UNUSED; 128577298Sobrien{ 128677298Sobrien as_fatal (_("dwarf2 is not supported for this object file format")); 128760484Sobrien} 128860484Sobrien 128960484Sobrienvoid 129077298Sobriendwarf2_emit_insn (size) 129177298Sobrien int size ATTRIBUTE_UNUSED; 129260484Sobrien{ 129360484Sobrien} 129477298Sobrien 129577298Sobrienvoid 129677298Sobriendwarf2_directive_file (dummy) 129777298Sobrien int dummy ATTRIBUTE_UNUSED; 129877298Sobrien{ 129977298Sobrien as_fatal (_("dwarf2 is not supported for this object file format")); 130077298Sobrien} 130177298Sobrien 130277298Sobrienvoid 130377298Sobriendwarf2_directive_loc (dummy) 130477298Sobrien int dummy ATTRIBUTE_UNUSED; 130577298Sobrien{ 130677298Sobrien as_fatal (_("dwarf2 is not supported for this object file format")); 130777298Sobrien} 130877298Sobrien#endif /* BFD_ASSEMBLER */ 1309