xref: /illumos-gate/usr/src/lib/libdwarf/common/pro_line.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2   Copyright (C) 2000,2004 Silicon Graphics, Inc.  All Rights Reserved.
3   Portions Copyright 2011-2019 David Anderson. All Rights Reserved.
4 
5   This program is free software; you can redistribute it and/or modify it
6   under the terms of version 2.1 of the GNU Lesser General Public License
7   as published by the Free Software Foundation.
8 
9   This program is distributed in the hope that it would be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13   Further, this software is distributed without any warranty that it is
14   free of the rightful claim of any third person regarding infringement
15   or the like.  Any license provided herein, whether implied or
16   otherwise, applies only to this software file.  Patent licenses, if
17   any, provided herein do not apply to combinations of this program with
18   other software, or any other product whatsoever.
19 
20   You should have received a copy of the GNU Lesser General Public
21   License along with this program; if not, write the Free Software
22   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
23   USA.
24 
25 */
26 
27 #include "config.h"
28 #include "libdwarfdefs.h"
29 #include <stdio.h>
30 #include <string.h>
31 
32 #include "pro_incl.h"
33 #include <stddef.h>
34 #include "dwarf.h"
35 #include "libdwarf.h"
36 #include "pro_opaque.h"
37 #include "pro_error.h"
38 #include "pro_alloc.h"
39 #include "pro_encode_nm.h"
40 #include "pro_line.h"
41 
42 static int _dwarf_pro_add_line_entry(Dwarf_P_Debug,
43     Dwarf_Unsigned file_index,
44     Dwarf_Addr code_address,
45     Dwarf_Unsigned symidx,
46     Dwarf_Unsigned line_no,
47     Dwarf_Signed col_no,
48     Dwarf_Bool is_stmt_begin,
49     Dwarf_Bool is_bb_begin,
50     Dwarf_Ubyte opc,
51     Dwarf_Bool isepilbeg,
52     Dwarf_Bool isprolend,
53     Dwarf_Unsigned isa,
54     Dwarf_Unsigned discriminator,
55     Dwarf_Error * error);
56 
57 /*  Add a entry to the line information section
58     file_index: index of file in file entries, obtained from
59     add_file_entry() call.
60 
61     This function actually calls _dwarf_pro_add_line_entry(), with
62     an extra parameter, the opcode. Done so that interface calls
63     dwarf_lne_set_address() and dwarf_lne_end_sequence() can use
64     this internal routine.
65 
66     The return value of the original
67     interfaces is really signed. Bogus interface.
68     With dwarf_add_line_entry_c the interface is corrected. */
69 Dwarf_Unsigned
70 dwarf_add_line_entry_b(Dwarf_P_Debug dbg,
71     Dwarf_Unsigned file_index,
72     Dwarf_Addr     code_address,
73     Dwarf_Unsigned line_no,
74     Dwarf_Signed   col_no,
75     Dwarf_Bool     is_stmt_begin,
76     Dwarf_Bool     is_bb_begin,
77     Dwarf_Bool     isepilbeg,
78     Dwarf_Bool     isprolend,
79     Dwarf_Unsigned isa,
80     Dwarf_Unsigned discriminator,
81     Dwarf_Error *  error)
82 {
83     Dwarf_Unsigned retval = 0;
84     Dwarf_Ubyte opc = 0;
85     Dwarf_Unsigned symidx = 0;
86 
87     retval = _dwarf_pro_add_line_entry(dbg, file_index, code_address,
88         symidx,
89         line_no, col_no, is_stmt_begin,
90         is_bb_begin,
91         opc,
92         isepilbeg,isprolend,isa,discriminator, error);
93     if (retval != DW_DLV_OK) {
94         return DW_DLV_NOCOUNT;
95     }
96     return 0;
97 }
98 int
99 dwarf_add_line_entry_c(Dwarf_P_Debug dbg,
100     Dwarf_Unsigned file_index,
101     Dwarf_Addr     code_address,
102     Dwarf_Unsigned line_no,
103     Dwarf_Signed   col_no,
104     Dwarf_Bool     is_stmt_begin,
105     Dwarf_Bool     is_bb_begin,
106     Dwarf_Bool     isepilbeg,
107     Dwarf_Bool     isprolend,
108     Dwarf_Unsigned isa,
109     Dwarf_Unsigned discriminator,
110     Dwarf_Error *  error)
111 {
112     int retval = 0;
113     Dwarf_Ubyte opc = 0;
114     Dwarf_Unsigned symidx = 0;
115 
116     retval = _dwarf_pro_add_line_entry(dbg, file_index, code_address,
117         symidx,
118         line_no, col_no, is_stmt_begin,
119         is_bb_begin,
120         opc,
121         isepilbeg,isprolend,isa,discriminator, error);
122     return retval;
123 }
124 
125 
126 
127 /*  The return value is really signed. Bogus interface.*/
128 Dwarf_Unsigned
129 dwarf_add_line_entry(Dwarf_P_Debug dbg,
130     Dwarf_Unsigned file_index,
131     Dwarf_Addr code_address,
132     Dwarf_Unsigned line_no,
133     Dwarf_Signed col_no, /* Wrong, should be unsigned. */
134     Dwarf_Bool is_stmt_begin,
135     Dwarf_Bool is_bb_begin, Dwarf_Error * error)
136 {
137     int retval = 0;
138     Dwarf_Ubyte opc = 0;
139     Dwarf_Unsigned symidx = 0;
140     Dwarf_Bool isepilbeg = 0;
141     Dwarf_Bool isprolend  = 0;
142     Dwarf_Unsigned isa = 0;
143     Dwarf_Unsigned discriminator = 0;
144 
145     retval = _dwarf_pro_add_line_entry(dbg, file_index, code_address,
146         symidx,
147         line_no, col_no, is_stmt_begin,
148         is_bb_begin,
149         opc,
150         isepilbeg, isprolend, isa, discriminator,
151         error);
152     if (retval != DW_DLV_OK) {
153         return DW_DLV_NOCOUNT;
154     }
155     return 0;
156 }
157 
158 void
159 _dwarf_init_default_line_header_vals(Dwarf_P_Debug dbg)
160 {
161     dbg->de_line_inits.pi_linetable_version = dbg->de_output_version;
162     dbg->de_line_inits.pi_default_is_stmt =
163         /* is false pro_line.h */
164         DEFAULT_IS_STMT;
165     dbg->de_line_inits.pi_minimum_instruction_length =
166         /* is 1 or 4 depending on ifdefs in pro_line.h */
167         MIN_INST_LENGTH;
168     dbg->de_line_inits.pi_maximum_operations_per_instruction =
169         /*  Assuming the instruction set is not VLIW,
170             used in the line table */
171         1;
172     dbg->de_line_inits.pi_opcode_base =
173         /*  is 10 in pro_line.h but should be 13 in DWARF3
174             and later. */
175         OPCODE_BASE;
176     dbg->de_line_inits.pi_line_base =
177         /* is -1 in pro_line.h */
178         LINE_BASE;
179     dbg->de_line_inits.pi_line_range =
180         /* is 4 in pro_line.h */
181         LINE_RANGE;
182 
183     /*  Applies to line table and everywhere else
184         for a CU. */
185     dbg->de_line_inits.pi_address_size = dbg->de_pointer_size;
186 
187     /*  Assuming no segments. */
188     dbg->de_line_inits.pi_segment_selector_size = 0;
189     dbg->de_line_inits.pi_segment_size = 0;
190 }
191 
192 
193 /*  Ask to emit DW_LNE_set_address opcode explicitly. Used by be
194     to emit start of a new .text section, or to force a relocated
195     address into debug line information entry. */
196 Dwarf_Unsigned
197 dwarf_lne_set_address(Dwarf_P_Debug dbg,
198     Dwarf_Addr offs,
199     Dwarf_Unsigned symidx, Dwarf_Error * error)
200 {
201     int res = 0;
202 
203     res = dwarf_lne_set_address_a(dbg,offs,symidx,error);
204     if (res != DW_DLV_OK) {
205         return DW_DLV_NOCOUNT;
206     }
207     return 0;
208 
209 }
210 int
211 dwarf_lne_set_address_a(Dwarf_P_Debug dbg,
212     Dwarf_Addr offs,
213     Dwarf_Unsigned symidx, Dwarf_Error * error)
214 {
215     int            retval = 0;
216     Dwarf_Ubyte    opc = 0;
217     Dwarf_Unsigned file_index = 0;
218     Dwarf_Unsigned line_no = 0;
219     Dwarf_Signed   col_no = 0;
220     Dwarf_Bool     is_stmt = 0;
221     Dwarf_Bool     is_bb = 0;
222     Dwarf_Bool     isepilbeg = 0;
223     Dwarf_Bool     isprolend  = 0;
224     Dwarf_Unsigned isa = 0;
225     Dwarf_Unsigned discriminator = 0;
226 
227 
228     opc = DW_LNE_set_address;
229     retval = _dwarf_pro_add_line_entry(dbg, file_index, offs,
230         symidx,
231         line_no, col_no, is_stmt,
232         is_bb,
233         opc,
234         isepilbeg, isprolend, isa, discriminator,
235         error);
236     return retval;
237 }
238 
239 /*  Ask to emit end_seqence opcode. Used normally at the end of a
240     compilation unit. Can also be used in the middle if there
241     are gaps in the region described by the code address.  */
242 Dwarf_Unsigned
243 dwarf_lne_end_sequence(Dwarf_P_Debug dbg,
244     Dwarf_Addr end_address, Dwarf_Error * error)
245 {
246     int retval = 0;
247 
248     retval = dwarf_lne_end_sequence_a(dbg,end_address,error);
249     if (retval != DW_DLV_OK) {
250         return DW_DLV_NOCOUNT;
251     }
252     return 0;
253 }
254 int
255 dwarf_lne_end_sequence_a(Dwarf_P_Debug dbg,
256     Dwarf_Addr end_address, Dwarf_Error * error)
257 {
258     Dwarf_Ubyte    opc = 0;
259     int retval = 0;
260     Dwarf_Unsigned file_index = 0;
261     Dwarf_Unsigned symidx = 0;
262     Dwarf_Unsigned line_no = 0;
263     Dwarf_Bool     is_stmt = 0;
264     Dwarf_Bool     is_bb = 0;
265     Dwarf_Signed   col_no = 0;/* Wrong, should be unsigned. */
266     Dwarf_Bool     isepilbeg = 0;
267     Dwarf_Bool     isprolend  = 0;
268     Dwarf_Unsigned isa = 0;
269     Dwarf_Unsigned discriminator = 0;
270 
271     opc = DW_LNE_end_sequence;
272     retval = _dwarf_pro_add_line_entry(dbg, file_index, end_address,
273         symidx,
274         line_no, col_no, is_stmt,
275         is_bb,
276         opc,
277         isepilbeg, isprolend, isa, discriminator,
278         error);
279     return retval;
280 }
281 
282 /* As of December 2018 this returns DW_DLV_OK, DW_DLV_ERROR
283     not 0, DW_DLV_NOCOUNT*/
284 /*  Add an entry in the internal list of lines mantained by producer.
285     Opc indicates if an opcode needs to be generated, rather than just
286     an entry in the matrix. During opcodes generation time, these
287     opcodes will be used. */
288 static int
289 _dwarf_pro_add_line_entry(Dwarf_P_Debug dbg,
290     Dwarf_Unsigned file_index,
291     Dwarf_Addr code_address,
292     Dwarf_Unsigned symidx,
293     Dwarf_Unsigned line_no,
294     Dwarf_Signed col_no,
295     Dwarf_Bool is_stmt_begin,
296     Dwarf_Bool is_bb_begin,
297     Dwarf_Ubyte opc,
298     Dwarf_Bool isepilbeg,
299     Dwarf_Bool isprolend,
300     Dwarf_Unsigned isa,
301     Dwarf_Unsigned discriminator,
302     Dwarf_Error * error)
303 {
304     if (dbg->de_lines == NULL) {
305         dbg->de_lines = (Dwarf_P_Line)
306             _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Line_s));
307         if (dbg->de_lines == NULL) {
308             DWARF_P_DBG_ERROR(dbg, DW_DLE_LINE_ALLOC, DW_DLV_ERROR);
309         }
310         dbg->de_last_line = dbg->de_lines;
311         _dwarf_pro_reg_init(dbg,dbg->de_lines);
312 
313     } else {
314         dbg->de_last_line->dpl_next = (Dwarf_P_Line)
315             _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Line_s));
316         if (dbg->de_last_line->dpl_next == NULL) {
317             DWARF_P_DBG_ERROR(dbg, DW_DLE_LINE_ALLOC, DW_DLV_ERROR);
318         }
319         dbg->de_last_line = dbg->de_last_line->dpl_next;
320         _dwarf_pro_reg_init(dbg,dbg->de_last_line);
321     }
322     dbg->de_last_line->dpl_address = code_address;
323     dbg->de_last_line->dpl_file = (unsigned long) file_index;
324     dbg->de_last_line->dpl_line = (unsigned long) line_no;
325     dbg->de_last_line->dpl_column = (unsigned long) col_no;
326     dbg->de_last_line->dpl_is_stmt = is_stmt_begin;
327     dbg->de_last_line->dpl_basic_block = is_bb_begin;
328     dbg->de_last_line->dpl_opc = opc;
329     dbg->de_last_line->dpl_r_symidx = symidx;
330     dbg->de_last_line->dpl_prologue_end = isprolend;
331     dbg->de_last_line->dpl_epilogue_begin = isepilbeg;
332     dbg->de_last_line->dpl_isa = isa;
333     dbg->de_last_line->dpl_discriminator = discriminator;
334     return DW_DLV_OK;
335 }
336 
337 /*  Add a directory declaration to the debug_line section. Stored
338     in linked list. */
339 Dwarf_Unsigned
340 dwarf_add_directory_decl(Dwarf_P_Debug dbg,
341     char *name,
342     Dwarf_Error * error)
343 {
344     Dwarf_Unsigned index = 0;
345     int res = 0;
346     /* DW_DLV_NOCOUNT on error, de_n_inc_dirs on success. */
347 
348     res = dwarf_add_directory_decl_a(dbg,name,&index,error);
349     if (res != DW_DLV_OK) {
350         return (Dwarf_Unsigned)DW_DLV_NOCOUNT;
351     }
352     return index;
353 }
354 int
355 dwarf_add_directory_decl_a(Dwarf_P_Debug dbg,
356     char *name,
357     Dwarf_Unsigned *index_in_directories,
358     Dwarf_Error * error)
359 {
360     if (dbg->de_inc_dirs == NULL) {
361         dbg->de_inc_dirs = (Dwarf_P_F_Entry)
362             _dwarf_p_get_alloc(dbg,
363             sizeof(struct Dwarf_P_F_Entry_s));
364         if (dbg->de_inc_dirs == NULL) {
365             DWARF_P_DBG_ERROR(dbg, DW_DLE_INCDIR_ALLOC,
366                 DW_DLV_ERROR);
367         }
368         dbg->de_last_inc_dir = dbg->de_inc_dirs;
369         dbg->de_n_inc_dirs = 1;
370     } else {
371         dbg->de_last_inc_dir->dfe_next = (Dwarf_P_F_Entry)
372             _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_F_Entry_s));
373         if (dbg->de_last_inc_dir->dfe_next == NULL) {
374             DWARF_P_DBG_ERROR(dbg, DW_DLE_INCDIR_ALLOC,
375                 DW_DLV_ERROR);
376         }
377         dbg->de_last_inc_dir = dbg->de_last_inc_dir->dfe_next;
378         dbg->de_n_inc_dirs++;
379     }
380     dbg->de_last_inc_dir->dfe_name =
381         (char *) _dwarf_p_get_alloc(dbg, strlen(name) + 1);
382     if (dbg->de_last_inc_dir->dfe_name == NULL) {
383         DWARF_P_DBG_ERROR(dbg, DW_DLE_STRING_ALLOC, DW_DLV_ERROR);
384     }
385     strcpy(dbg->de_last_inc_dir->dfe_name, name);
386     dbg->de_last_inc_dir->dfe_next = NULL;
387 
388     *index_in_directories = dbg->de_n_inc_dirs;
389     return DW_DLV_OK;
390 }
391 
392 /*  Add a file entry declaration to the debug_line section. Stored
393     in linked list. The data is immediately encoded as leb128
394     and stored in Dwarf_P_F_Entry_s struct. */
395 Dwarf_Unsigned
396 dwarf_add_file_decl(Dwarf_P_Debug dbg,
397     char *name,
398     Dwarf_Unsigned dir_idx,
399     Dwarf_Unsigned time_mod,
400     Dwarf_Unsigned length,
401     Dwarf_Error * error)
402 {
403     Dwarf_Unsigned filecount = 0;
404     int res = 0;
405 
406     res = dwarf_add_file_decl_a(dbg,name,dir_idx,
407         time_mod,length,&filecount,error);
408     if (res != DW_DLV_OK) {
409         return DW_DLV_NOCOUNT;
410     }
411     return filecount;
412 }
413 int
414 dwarf_add_file_decl_a(Dwarf_P_Debug dbg,
415     char *name,
416     Dwarf_Unsigned dir_idx,
417     Dwarf_Unsigned time_mod,
418     Dwarf_Unsigned length,
419     Dwarf_Unsigned *file_entry_count_out,
420     Dwarf_Error * error)
421 {
422     Dwarf_P_F_Entry cur;
423     char *ptr = 0;
424     int nbytes_idx, nbytes_time, nbytes_len;
425     char buffidx[ENCODE_SPACE_NEEDED];
426     char bufftime[ENCODE_SPACE_NEEDED];
427     char bufflen[ENCODE_SPACE_NEEDED];
428     int res = 0;
429 
430     if (dbg->de_file_entries == NULL) {
431         dbg->de_file_entries = (Dwarf_P_F_Entry)
432             _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_F_Entry_s));
433         if (dbg->de_file_entries == NULL) {
434             DWARF_P_DBG_ERROR(dbg, DW_DLE_FILE_ENTRY_ALLOC,
435                 DW_DLV_ERROR);
436         }
437         cur = dbg->de_file_entries;
438         dbg->de_last_file_entry = cur;
439         dbg->de_n_file_entries = 1;
440     } else {
441         cur = dbg->de_last_file_entry;
442         cur->dfe_next = (Dwarf_P_F_Entry)
443             _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_F_Entry_s));
444         if (cur->dfe_next == NULL) {
445             DWARF_P_DBG_ERROR(dbg, DW_DLE_FILE_ENTRY_ALLOC,
446                 DW_DLV_ERROR);
447         }
448         cur = cur->dfe_next;
449         dbg->de_last_file_entry = cur;
450         dbg->de_n_file_entries++;
451     }
452     cur->dfe_name = (char *) _dwarf_p_get_alloc(dbg, strlen(name) + 1);
453     if (cur->dfe_name == NULL) {
454         DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_ERROR);
455     }
456     strcpy((char *) cur->dfe_name, name);
457     res = _dwarf_pro_encode_leb128_nm(dir_idx, &nbytes_idx,
458         buffidx, sizeof(buffidx));
459     if (res != DW_DLV_OK) {
460         /* DW_DLV_NO_ENTRY impossible */
461         DWARF_P_DBG_ERROR(dbg, DW_DLE_LEB_OUT_ERROR, DW_DLV_ERROR);
462     }
463     res = _dwarf_pro_encode_leb128_nm(time_mod, &nbytes_time,
464         bufftime, sizeof(bufftime));
465     if (res != DW_DLV_OK) {
466         /* DW_DLV_NO_ENTRY impossible */
467         DWARF_P_DBG_ERROR(dbg, DW_DLE_LEB_OUT_ERROR, DW_DLV_ERROR);
468     }
469     res = _dwarf_pro_encode_leb128_nm(length, &nbytes_len,
470         bufflen, sizeof(bufflen));
471     if (res != DW_DLV_OK) {
472         /* DW_DLV_NO_ENTRY impossible */
473         DWARF_P_DBG_ERROR(dbg,DW_DLE_LEB_OUT_ERROR,DW_DLV_ERROR);
474     }
475     cur->dfe_args = (char *)
476         _dwarf_p_get_alloc(dbg, nbytes_idx + nbytes_time + nbytes_len);
477     if (cur->dfe_args == NULL) {
478         DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_ERROR);
479     }
480     ptr = cur->dfe_args;
481     memcpy((void *) ptr, buffidx, nbytes_idx);
482     ptr += nbytes_idx;
483     memcpy((void *) ptr, bufftime, nbytes_time);
484     ptr += nbytes_time;
485     memcpy((void *) ptr, bufflen, nbytes_len);
486     cur->dfe_nbytes = nbytes_idx + nbytes_time + nbytes_len;
487     cur->dfe_next = NULL;
488     *file_entry_count_out = dbg->de_n_file_entries;
489     return DW_DLV_OK;
490 }
491 
492 
493 /*  Initialize a row of the matrix for line numbers, meaning
494     initialize the struct corresponding to it */
495 void
496 _dwarf_pro_reg_init(Dwarf_P_Debug dbg, Dwarf_P_Line cur_line)
497 {
498     cur_line->dpl_address = 0;
499     cur_line->dpl_file = 1;
500     cur_line->dpl_line = 1;
501     cur_line->dpl_column = 0;
502     cur_line->dpl_is_stmt = dbg->de_line_inits.pi_default_is_stmt;
503     cur_line->dpl_basic_block = false;
504     cur_line->dpl_next = NULL;
505     cur_line->dpl_prologue_end = 0;
506     cur_line->dpl_epilogue_begin = 0;
507     cur_line->dpl_isa = 0;
508     cur_line->dpl_discriminator = 0;
509     cur_line->dpl_opc = 0;
510 }
511