1 /* $NetBSD: libdwarf_lineno.c,v 1.5 2024/03/03 17:37:32 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2009,2010,2023 Kai Wang
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include "_libdwarf.h"
30
31 __RCSID("$NetBSD: libdwarf_lineno.c,v 1.5 2024/03/03 17:37:32 christos Exp $");
32 ELFTC_VCSID("Id: libdwarf_lineno.c 4019 2023-10-22 03:06:17Z kaiwang27");
33
34 static int
_dwarf_lineno_make_fullpath(Dwarf_Debug dbg,Dwarf_LineInfo li,Dwarf_LineFile lf,const char * compdir,Dwarf_Error * error)35 _dwarf_lineno_make_fullpath(Dwarf_Debug dbg, Dwarf_LineInfo li,
36 Dwarf_LineFile lf, const char *compdir, Dwarf_Error *error)
37 {
38 const char *dirname;
39 int slen;
40
41 /* Make full pathname if need. */
42 if (*lf->lf_fname != '/') {
43 dirname = compdir;
44 if (lf->lf_dirndx > 0)
45 dirname = li->li_incdirs[lf->lf_dirndx - 1];
46 if (dirname != NULL) {
47 slen = strlen(dirname) + strlen(lf->lf_fname) + 2;
48 if ((lf->lf_fullpath = malloc(slen)) == NULL) {
49 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
50 return (DW_DLE_MEMORY);
51 }
52 snprintf(lf->lf_fullpath, slen, "%s/%s", dirname,
53 lf->lf_fname);
54 }
55 }
56
57 return (DW_DLE_NONE);
58 }
59
60 static int
_dwarf_lineno_add_file(Dwarf_LineInfo li,uint8_t ** p,const char * compdir,Dwarf_Error * error,Dwarf_Debug dbg)61 _dwarf_lineno_add_file(Dwarf_LineInfo li, uint8_t **p, const char *compdir,
62 Dwarf_Error *error, Dwarf_Debug dbg)
63 {
64 Dwarf_LineFile lf;
65 uint8_t *src;
66 int ret;
67
68 src = *p;
69
70 if ((lf = malloc(sizeof(struct _Dwarf_LineFile))) == NULL) {
71 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
72 return (DW_DLE_MEMORY);
73 }
74
75 lf->lf_fullpath = NULL;
76 lf->lf_fname = (char *) src;
77 src += strlen(lf->lf_fname) + 1;
78 lf->lf_dirndx = _dwarf_decode_uleb128(&src);
79 if (lf->lf_dirndx > li->li_inclen) {
80 free(lf);
81 DWARF_SET_ERROR(dbg, error, DW_DLE_DIR_INDEX_BAD);
82 return (DW_DLE_DIR_INDEX_BAD);
83 }
84
85 ret = _dwarf_lineno_make_fullpath(dbg, li, lf, compdir, error);
86 if (ret != DW_DLE_NONE) {
87 free(lf);
88 return (ret);
89 }
90
91 lf->lf_mtime = _dwarf_decode_uleb128(&src);
92 lf->lf_size = _dwarf_decode_uleb128(&src);
93 STAILQ_INSERT_TAIL(&li->li_lflist, lf, lf_next);
94 li->li_lflen++;
95
96 *p = src;
97
98 return (DW_DLE_NONE);
99 }
100
101 static int
_dwarf_lineno_run_program(Dwarf_CU cu,Dwarf_LineInfo li,uint8_t * p,uint8_t * pe,const char * compdir,Dwarf_Error * error)102 _dwarf_lineno_run_program(Dwarf_CU cu, Dwarf_LineInfo li, uint8_t *p,
103 uint8_t *pe, const char *compdir, Dwarf_Error *error)
104 {
105 Dwarf_Debug dbg;
106 Dwarf_Line ln, tln;
107 uint64_t address, file, line, column, opsize;
108 int is_stmt, basic_block, end_sequence;
109 int ret;
110
111 #define RESET_REGISTERS \
112 do { \
113 address = 0; \
114 file = 1; \
115 line = 1; \
116 column = 0; \
117 is_stmt = li->li_defstmt; \
118 basic_block = 0; \
119 end_sequence = 0; \
120 } while(0)
121
122 #define APPEND_ROW \
123 do { \
124 ln = malloc(sizeof(struct _Dwarf_Line)); \
125 if (ln == NULL) { \
126 ret = DW_DLE_MEMORY; \
127 DWARF_SET_ERROR(dbg, error, ret); \
128 goto prog_fail; \
129 } \
130 ln->ln_li = li; \
131 ln->ln_addr = address; \
132 ln->ln_symndx = 0; \
133 ln->ln_fileno = file; \
134 ln->ln_lineno = line; \
135 ln->ln_column = column; \
136 ln->ln_bblock = basic_block; \
137 ln->ln_stmt = is_stmt; \
138 ln->ln_endseq = end_sequence; \
139 STAILQ_INSERT_TAIL(&li->li_lnlist, ln, ln_next);\
140 li->li_lnlen++; \
141 } while(0)
142
143 #define LINE(x) (li->li_lbase + (((x) - li->li_opbase) % li->li_lrange))
144 #define ADDRESS(x) ((((x) - li->li_opbase) / li->li_lrange) * li->li_minlen)
145
146 dbg = cu->cu_dbg;
147
148 /*
149 * Set registers to their default values.
150 */
151 RESET_REGISTERS;
152
153 /*
154 * Start line number program.
155 */
156 while (p < pe) {
157 if (*p == 0) {
158
159 /*
160 * Extended Opcodes.
161 */
162
163 p++;
164 opsize = _dwarf_decode_uleb128(&p);
165 switch (*p) {
166 case DW_LNE_end_sequence:
167 p++;
168 end_sequence = 1;
169 APPEND_ROW;
170 RESET_REGISTERS;
171 break;
172 case DW_LNE_set_address:
173 p++;
174 address = dbg->decode(&p, cu->cu_pointer_size);
175 break;
176 case DW_LNE_define_file:
177 p++;
178 ret = _dwarf_lineno_add_file(li, &p, compdir,
179 error, dbg);
180 if (ret != DW_DLE_NONE)
181 goto prog_fail;
182 break;
183 default:
184 /* Unrecognized extened opcodes. */
185 p += opsize;
186 }
187
188 } else if (*p > 0 && *p < li->li_opbase) {
189
190 /*
191 * Standard Opcodes.
192 */
193
194 switch (*p++) {
195 case DW_LNS_copy:
196 APPEND_ROW;
197 basic_block = 0;
198 break;
199 case DW_LNS_advance_pc:
200 address += _dwarf_decode_uleb128(&p) *
201 li->li_minlen;
202 break;
203 case DW_LNS_advance_line:
204 line += _dwarf_decode_sleb128(&p);
205 break;
206 case DW_LNS_set_file:
207 file = _dwarf_decode_uleb128(&p);
208 break;
209 case DW_LNS_set_column:
210 column = _dwarf_decode_uleb128(&p);
211 break;
212 case DW_LNS_negate_stmt:
213 is_stmt = !is_stmt;
214 break;
215 case DW_LNS_set_basic_block:
216 basic_block = 1;
217 break;
218 case DW_LNS_const_add_pc:
219 address += ADDRESS(255);
220 break;
221 case DW_LNS_fixed_advance_pc:
222 address += dbg->decode(&p, 2);
223 break;
224 case DW_LNS_set_prologue_end:
225 break;
226 case DW_LNS_set_epilogue_begin:
227 break;
228 case DW_LNS_set_isa:
229 (void) _dwarf_decode_uleb128(&p);
230 break;
231 default:
232 /* Unrecognized extened opcodes. What to do? */
233 break;
234 }
235
236 } else {
237
238 /*
239 * Special Opcodes.
240 */
241
242 line += LINE(*p);
243 address += ADDRESS(*p);
244 APPEND_ROW;
245 basic_block = 0;
246 p++;
247 }
248 }
249
250 return (DW_DLE_NONE);
251
252 prog_fail:
253
254 STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
255 STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next);
256 free(ln);
257 }
258
259 return (ret);
260
261 #undef RESET_REGISTERS
262 #undef APPEND_ROW
263 #undef LINE
264 #undef ADDRESS
265 }
266
267 struct lnct {
268 unsigned type;
269 unsigned form;
270 };
271
272
273 static int
_dwarf_lineno_parse_lnct_desc(Dwarf_Debug dbg,int fmt,struct lnct ** lnct,uint8_t * data,uint64_t * offsetp,Dwarf_Error * error)274 _dwarf_lineno_parse_lnct_desc(Dwarf_Debug dbg, int fmt, struct lnct **lnct,
275 uint8_t *data, uint64_t *offsetp, Dwarf_Error *error)
276 {
277 int i;
278
279 if (fmt == 0) {
280 *lnct = NULL;
281 return (DW_DLE_NONE);
282 }
283
284 if ((*lnct = calloc(fmt, sizeof(struct lnct))) == NULL) {
285 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
286 return (DW_DLE_MEMORY);
287 }
288 for (i = 0; i < fmt; i++) {
289 (*lnct)[i].type = _dwarf_read_uleb128(data, offsetp);
290 (*lnct)[i].form = _dwarf_read_uleb128(data, offsetp);
291 }
292
293 return (DW_DLE_NONE);
294 }
295
296 static int
_dwarf_lineno_lnct_path(Dwarf_Debug dbg,char ** fname,unsigned form,uint8_t * data,uint64_t size,uint64_t * offsetp,int dwarf_size,Dwarf_Error * error)297 _dwarf_lineno_lnct_path(Dwarf_Debug dbg, char **fname, unsigned form,
298 uint8_t *data, uint64_t size, uint64_t *offsetp, int dwarf_size,
299 Dwarf_Error *error)
300 {
301 Dwarf_Unsigned sp;
302 int ret;
303
304 ret = DW_DLE_NONE;
305
306 switch (form) {
307 case DW_FORM_string:
308 *fname = _dwarf_read_string(data, size, offsetp);
309 break;
310 case DW_FORM_strp:
311 sp = dbg->read(data, offsetp, dwarf_size);
312 *fname = _dwarf_strtab_get_table(dbg) + sp;
313 break;
314 case DW_FORM_line_strp:
315 sp = dbg->read(data, offsetp, dwarf_size);
316 *fname = _dwarf_strtab_get_line_table(dbg) + sp;
317 break;
318 case DW_FORM_strp_sup:
319 sp = dbg->read(data, offsetp, dwarf_size);
320 *fname = NULL; /* TODO: support sup string table. */
321 break;
322 default:
323 ret = DW_DLE_LNCT_DESC_BAD;
324 DWARF_SET_ERROR(dbg, error, ret);
325 break;
326 }
327
328 return (ret);
329 }
330
331 static int
_dwarf_lineno_lnct_dirndx(Dwarf_Debug dbg,Dwarf_Unsigned * dirndx,unsigned form,uint8_t * data,uint64_t * offsetp,Dwarf_Error * error)332 _dwarf_lineno_lnct_dirndx(Dwarf_Debug dbg, Dwarf_Unsigned *dirndx,
333 unsigned form, uint8_t *data, uint64_t *offsetp, Dwarf_Error *error)
334 {
335 int ret;
336
337 ret = DW_DLE_NONE;
338
339 switch (form) {
340 case DW_FORM_data1:
341 *dirndx = dbg->read(data, offsetp, 1);
342 break;
343 case DW_FORM_data2:
344 *dirndx = dbg->read(data, offsetp, 2);
345 break;
346 case DW_FORM_udata:
347 *dirndx = _dwarf_read_uleb128(data, offsetp);
348 break;
349 default:
350 ret = DW_DLE_LNCT_DESC_BAD;
351 DWARF_SET_ERROR(dbg, error, ret);
352 break;
353 }
354
355 return (ret);
356 }
357
358 static int
_dwarf_lineno_lnct_timestamp(Dwarf_Debug dbg,Dwarf_Unsigned * ts,unsigned form,uint8_t * data,uint64_t * offsetp,Dwarf_Error * error)359 _dwarf_lineno_lnct_timestamp(Dwarf_Debug dbg, Dwarf_Unsigned *ts,
360 unsigned form, uint8_t *data, uint64_t *offsetp, Dwarf_Error *error)
361 {
362 int ret;
363
364 ret = DW_DLE_NONE;
365
366 switch (form) {
367 case DW_FORM_udata:
368 *ts = _dwarf_read_uleb128(data, offsetp);
369 break;
370 case DW_FORM_data4:
371 *ts = dbg->read(data, offsetp, 4);
372 break;
373 case DW_FORM_data8:
374 *ts = dbg->read(data, offsetp, 8);
375 break;
376 case DW_FORM_block:
377 /* TODO: Not supported. */
378 default:
379 ret = DW_DLE_LNCT_DESC_BAD;
380 DWARF_SET_ERROR(dbg, error, ret);
381 break;
382 }
383
384 return (ret);
385 }
386
387 static int
_dwarf_lineno_lnct_size(Dwarf_Debug dbg,Dwarf_Unsigned * sz,unsigned form,uint8_t * data,uint64_t * offsetp,Dwarf_Error * error)388 _dwarf_lineno_lnct_size(Dwarf_Debug dbg, Dwarf_Unsigned *sz, unsigned form,
389 uint8_t *data, uint64_t *offsetp, Dwarf_Error *error)
390 {
391 int ret;
392
393 ret = DW_DLE_NONE;
394
395 switch (form) {
396 case DW_FORM_udata:
397 *sz = _dwarf_read_uleb128(data, offsetp);
398 break;
399 case DW_FORM_data1:
400 *sz = dbg->read(data, offsetp, 1);
401 break;
402 case DW_FORM_data2:
403 *sz = dbg->read(data, offsetp, 2);
404 break;
405 case DW_FORM_data4:
406 *sz = dbg->read(data, offsetp, 4);
407 break;
408 case DW_FORM_data8:
409 *sz = dbg->read(data, offsetp, 8);
410 break;
411 default:
412 ret = DW_DLE_LNCT_DESC_BAD;
413 DWARF_SET_ERROR(dbg, error, ret);
414 break;
415 }
416
417 return (ret);
418 }
419
420 static int
_dwarf_lineno_lnct_md5(Dwarf_Debug dbg,Dwarf_Form_Data16 * md5,unsigned form,uint8_t * data,uint64_t * offsetp,Dwarf_Error * error)421 _dwarf_lineno_lnct_md5(Dwarf_Debug dbg, Dwarf_Form_Data16 *md5,
422 unsigned form, uint8_t *data, uint64_t *offsetp, Dwarf_Error *error)
423 {
424
425 if (form != DW_FORM_data16) {
426 DWARF_SET_ERROR(dbg, error, DW_DLE_LNCT_DESC_BAD);
427 return (DW_DLE_LNCT_DESC_BAD);
428 }
429
430 memcpy(md5->fd_data, data + *offsetp, 16);
431 offsetp += 16;
432
433 return (DW_DLE_NONE);
434 }
435
436 int
_dwarf_lineno_init(Dwarf_Die die,uint64_t offset,Dwarf_Error * error)437 _dwarf_lineno_init(Dwarf_Die die, uint64_t offset, Dwarf_Error *error)
438 {
439 Dwarf_Debug dbg;
440 Dwarf_Section *ds;
441 Dwarf_CU cu;
442 Dwarf_Attribute at;
443 Dwarf_LineInfo li;
444 Dwarf_LineFile lf, tlf;
445 struct lnct *lnct;
446 const char *compdir;
447 uint64_t length, hdroff, endoff;
448 uint8_t *p;
449 int dwarf_size, fmt, i, j, ret;
450
451 cu = die->die_cu;
452 assert(cu != NULL);
453
454 dbg = cu->cu_dbg;
455 assert(dbg != NULL);
456
457 if ((ds = _dwarf_find_section(dbg, ".debug_line")) == NULL)
458 return (DW_DLE_NONE);
459
460 /*
461 * Try to find out the dir where the CU was compiled. Later we
462 * will use the dir to create full pathnames, if need.
463 */
464 compdir = NULL;
465 at = _dwarf_attr_find(die, DW_AT_comp_dir);
466 if (at != NULL) {
467 switch (at->at_form) {
468 case DW_FORM_strp:
469 case DW_FORM_strp_sup:
470 case DW_FORM_line_strp:
471 compdir = at->u[1].s;
472 break;
473 case DW_FORM_string:
474 compdir = at->u[0].s;
475 break;
476 default:
477 break;
478 }
479 }
480
481 length = dbg->read(ds->ds_data, &offset, 4);
482 if (length == 0xffffffff) {
483 dwarf_size = 8;
484 length = dbg->read(ds->ds_data, &offset, 8);
485 } else
486 dwarf_size = 4;
487
488 if (length > ds->ds_size - offset) {
489 DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD);
490 return (DW_DLE_DEBUG_LINE_LENGTH_BAD);
491 }
492
493 if ((li = calloc(1, sizeof(struct _Dwarf_LineInfo))) == NULL) {
494 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
495 return (DW_DLE_MEMORY);
496 }
497
498 /*
499 * Read in line number program header.
500 */
501 li->li_length = length;
502 endoff = offset + length;
503 li->li_version = dbg->read(ds->ds_data, &offset, 2);
504 if (li->li_version == 5) {
505 (void) dbg->read(ds->ds_data, &offset, 1); /* TODO */
506 (void) dbg->read(ds->ds_data, &offset, 1); /* TODO */
507 }
508 li->li_hdrlen = dbg->read(ds->ds_data, &offset, dwarf_size);
509 hdroff = offset;
510 li->li_minlen = dbg->read(ds->ds_data, &offset, 1);
511 if (li->li_version >= 4)
512 li->li_maxop = dbg->read(ds->ds_data, &offset, 1);
513 li->li_defstmt = dbg->read(ds->ds_data, &offset, 1);
514 li->li_lbase = dbg->read(ds->ds_data, &offset, 1);
515 li->li_lrange = dbg->read(ds->ds_data, &offset, 1);
516 li->li_opbase = dbg->read(ds->ds_data, &offset, 1);
517 STAILQ_INIT(&li->li_lflist);
518 STAILQ_INIT(&li->li_lnlist);
519
520 if ((int)li->li_hdrlen - 5 < li->li_opbase - 1) {
521 ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
522 DWARF_SET_ERROR(dbg, error, ret);
523 goto fail_cleanup;
524 }
525
526 if ((li->li_oplen = malloc(li->li_opbase)) == NULL) {
527 ret = DW_DLE_MEMORY;
528 DWARF_SET_ERROR(dbg, error, ret);
529 goto fail_cleanup;
530 }
531
532 /*
533 * Read in std opcode arg length list. Note that the first
534 * element is not used.
535 */
536 for (i = 1; i < li->li_opbase; i++)
537 li->li_oplen[i] = dbg->read(ds->ds_data, &offset, 1);
538
539 /*
540 * Directory and filename parser for DWARF4 and below.
541 */
542 if (li->li_version <= 4) {
543
544 /*
545 * Check how many strings in the include dir string array.
546 */
547 length = 0;
548 p = ds->ds_data + offset;
549 while (*p != '\0') {
550 while (*p++ != '\0')
551 ;
552 length++;
553 }
554 li->li_inclen = length;
555
556 /* Sanity check. */
557 if (p - ds->ds_data > (int) ds->ds_size) {
558 ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
559 DWARF_SET_ERROR(dbg, error, ret);
560 goto fail_cleanup;
561 }
562
563 if (length != 0) {
564 if ((li->li_incdirs = malloc(length * sizeof(char *))) ==
565 NULL) {
566 ret = DW_DLE_MEMORY;
567 DWARF_SET_ERROR(dbg, error, ret);
568 goto fail_cleanup;
569 }
570 }
571
572 /* Fill in include dir array. */
573 i = 0;
574 p = ds->ds_data + offset;
575 while (*p != '\0') {
576 li->li_incdirs[i++] = (char *) p;
577 while (*p++ != '\0')
578 ;
579 }
580
581 p++;
582
583 /*
584 * Process file list.
585 */
586 while (*p != '\0') {
587 ret = _dwarf_lineno_add_file(li, &p, compdir, error, dbg);
588 if (ret != DW_DLE_NONE)
589 goto fail_cleanup;
590 if (p - ds->ds_data > (int) ds->ds_size) {
591 ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
592 DWARF_SET_ERROR(dbg, error, ret);
593 goto fail_cleanup;
594 }
595 }
596
597 p++;
598
599 /* Sanity check. */
600 if (p - ds->ds_data - hdroff != li->li_hdrlen) {
601 ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
602 DWARF_SET_ERROR(dbg, error, ret);
603 goto fail_cleanup;
604 }
605
606 goto lnprog;
607 }
608
609 /*
610 * DWARF5 has completely overhauled the dir/source file information
611 * fields, which are incompatible with DWARF4 or lower.
612 */
613
614 lnct = NULL;
615 fmt = dbg->read(ds->ds_data, &offset, 1);
616 if ((ret = _dwarf_lineno_parse_lnct_desc(dbg, fmt, &lnct, ds->ds_data,
617 &offset, error)) != DW_DLE_NONE)
618 goto fail_cleanup;
619
620 li->li_inclen = dbg->read(ds->ds_data, &offset, 1);
621 if (li->li_inclen == 0) {
622 if (fmt > 0) {
623 free(lnct);
624 ret = DW_DLE_DIR_COUNT_BAD;
625 DWARF_SET_ERROR(dbg, error, ret);
626 goto fail_cleanup;
627 }
628
629 goto file_entries;
630 }
631
632 if (fmt == 0) {
633 ret = DW_DLE_DIR_COUNT_BAD;
634 DWARF_SET_ERROR(dbg, error, ret);
635 goto fail_cleanup;
636 }
637 if ((li->li_incdirs = malloc(length * sizeof(char *))) == NULL) {
638 free(lnct);
639 ret = DW_DLE_MEMORY;
640 DWARF_SET_ERROR(dbg, error, ret);
641 goto fail_cleanup;
642 }
643 for (i = 0; i < li->li_inclen; i++) {
644 for (j = 0; j < fmt; j++) {
645 if (lnct[j].type != DW_LNCT_path) {
646 free(lnct);
647 ret = DW_DLE_LNCT_DESC_BAD;
648 DWARF_SET_ERROR(dbg, error, ret);
649 goto fail_cleanup;
650 }
651
652 ret = _dwarf_lineno_lnct_path(dbg, &li->li_incdirs[i],
653 lnct[j].form, ds->ds_data, ds->ds_size, &offset,
654 dwarf_size, error);
655 if (ret != DW_DLE_NONE) {
656 free(lnct);
657 goto fail_cleanup;
658 }
659 }
660 }
661 if (lnct)
662 free(lnct);
663
664 file_entries:
665
666 lnct = NULL;
667 fmt = dbg->read(ds->ds_data, &offset, 1);
668 if ((ret = _dwarf_lineno_parse_lnct_desc(dbg, fmt, &lnct, ds->ds_data,
669 &offset, error)) != DW_DLE_NONE)
670 goto fail_cleanup;
671
672 li->li_lflen = dbg->read(ds->ds_data, &offset, 1);
673 if (li->li_lflen == 0) {
674 if (fmt > 0) {
675 free(lnct);
676 ret = DW_DLE_FILE_COUNT_BAD;
677 DWARF_SET_ERROR(dbg, error, ret);
678 goto fail_cleanup;
679 }
680
681 p = ds->ds_data + offset;
682 goto lnprog;
683 }
684
685 for (i = 0; i < li->li_lflen; i++) {
686 if ((lf = malloc(sizeof(struct _Dwarf_LineFile))) == NULL) {
687 free(lnct);
688 ret = DW_DLE_MEMORY;
689 DWARF_SET_ERROR(dbg, error, ret);
690 goto fail_cleanup;
691 }
692 for (j = 0; j < fmt; j++) {
693 switch (lnct[j].type) {
694 case DW_LNCT_path:
695 ret = _dwarf_lineno_lnct_path(dbg,
696 &lf->lf_fname, lnct[j].form, ds->ds_data,
697 ds->ds_size, &offset, dwarf_size, error);
698 break;
699 case DW_LNCT_directory_index:
700 ret = _dwarf_lineno_lnct_dirndx(dbg,
701 &lf->lf_dirndx, lnct[j].form, ds->ds_data,
702 &offset, error);
703 break;
704 case DW_LNCT_timestamp:
705 ret = _dwarf_lineno_lnct_timestamp(dbg,
706 &lf->lf_mtime, lnct[j].form, ds->ds_data,
707 &offset, error);
708 break;
709 case DW_LNCT_size:
710 ret = _dwarf_lineno_lnct_size(dbg,
711 &lf->lf_size, lnct[j].form, ds->ds_data,
712 &offset, error);
713 break;
714 case DW_LNCT_MD5:
715 ret = _dwarf_lineno_lnct_md5(dbg,
716 &lf->lf_md5, lnct[j].form, ds->ds_data,
717 &offset, error);
718 break;
719 default:
720 ret = DW_DLE_LNCT_DESC_BAD;
721 DWARF_SET_ERROR(dbg, error, ret);
722 break;
723 }
724 if (ret != DW_DLE_NONE) {
725 free(lf);
726 free(lnct);
727 goto fail_cleanup;
728 }
729 }
730 ret = _dwarf_lineno_make_fullpath(dbg, li, lf, compdir, error);
731 if (ret != DW_DLE_NONE) {
732 free(lf);
733 free(lnct);
734 goto fail_cleanup;
735 }
736 STAILQ_INSERT_TAIL(&li->li_lflist, lf, lf_next);
737 }
738 if (lnct)
739 free(lnct);
740
741 p = ds->ds_data + offset;
742
743 lnprog:
744 /*
745 * Process line number program.
746 */
747 ret = _dwarf_lineno_run_program(cu, li, p, ds->ds_data + endoff, compdir,
748 error);
749 if (ret != DW_DLE_NONE)
750 goto fail_cleanup;
751
752 cu->cu_lineinfo = li;
753
754 return (DW_DLE_NONE);
755
756 fail_cleanup:
757
758 STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
759 STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile, lf_next);
760 if (lf->lf_fullpath)
761 free(lf->lf_fullpath);
762 free(lf);
763 }
764
765 if (li->li_oplen)
766 free(li->li_oplen);
767 if (li->li_incdirs)
768 free(li->li_incdirs);
769 free(li);
770
771 return (ret);
772 }
773
774 void
_dwarf_lineno_cleanup(Dwarf_LineInfo li)775 _dwarf_lineno_cleanup(Dwarf_LineInfo li)
776 {
777 Dwarf_LineFile lf, tlf;
778 Dwarf_Line ln, tln;
779
780 if (li == NULL)
781 return;
782 STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
783 STAILQ_REMOVE(&li->li_lflist, lf,
784 _Dwarf_LineFile, lf_next);
785 if (lf->lf_fullpath)
786 free(lf->lf_fullpath);
787 free(lf);
788 }
789 STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
790 STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line,
791 ln_next);
792 free(ln);
793 }
794 if (li->li_oplen)
795 free(li->li_oplen);
796 if (li->li_incdirs)
797 free(li->li_incdirs);
798 if (li->li_lnarray)
799 free(li->li_lnarray);
800 if (li->li_lfnarray)
801 free(li->li_lfnarray);
802 free(li);
803 }
804
805 static int
_dwarf_lineno_gen_program(Dwarf_P_Debug dbg,Dwarf_P_Section ds,Dwarf_Rel_Section drs,Dwarf_Error * error)806 _dwarf_lineno_gen_program(Dwarf_P_Debug dbg, Dwarf_P_Section ds,
807 Dwarf_Rel_Section drs, Dwarf_Error * error)
808 {
809 Dwarf_LineInfo li;
810 Dwarf_Line ln;
811 Dwarf_Unsigned address, file, line, spc;
812 Dwarf_Unsigned addr0, maddr;
813 Dwarf_Signed line0, column;
814 int is_stmt, basic_block;
815 int need_copy;
816 int ret;
817
818 #define RESET_REGISTERS \
819 do { \
820 address = 0; \
821 file = 1; \
822 line = 1; \
823 column = 0; \
824 is_stmt = li->li_defstmt; \
825 basic_block = 0; \
826 } while(0)
827
828 li = dbg->dbgp_lineinfo;
829 maddr = (255 - li->li_opbase) / li->li_lrange;
830
831 RESET_REGISTERS;
832
833 STAILQ_FOREACH(ln, &li->li_lnlist, ln_next) {
834 if (ln->ln_symndx > 0) {
835 /*
836 * Generate DW_LNE_set_address extended op.
837 */
838 RCHECK(WRITE_VALUE(0, 1));
839 RCHECK(WRITE_ULEB128(dbg->dbg_pointer_size + 1));
840 RCHECK(WRITE_VALUE(DW_LNE_set_address, 1));
841 RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds,
842 dwarf_drt_data_reloc, dbg->dbg_pointer_size,
843 ds->ds_size, ln->ln_symndx, ln->ln_addr,
844 NULL, error));
845 address = ln->ln_addr;
846 continue;
847 } else if (ln->ln_endseq) {
848 addr0 = (ln->ln_addr - address) / li->li_minlen;
849 if (addr0 != 0) {
850 RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1));
851 RCHECK(WRITE_ULEB128(addr0));
852 }
853
854 /*
855 * Generate DW_LNE_end_sequence.
856 */
857 RCHECK(WRITE_VALUE(0, 1));
858 RCHECK(WRITE_ULEB128(1));
859 RCHECK(WRITE_VALUE(DW_LNE_end_sequence, 1));
860 RESET_REGISTERS;
861 continue;
862 }
863
864 /*
865 * Generate standard opcodes for file, column, is_stmt or
866 * basic_block changes.
867 */
868 if (ln->ln_fileno != file) {
869 RCHECK(WRITE_VALUE(DW_LNS_set_file, 1));
870 RCHECK(WRITE_ULEB128(ln->ln_fileno));
871 file = ln->ln_fileno;
872 }
873 if (ln->ln_column != column) {
874 RCHECK(WRITE_VALUE(DW_LNS_set_column, 1));
875 RCHECK(WRITE_ULEB128(ln->ln_column));
876 column = ln->ln_column;
877 }
878 if (ln->ln_stmt != is_stmt) {
879 RCHECK(WRITE_VALUE(DW_LNS_negate_stmt, 1));
880 is_stmt = ln->ln_stmt;
881 }
882 if (ln->ln_bblock && !basic_block) {
883 RCHECK(WRITE_VALUE(DW_LNS_set_basic_block, 1));
884 basic_block = 1;
885 }
886
887 /*
888 * Calculate address and line number change.
889 */
890 addr0 = (ln->ln_addr - address) / li->li_minlen;
891 line0 = ln->ln_lineno - line;
892
893 if (addr0 == 0 && line0 == 0)
894 continue;
895
896 /*
897 * Check if line delta is with the range and if the special
898 * opcode can be used.
899 */
900 assert(li->li_lbase <= 0);
901 if (line0 >= li->li_lbase &&
902 line0 <= li->li_lbase + li->li_lrange - 1) {
903 spc = (line0 - li->li_lbase) +
904 (li->li_lrange * addr0) + li->li_opbase;
905 if (spc <= 255) {
906 RCHECK(WRITE_VALUE(spc, 1));
907 basic_block = 0;
908 goto next_line;
909 }
910 }
911
912 /* Generate DW_LNS_advance_line for line number change. */
913 if (line0 != 0) {
914 RCHECK(WRITE_VALUE(DW_LNS_advance_line, 1));
915 RCHECK(WRITE_SLEB128(line0));
916 line0 = 0;
917 need_copy = 1;
918 } else
919 need_copy = basic_block;
920
921 if (addr0 != 0) {
922 /* See if it can be handled by DW_LNS_const_add_pc. */
923 spc = (line0 - li->li_lbase) +
924 (li->li_lrange * (addr0 - maddr)) + li->li_opbase;
925 if (addr0 >= maddr && spc <= 255) {
926 RCHECK(WRITE_VALUE(DW_LNS_const_add_pc, 1));
927 RCHECK(WRITE_VALUE(spc, 1));
928 } else {
929 /* Otherwise we use DW_LNS_advance_pc. */
930 RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1));
931 RCHECK(WRITE_ULEB128(addr0));
932 }
933 }
934
935 if (need_copy) {
936 RCHECK(WRITE_VALUE(DW_LNS_copy, 1));
937 basic_block = 0;
938 }
939
940 next_line:
941 address = ln->ln_addr;
942 line = ln->ln_lineno;
943 }
944
945 return (DW_DLE_NONE);
946
947 gen_fail:
948 return (ret);
949
950 #undef RESET_REGISTERS
951 }
952
953 static uint8_t
_dwarf_get_minlen(Dwarf_P_Debug dbg)954 _dwarf_get_minlen(Dwarf_P_Debug dbg)
955 {
956
957 assert(dbg != NULL);
958
959 switch (dbg->dbgp_isa) {
960 case DW_ISA_ARM:
961 return (2);
962 case DW_ISA_X86:
963 case DW_ISA_X86_64:
964 return (1);
965 default:
966 return (4);
967 }
968 }
969
970 static uint8_t oplen[] = {0, 1, 1, 1, 1, 0, 0, 0, 1};
971
972 int
_dwarf_lineno_gen(Dwarf_P_Debug dbg,Dwarf_Error * error)973 _dwarf_lineno_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
974 {
975 Dwarf_LineInfo li;
976 Dwarf_LineFile lf;
977 Dwarf_P_Section ds;
978 Dwarf_Rel_Section drs;
979 Dwarf_Unsigned offset;
980 int i, ret;
981
982 assert(dbg != NULL && dbg->dbgp_lineinfo != NULL);
983
984 li = dbg->dbgp_lineinfo;
985 if (STAILQ_EMPTY(&li->li_lnlist))
986 return (DW_DLE_NONE);
987
988 li->li_length = 0;
989 li->li_version = 2;
990 li->li_hdrlen = 0;
991 li->li_minlen = _dwarf_get_minlen(dbg);
992 li->li_defstmt = 1;
993 li->li_lbase = -5;
994 li->li_lrange = 14;
995 li->li_opbase = 10;
996
997 /* Create .debug_line section. */
998 if ((ret = _dwarf_section_init(dbg, &ds, ".debug_line", 0, error)) !=
999 DW_DLE_NONE)
1000 return (ret);
1001
1002 /* Create relocation section for .debug_line */
1003 if ((ret = _dwarf_reloc_section_init(dbg, &drs, ds, error)) !=
1004 DW_DLE_NONE)
1005 goto gen_fail1;
1006
1007 /* Length placeholder. (We only use 32-bit DWARF format) */
1008 RCHECK(WRITE_VALUE(0, 4));
1009
1010 /* Write line number dwarf version. (DWARF2) */
1011 RCHECK(WRITE_VALUE(li->li_version, 2));
1012
1013 /* Header length placeholder. */
1014 offset = ds->ds_size;
1015 RCHECK(WRITE_VALUE(li->li_hdrlen, 4));
1016
1017 /* Write minimum instruction length. */
1018 RCHECK(WRITE_VALUE(li->li_minlen, 1));
1019
1020 /*
1021 * Write initial value for is_stmt. XXX Which default value we
1022 * should use?
1023 */
1024 RCHECK(WRITE_VALUE(li->li_defstmt, 1));
1025
1026 /*
1027 * Write line_base and line_range. FIXME These value needs to be
1028 * fine tuned.
1029 */
1030 RCHECK(WRITE_VALUE(li->li_lbase, 1));
1031 RCHECK(WRITE_VALUE(li->li_lrange, 1));
1032
1033 /* Write opcode_base. (DWARF2) */
1034 RCHECK(WRITE_VALUE(li->li_opbase, 1));
1035
1036 /* Write standard op length array. */
1037 RCHECK(WRITE_BLOCK(oplen, sizeof(oplen) / sizeof(oplen[0])));
1038
1039 /* Write the list of include directories. */
1040 for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++)
1041 RCHECK(WRITE_STRING(li->li_incdirs[i]));
1042 RCHECK(WRITE_VALUE(0, 1));
1043
1044 /* Write the list of filenames. */
1045 STAILQ_FOREACH(lf, &li->li_lflist, lf_next) {
1046 RCHECK(WRITE_STRING(lf->lf_fname));
1047 RCHECK(WRITE_ULEB128(lf->lf_dirndx));
1048 RCHECK(WRITE_ULEB128(lf->lf_mtime));
1049 RCHECK(WRITE_ULEB128(lf->lf_size));
1050 }
1051 RCHECK(WRITE_VALUE(0, 1));
1052
1053 /* Fill in the header length. */
1054 li->li_hdrlen = ds->ds_size - offset - 4;
1055 dbg->write(ds->ds_data, &offset, li->li_hdrlen, 4);
1056
1057 /* Generate the line number program. */
1058 RCHECK(_dwarf_lineno_gen_program(dbg, ds, drs, error));
1059
1060 /* Fill in the length of this line info. */
1061 li->li_length = ds->ds_size - 4;
1062 offset = 0;
1063 dbg->write(ds->ds_data, &offset, li->li_length, 4);
1064
1065 /* Notify the creation of .debug_line ELF section. */
1066 RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
1067
1068 /* Finalize relocation section for .debug_line. */
1069 RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error));
1070
1071 return (DW_DLE_NONE);
1072
1073 gen_fail:
1074 _dwarf_reloc_section_free(dbg, &drs);
1075
1076 gen_fail1:
1077 _dwarf_section_free(dbg, &ds);
1078
1079 return (ret);
1080 }
1081
1082 void
_dwarf_lineno_pro_cleanup(Dwarf_P_Debug dbg)1083 _dwarf_lineno_pro_cleanup(Dwarf_P_Debug dbg)
1084 {
1085 Dwarf_LineInfo li;
1086 Dwarf_LineFile lf, tlf;
1087 Dwarf_Line ln, tln;
1088 int i;
1089
1090 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
1091 if (dbg->dbgp_lineinfo == NULL)
1092 return;
1093
1094 li = dbg->dbgp_lineinfo;
1095 STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
1096 STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile,
1097 lf_next);
1098 if (lf->lf_fname)
1099 free(lf->lf_fname);
1100 free(lf);
1101 }
1102 STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
1103 STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next);
1104 free(ln);
1105 }
1106 if (li->li_incdirs) {
1107 for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++)
1108 free(li->li_incdirs[i]);
1109 free(li->li_incdirs);
1110 }
1111 free(li);
1112 dbg->dbgp_lineinfo = NULL;
1113 }
1114