xref: /openbsd-src/gnu/usr.bin/gcc/gcc/line-map.c (revision c87b03e512fc05ed6e0222f6fb0ae86264b1d05b)
1*c87b03e5Sespie /* Map logical line numbers to (source file, line number) pairs.
2*c87b03e5Sespie    Copyright (C) 2001
3*c87b03e5Sespie    Free Software Foundation, Inc.
4*c87b03e5Sespie 
5*c87b03e5Sespie This program is free software; you can redistribute it and/or modify it
6*c87b03e5Sespie under the terms of the GNU General Public License as published by the
7*c87b03e5Sespie Free Software Foundation; either version 2, or (at your option) any
8*c87b03e5Sespie later version.
9*c87b03e5Sespie 
10*c87b03e5Sespie This program is distributed in the hope that it will be useful,
11*c87b03e5Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
12*c87b03e5Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*c87b03e5Sespie GNU General Public License for more details.
14*c87b03e5Sespie 
15*c87b03e5Sespie You should have received a copy of the GNU General Public License
16*c87b03e5Sespie along with this program; if not, write to the Free Software
17*c87b03e5Sespie Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18*c87b03e5Sespie 
19*c87b03e5Sespie  In other words, you are welcome to use, share and improve this program.
20*c87b03e5Sespie  You are forbidden to forbid anyone else to use, share and improve
21*c87b03e5Sespie  what you give them.   Help stamp out software-hoarding!  */
22*c87b03e5Sespie 
23*c87b03e5Sespie #include "config.h"
24*c87b03e5Sespie #include "system.h"
25*c87b03e5Sespie #include "line-map.h"
26*c87b03e5Sespie #include "intl.h"
27*c87b03e5Sespie 
28*c87b03e5Sespie static void trace_include
29*c87b03e5Sespie   PARAMS ((const struct line_maps *, const struct line_map *));
30*c87b03e5Sespie 
31*c87b03e5Sespie /* Initialize a line map set.  */
32*c87b03e5Sespie 
33*c87b03e5Sespie void
init_line_maps(set)34*c87b03e5Sespie init_line_maps (set)
35*c87b03e5Sespie      struct line_maps *set;
36*c87b03e5Sespie {
37*c87b03e5Sespie   set->maps = 0;
38*c87b03e5Sespie   set->allocated = 0;
39*c87b03e5Sespie   set->used = 0;
40*c87b03e5Sespie   set->last_listed = -1;
41*c87b03e5Sespie   set->trace_includes = false;
42*c87b03e5Sespie   set->depth = 0;
43*c87b03e5Sespie }
44*c87b03e5Sespie 
45*c87b03e5Sespie /* Free a line map set.  */
46*c87b03e5Sespie 
47*c87b03e5Sespie void
free_line_maps(set)48*c87b03e5Sespie free_line_maps (set)
49*c87b03e5Sespie      struct line_maps *set;
50*c87b03e5Sespie {
51*c87b03e5Sespie   if (set->maps)
52*c87b03e5Sespie     {
53*c87b03e5Sespie       struct line_map *map;
54*c87b03e5Sespie 
55*c87b03e5Sespie       /* Depending upon whether we are handling preprocessed input or
56*c87b03e5Sespie 	 not, this can be a user error or an ICE.  */
57*c87b03e5Sespie       for (map = CURRENT_LINE_MAP (set); ! MAIN_FILE_P (map);
58*c87b03e5Sespie 	   map = INCLUDED_FROM (set, map))
59*c87b03e5Sespie 	fprintf (stderr, "line-map.c: file \"%s\" entered but not left\n",
60*c87b03e5Sespie 		 map->to_file);
61*c87b03e5Sespie 
62*c87b03e5Sespie       free (set->maps);
63*c87b03e5Sespie     }
64*c87b03e5Sespie }
65*c87b03e5Sespie 
66*c87b03e5Sespie /* Add a mapping of logical source line to physical source file and
67*c87b03e5Sespie    line number.  Ther text pointed to by TO_FILE must have a lifetime
68*c87b03e5Sespie    at least as long as the final call to lookup_line ().
69*c87b03e5Sespie 
70*c87b03e5Sespie    FROM_LINE should be monotonic increasing across calls to this
71*c87b03e5Sespie    function.  */
72*c87b03e5Sespie 
73*c87b03e5Sespie const struct line_map *
add_line_map(set,reason,sysp,from_line,to_file,to_line)74*c87b03e5Sespie add_line_map (set, reason, sysp, from_line, to_file, to_line)
75*c87b03e5Sespie      struct line_maps *set;
76*c87b03e5Sespie      enum lc_reason reason;
77*c87b03e5Sespie      unsigned int sysp;
78*c87b03e5Sespie      unsigned int from_line;
79*c87b03e5Sespie      const char *to_file;
80*c87b03e5Sespie      unsigned int to_line;
81*c87b03e5Sespie {
82*c87b03e5Sespie   struct line_map *map;
83*c87b03e5Sespie 
84*c87b03e5Sespie   if (set->used && from_line < set->maps[set->used - 1].from_line)
85*c87b03e5Sespie     abort ();
86*c87b03e5Sespie 
87*c87b03e5Sespie   if (set->used == set->allocated)
88*c87b03e5Sespie     {
89*c87b03e5Sespie       set->allocated = 2 * set->allocated + 256;
90*c87b03e5Sespie       set->maps = (struct line_map *)
91*c87b03e5Sespie 	xrealloc (set->maps, set->allocated * sizeof (struct line_map));
92*c87b03e5Sespie     }
93*c87b03e5Sespie 
94*c87b03e5Sespie   map = &set->maps[set->used++];
95*c87b03e5Sespie 
96*c87b03e5Sespie   /* If we don't keep our line maps consistent, we can easily
97*c87b03e5Sespie      segfault.  Don't rely on the client to do it for us.  */
98*c87b03e5Sespie   if (set->depth == 0)
99*c87b03e5Sespie     reason = LC_ENTER;
100*c87b03e5Sespie   else if (reason == LC_LEAVE)
101*c87b03e5Sespie     {
102*c87b03e5Sespie       struct line_map *from;
103*c87b03e5Sespie       bool error;
104*c87b03e5Sespie 
105*c87b03e5Sespie       if (MAIN_FILE_P (map - 1))
106*c87b03e5Sespie 	{
107*c87b03e5Sespie 	  error = true;
108*c87b03e5Sespie 	  reason = LC_RENAME;
109*c87b03e5Sespie 	  from = map - 1;
110*c87b03e5Sespie 	}
111*c87b03e5Sespie       else
112*c87b03e5Sespie 	{
113*c87b03e5Sespie 	  from = INCLUDED_FROM (set, map - 1);
114*c87b03e5Sespie 	  error = to_file && strcmp (from->to_file, to_file);
115*c87b03e5Sespie 	}
116*c87b03e5Sespie 
117*c87b03e5Sespie       /* Depending upon whether we are handling preprocessed input or
118*c87b03e5Sespie 	 not, this can be a user error or an ICE.  */
119*c87b03e5Sespie       if (error)
120*c87b03e5Sespie 	fprintf (stderr, "line-map.c: file \"%s\" left but not entered\n",
121*c87b03e5Sespie 		 to_file);
122*c87b03e5Sespie 
123*c87b03e5Sespie       /* A TO_FILE of NULL is special - we use the natural values.  */
124*c87b03e5Sespie       if (error || to_file == NULL)
125*c87b03e5Sespie 	{
126*c87b03e5Sespie 	  to_file = from->to_file;
127*c87b03e5Sespie 	  to_line = LAST_SOURCE_LINE (from) + 1;
128*c87b03e5Sespie 	  sysp = from->sysp;
129*c87b03e5Sespie 	}
130*c87b03e5Sespie     }
131*c87b03e5Sespie 
132*c87b03e5Sespie   map->reason = reason;
133*c87b03e5Sespie   map->sysp = sysp;
134*c87b03e5Sespie   map->from_line = from_line;
135*c87b03e5Sespie   map->to_file = to_file;
136*c87b03e5Sespie   map->to_line = to_line;
137*c87b03e5Sespie 
138*c87b03e5Sespie   if (reason == LC_ENTER)
139*c87b03e5Sespie     {
140*c87b03e5Sespie       set->depth++;
141*c87b03e5Sespie       map->included_from = set->used - 2;
142*c87b03e5Sespie       if (set->trace_includes)
143*c87b03e5Sespie 	trace_include (set, map);
144*c87b03e5Sespie     }
145*c87b03e5Sespie   else if (reason == LC_RENAME)
146*c87b03e5Sespie     map->included_from = map[-1].included_from;
147*c87b03e5Sespie   else if (reason == LC_LEAVE)
148*c87b03e5Sespie     {
149*c87b03e5Sespie       set->depth--;
150*c87b03e5Sespie       map->included_from = INCLUDED_FROM (set, map - 1)->included_from;
151*c87b03e5Sespie     }
152*c87b03e5Sespie 
153*c87b03e5Sespie   return map;
154*c87b03e5Sespie }
155*c87b03e5Sespie 
156*c87b03e5Sespie /* Given a logical line, returns the map from which the corresponding
157*c87b03e5Sespie    (source file, line) pair can be deduced.  Since the set is built
158*c87b03e5Sespie    chronologically, the logical lines are monotonic increasing, and so
159*c87b03e5Sespie    the list is sorted and we can use a binary search.  */
160*c87b03e5Sespie 
161*c87b03e5Sespie const struct line_map *
lookup_line(set,line)162*c87b03e5Sespie lookup_line (set, line)
163*c87b03e5Sespie      struct line_maps *set;
164*c87b03e5Sespie      unsigned int line;
165*c87b03e5Sespie {
166*c87b03e5Sespie   unsigned int md, mn = 0, mx = set->used;
167*c87b03e5Sespie 
168*c87b03e5Sespie   if (mx == 0)
169*c87b03e5Sespie     abort ();
170*c87b03e5Sespie 
171*c87b03e5Sespie   while (mx - mn > 1)
172*c87b03e5Sespie     {
173*c87b03e5Sespie       md = (mn + mx) / 2;
174*c87b03e5Sespie       if (set->maps[md].from_line > line)
175*c87b03e5Sespie 	mx = md;
176*c87b03e5Sespie       else
177*c87b03e5Sespie 	mn = md;
178*c87b03e5Sespie     }
179*c87b03e5Sespie 
180*c87b03e5Sespie   return &set->maps[mn];
181*c87b03e5Sespie }
182*c87b03e5Sespie 
183*c87b03e5Sespie /* Print the file names and line numbers of the #include commands
184*c87b03e5Sespie    which led to the map MAP, if any, to stderr.  Nothing is output if
185*c87b03e5Sespie    the most recently listed stack is the same as the current one.  */
186*c87b03e5Sespie 
187*c87b03e5Sespie void
print_containing_files(set,map)188*c87b03e5Sespie print_containing_files (set, map)
189*c87b03e5Sespie      struct line_maps *set;
190*c87b03e5Sespie      const struct line_map *map;
191*c87b03e5Sespie {
192*c87b03e5Sespie   if (MAIN_FILE_P (map) || set->last_listed == map->included_from)
193*c87b03e5Sespie     return;
194*c87b03e5Sespie 
195*c87b03e5Sespie   set->last_listed = map->included_from;
196*c87b03e5Sespie   map = INCLUDED_FROM (set, map);
197*c87b03e5Sespie 
198*c87b03e5Sespie   fprintf (stderr,  _("In file included from %s:%u"),
199*c87b03e5Sespie 	   map->to_file, LAST_SOURCE_LINE (map));
200*c87b03e5Sespie 
201*c87b03e5Sespie   while (! MAIN_FILE_P (map))
202*c87b03e5Sespie     {
203*c87b03e5Sespie       map = INCLUDED_FROM (set, map);
204*c87b03e5Sespie       /* Translators note: this message is used in conjunction
205*c87b03e5Sespie 	 with "In file included from %s:%ld" and some other
206*c87b03e5Sespie 	 tricks.  We want something like this:
207*c87b03e5Sespie 
208*c87b03e5Sespie 	 | In file included from sys/select.h:123,
209*c87b03e5Sespie 	 |                  from sys/types.h:234,
210*c87b03e5Sespie 	 |                  from userfile.c:31:
211*c87b03e5Sespie 	 | bits/select.h:45: <error message here>
212*c87b03e5Sespie 
213*c87b03e5Sespie 	 with all the "from"s lined up.
214*c87b03e5Sespie 	 The trailing comma is at the beginning of this message,
215*c87b03e5Sespie 	 and the trailing colon is not translated.  */
216*c87b03e5Sespie       fprintf (stderr, _(",\n                 from %s:%u"),
217*c87b03e5Sespie 	       map->to_file, LAST_SOURCE_LINE (map));
218*c87b03e5Sespie     }
219*c87b03e5Sespie 
220*c87b03e5Sespie   fputs (":\n", stderr);
221*c87b03e5Sespie }
222*c87b03e5Sespie 
223*c87b03e5Sespie /* Print an include trace, for e.g. the -H option of the preprocessor.  */
224*c87b03e5Sespie 
225*c87b03e5Sespie static void
trace_include(set,map)226*c87b03e5Sespie trace_include (set, map)
227*c87b03e5Sespie      const struct line_maps *set;
228*c87b03e5Sespie      const struct line_map *map;
229*c87b03e5Sespie {
230*c87b03e5Sespie   unsigned int i = set->depth;
231*c87b03e5Sespie 
232*c87b03e5Sespie   while (--i)
233*c87b03e5Sespie     putc ('.', stderr);
234*c87b03e5Sespie   fprintf (stderr, " %s\n", map->to_file);
235*c87b03e5Sespie }
236