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