xref: /freebsd/contrib/elftoolchain/libdwarf/libdwarf_lineno.c (revision 415e34c4d5dff4c334330d58e06644da5c39b0bd)
1 /*-
2  * Copyright (c) 2009,2010 Kai Wang
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include "_libdwarf.h"
28 
29 ELFTC_VCSID("$Id: libdwarf_lineno.c 3164 2015-02-19 01:20:12Z kaiwang27 $");
30 
31 static int
_dwarf_lineno_add_file(Dwarf_LineInfo li,uint8_t ** p,const char * compdir,Dwarf_Error * error,Dwarf_Debug dbg)32 _dwarf_lineno_add_file(Dwarf_LineInfo li, uint8_t **p, const char *compdir,
33     Dwarf_Error *error, Dwarf_Debug dbg)
34 {
35 	Dwarf_LineFile lf;
36 	FILE *filepath;
37 	const char *incdir;
38 	uint8_t *src;
39 	size_t slen;
40 
41 	src = *p;
42 
43 	if ((lf = malloc(sizeof(struct _Dwarf_LineFile))) == NULL) {
44 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
45 		return (DW_DLE_MEMORY);
46 	}
47 
48 	lf->lf_fullpath = NULL;
49 	lf->lf_fname = (char *) src;
50 	src += strlen(lf->lf_fname) + 1;
51 	lf->lf_dirndx = _dwarf_decode_uleb128(&src);
52 	if (lf->lf_dirndx > li->li_inclen) {
53 		free(lf);
54 		DWARF_SET_ERROR(dbg, error, DW_DLE_DIR_INDEX_BAD);
55 		return (DW_DLE_DIR_INDEX_BAD);
56 	}
57 
58 	/* Make a full pathname if needed. */
59 	if (*lf->lf_fname != '/') {
60 		filepath = open_memstream(&lf->lf_fullpath, &slen);
61 		if (filepath == NULL) {
62 			free(lf);
63 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
64 			return (DW_DLE_MEMORY);
65 		}
66 
67 		if (lf->lf_dirndx > 0)
68 			incdir = li->li_incdirs[lf->lf_dirndx - 1];
69 		else
70 			incdir = NULL;
71 
72 		/*
73 		 * Prepend the compilation directory if the directory table
74 		 * entry is relative.
75 		 */
76 		if (incdir == NULL || *incdir != '/')
77 			fprintf(filepath, "%s/", compdir);
78 		if (incdir != NULL)
79 			fprintf(filepath, "%s/", incdir);
80 		fprintf(filepath, "%s", lf->lf_fname);
81 		if (fclose(filepath) != 0) {
82 			free(lf);
83 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
84 			return (DW_DLE_MEMORY);
85 		}
86 	}
87 
88 	lf->lf_mtime = _dwarf_decode_uleb128(&src);
89 	lf->lf_size = _dwarf_decode_uleb128(&src);
90 	STAILQ_INSERT_TAIL(&li->li_lflist, lf, lf_next);
91 	li->li_lflen++;
92 
93 	*p = src;
94 
95 	return (DW_DLE_NONE);
96 }
97 
98 static int
_dwarf_lineno_run_program(Dwarf_CU cu,Dwarf_LineInfo li,uint8_t * p,uint8_t * pe,const char * compdir,Dwarf_Error * error)99 _dwarf_lineno_run_program(Dwarf_CU cu, Dwarf_LineInfo li, uint8_t *p,
100     uint8_t *pe, const char *compdir, Dwarf_Error *error)
101 {
102 	Dwarf_Debug dbg;
103 	Dwarf_Line ln, tln;
104 	uint64_t address, file, line, column, opsize;
105 	int is_stmt, basic_block, end_sequence;
106 	int ret;
107 
108 #define	RESET_REGISTERS						\
109 	do {							\
110 		address	       = 0;				\
111 		file	       = 1;				\
112 		line	       = 1;				\
113 		column	       = 0;				\
114 		is_stmt	       = li->li_defstmt;		\
115 		basic_block    = 0;				\
116 		end_sequence   = 0;				\
117 	} while(0)
118 
119 #define	APPEND_ROW						\
120 	do {							\
121 		ln = malloc(sizeof(struct _Dwarf_Line));	\
122 		if (ln == NULL) {				\
123 			ret = DW_DLE_MEMORY;			\
124 			DWARF_SET_ERROR(dbg, error, ret);	\
125 			goto prog_fail;				\
126 		}						\
127 		ln->ln_li     = li;				\
128 		ln->ln_addr   = address;			\
129 		ln->ln_symndx = 0;				\
130 		ln->ln_fileno = file;				\
131 		ln->ln_lineno = line;				\
132 		ln->ln_column = column;				\
133 		ln->ln_bblock = basic_block;			\
134 		ln->ln_stmt   = is_stmt;			\
135 		ln->ln_endseq = end_sequence;			\
136 		STAILQ_INSERT_TAIL(&li->li_lnlist, ln, ln_next);\
137 		li->li_lnlen++;					\
138 	} while(0)
139 
140 #define	LINE(x) (li->li_lbase + (((x) - li->li_opbase) % li->li_lrange))
141 #define	ADDRESS(x) ((((x) - li->li_opbase) / li->li_lrange) * li->li_minlen)
142 
143 	dbg = cu->cu_dbg;
144 
145 	/*
146 	 * Set registers to their default values.
147 	 */
148 	RESET_REGISTERS;
149 
150 	/*
151 	 * Start line number program.
152 	 */
153 	while (p < pe) {
154 		if (*p == 0) {
155 
156 			/*
157 			 * Extended Opcodes.
158 			 */
159 
160 			p++;
161 			opsize = _dwarf_decode_uleb128(&p);
162 			switch (*p) {
163 			case DW_LNE_end_sequence:
164 				p++;
165 				end_sequence = 1;
166 				APPEND_ROW;
167 				RESET_REGISTERS;
168 				break;
169 			case DW_LNE_set_address:
170 				p++;
171 				address = dbg->decode(&p, cu->cu_pointer_size);
172 				break;
173 			case DW_LNE_define_file:
174 				p++;
175 				ret = _dwarf_lineno_add_file(li, &p, compdir,
176 				    error, dbg);
177 				if (ret != DW_DLE_NONE)
178 					goto prog_fail;
179 				break;
180 			default:
181 				/* Unrecognized extened opcodes. */
182 				p += opsize;
183 			}
184 
185 		} else if (*p > 0 && *p < li->li_opbase) {
186 
187 			/*
188 			 * Standard Opcodes.
189 			 */
190 
191 			switch (*p++) {
192 			case DW_LNS_copy:
193 				APPEND_ROW;
194 				basic_block = 0;
195 				break;
196 			case DW_LNS_advance_pc:
197 				address += _dwarf_decode_uleb128(&p) *
198 				    li->li_minlen;
199 				break;
200 			case DW_LNS_advance_line:
201 				line += _dwarf_decode_sleb128(&p);
202 				break;
203 			case DW_LNS_set_file:
204 				file = _dwarf_decode_uleb128(&p);
205 				break;
206 			case DW_LNS_set_column:
207 				column = _dwarf_decode_uleb128(&p);
208 				break;
209 			case DW_LNS_negate_stmt:
210 				is_stmt = !is_stmt;
211 				break;
212 			case DW_LNS_set_basic_block:
213 				basic_block = 1;
214 				break;
215 			case DW_LNS_const_add_pc:
216 				address += ADDRESS(255);
217 				break;
218 			case DW_LNS_fixed_advance_pc:
219 				address += dbg->decode(&p, 2);
220 				break;
221 			case DW_LNS_set_prologue_end:
222 				break;
223 			case DW_LNS_set_epilogue_begin:
224 				break;
225 			case DW_LNS_set_isa:
226 				(void) _dwarf_decode_uleb128(&p);
227 				break;
228 			default:
229 				/* Unrecognized extened opcodes. What to do? */
230 				break;
231 			}
232 
233 		} else {
234 
235 			/*
236 			 * Special Opcodes.
237 			 */
238 
239 			line += LINE(*p);
240 			address += ADDRESS(*p);
241 			APPEND_ROW;
242 			basic_block = 0;
243 			p++;
244 		}
245 	}
246 
247 	return (DW_DLE_NONE);
248 
249 prog_fail:
250 
251 	STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
252 		STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next);
253 		free(ln);
254 	}
255 
256 	return (ret);
257 
258 #undef	RESET_REGISTERS
259 #undef	APPEND_ROW
260 #undef	LINE
261 #undef	ADDRESS
262 }
263 
264 int
_dwarf_lineno_init(Dwarf_Die die,uint64_t offset,Dwarf_Error * error)265 _dwarf_lineno_init(Dwarf_Die die, uint64_t offset, Dwarf_Error *error)
266 {
267 	Dwarf_Debug dbg;
268 	Dwarf_Section *ds;
269 	Dwarf_CU cu;
270 	Dwarf_Attribute at;
271 	Dwarf_LineInfo li;
272 	Dwarf_LineFile lf, tlf;
273 	const char *compdir;
274 	uint64_t length, hdroff, endoff;
275 	uint8_t *p;
276 	int dwarf_size, i, ret;
277 
278 	cu = die->die_cu;
279 	assert(cu != NULL);
280 
281 	dbg = cu->cu_dbg;
282 	assert(dbg != NULL);
283 
284 	if ((ds = _dwarf_find_section(dbg, ".debug_line")) == NULL)
285 		return (DW_DLE_NONE);
286 
287 	/*
288 	 * Try to find out the dir where the CU was compiled. Later we
289 	 * will use the dir to create full pathnames, if need.
290 	 */
291 	compdir = NULL;
292 	at = _dwarf_attr_find(die, DW_AT_comp_dir);
293 	if (at != NULL) {
294 		switch (at->at_form) {
295 		case DW_FORM_strp:
296 			compdir = at->u[1].s;
297 			break;
298 		case DW_FORM_string:
299 			compdir = at->u[0].s;
300 			break;
301 		default:
302 			break;
303 		}
304 	}
305 
306 	length = dbg->read(ds->ds_data, &offset, 4);
307 	if (length == 0xffffffff) {
308 		dwarf_size = 8;
309 		length = dbg->read(ds->ds_data, &offset, 8);
310 	} else
311 		dwarf_size = 4;
312 
313 	if (length > ds->ds_size - offset) {
314 		DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD);
315 		return (DW_DLE_DEBUG_LINE_LENGTH_BAD);
316 	}
317 
318 	if ((li = calloc(1, sizeof(struct _Dwarf_LineInfo))) == NULL) {
319 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
320 		return (DW_DLE_MEMORY);
321 	}
322 
323 	/*
324 	 * Read in line number program header.
325 	 */
326 	li->li_length = length;
327 	endoff = offset + length;
328 	li->li_version = dbg->read(ds->ds_data, &offset, 2); /* FIXME: verify version */
329 	li->li_hdrlen = dbg->read(ds->ds_data, &offset, dwarf_size);
330 	hdroff = offset;
331 	li->li_minlen = dbg->read(ds->ds_data, &offset, 1);
332 	if (li->li_version == 4)
333 		li->li_maxop = dbg->read(ds->ds_data, &offset, 1);
334 	li->li_defstmt = dbg->read(ds->ds_data, &offset, 1);
335 	li->li_lbase = dbg->read(ds->ds_data, &offset, 1);
336 	li->li_lrange = dbg->read(ds->ds_data, &offset, 1);
337 	li->li_opbase = dbg->read(ds->ds_data, &offset, 1);
338 	STAILQ_INIT(&li->li_lflist);
339 	STAILQ_INIT(&li->li_lnlist);
340 
341 	if ((int)li->li_hdrlen - 5 < li->li_opbase - 1) {
342 		ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
343 		DWARF_SET_ERROR(dbg, error, ret);
344 		goto fail_cleanup;
345 	}
346 
347 	if ((li->li_oplen = malloc(li->li_opbase)) == NULL) {
348 		ret = DW_DLE_MEMORY;
349 		DWARF_SET_ERROR(dbg, error, ret);
350 		goto fail_cleanup;
351 	}
352 
353 	/*
354 	 * Read in std opcode arg length list. Note that the first
355 	 * element is not used.
356 	 */
357 	for (i = 1; i < li->li_opbase; i++)
358 		li->li_oplen[i] = dbg->read(ds->ds_data, &offset, 1);
359 
360 	/*
361 	 * Check how many strings in the include dir string array.
362 	 */
363 	length = 0;
364 	p = ds->ds_data + offset;
365 	while (*p != '\0') {
366 		while (*p++ != '\0')
367 			;
368 		length++;
369 	}
370 	li->li_inclen = length;
371 
372 	/* Sanity check. */
373 	if (p - ds->ds_data > (int) ds->ds_size) {
374 		ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
375 		DWARF_SET_ERROR(dbg, error, ret);
376 		goto fail_cleanup;
377 	}
378 
379 	if (length != 0) {
380 		if ((li->li_incdirs = malloc(length * sizeof(char *))) ==
381 		    NULL) {
382 			ret = DW_DLE_MEMORY;
383 			DWARF_SET_ERROR(dbg, error, ret);
384 			goto fail_cleanup;
385 		}
386 	}
387 
388 	/* Fill in include dir array. */
389 	i = 0;
390 	p = ds->ds_data + offset;
391 	while (*p != '\0') {
392 		li->li_incdirs[i++] = (char *) p;
393 		while (*p++ != '\0')
394 			;
395 	}
396 
397 	p++;
398 
399 	/*
400 	 * Process file list.
401 	 */
402 	while (*p != '\0') {
403 		ret = _dwarf_lineno_add_file(li, &p, compdir, error, dbg);
404 		if (ret != DW_DLE_NONE)
405 			goto fail_cleanup;
406 		if (p - ds->ds_data > (int) ds->ds_size) {
407 			ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
408 			DWARF_SET_ERROR(dbg, error, ret);
409 			goto fail_cleanup;
410 		}
411 	}
412 
413 	p++;
414 
415 	/* Sanity check. */
416 	if (p - ds->ds_data - hdroff != li->li_hdrlen) {
417 		ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
418 		DWARF_SET_ERROR(dbg, error, ret);
419 		goto fail_cleanup;
420 	}
421 
422 	/*
423 	 * Process line number program.
424 	 */
425 	ret = _dwarf_lineno_run_program(cu, li, p, ds->ds_data + endoff, compdir,
426 	    error);
427 	if (ret != DW_DLE_NONE)
428 		goto fail_cleanup;
429 
430 	cu->cu_lineinfo = li;
431 
432 	return (DW_DLE_NONE);
433 
434 fail_cleanup:
435 
436 	STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
437 		STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile, lf_next);
438 		if (lf->lf_fullpath)
439 			free(lf->lf_fullpath);
440 		free(lf);
441 	}
442 
443 	if (li->li_oplen)
444 		free(li->li_oplen);
445 	if (li->li_incdirs)
446 		free(li->li_incdirs);
447 	free(li);
448 
449 	return (ret);
450 }
451 
452 void
_dwarf_lineno_cleanup(Dwarf_LineInfo li)453 _dwarf_lineno_cleanup(Dwarf_LineInfo li)
454 {
455 	Dwarf_LineFile lf, tlf;
456 	Dwarf_Line ln, tln;
457 
458 	if (li == NULL)
459 		return;
460 	STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
461 		STAILQ_REMOVE(&li->li_lflist, lf,
462 		    _Dwarf_LineFile, lf_next);
463 		if (lf->lf_fullpath)
464 			free(lf->lf_fullpath);
465 		free(lf);
466 	}
467 	STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
468 		STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line,
469 		    ln_next);
470 		free(ln);
471 	}
472 	if (li->li_oplen)
473 		free(li->li_oplen);
474 	if (li->li_incdirs)
475 		free(li->li_incdirs);
476 	if (li->li_lnarray)
477 		free(li->li_lnarray);
478 	if (li->li_lfnarray)
479 		free(li->li_lfnarray);
480 	free(li);
481 }
482 
483 static int
_dwarf_lineno_gen_program(Dwarf_P_Debug dbg,Dwarf_P_Section ds,Dwarf_Rel_Section drs,Dwarf_Error * error)484 _dwarf_lineno_gen_program(Dwarf_P_Debug dbg, Dwarf_P_Section ds,
485     Dwarf_Rel_Section drs, Dwarf_Error * error)
486 {
487 	Dwarf_LineInfo li;
488 	Dwarf_Line ln;
489 	Dwarf_Unsigned address, file, line, spc;
490 	Dwarf_Unsigned addr0, maddr;
491 	Dwarf_Signed line0, column;
492 	int is_stmt, basic_block;
493 	int need_copy;
494 	int ret;
495 
496 #define	RESET_REGISTERS						\
497 	do {							\
498 		address	       = 0;				\
499 		file	       = 1;				\
500 		line	       = 1;				\
501 		column	       = 0;				\
502 		is_stmt	       = li->li_defstmt;		\
503 		basic_block    = 0;				\
504 	} while(0)
505 
506 	li = dbg->dbgp_lineinfo;
507 	maddr = (255 - li->li_opbase) / li->li_lrange;
508 
509 	RESET_REGISTERS;
510 
511 	STAILQ_FOREACH(ln, &li->li_lnlist, ln_next) {
512 		if (ln->ln_symndx > 0) {
513 			/*
514 			 * Generate DW_LNE_set_address extended op.
515 			 */
516 			RCHECK(WRITE_VALUE(0, 1));
517 			RCHECK(WRITE_ULEB128(dbg->dbg_pointer_size + 1));
518 			RCHECK(WRITE_VALUE(DW_LNE_set_address, 1));
519 			RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds,
520 			    dwarf_drt_data_reloc, dbg->dbg_pointer_size,
521 			    ds->ds_size, ln->ln_symndx, ln->ln_addr,
522 			    NULL, error));
523 			address = ln->ln_addr;
524 			continue;
525 		} else if (ln->ln_endseq) {
526 			addr0 = (ln->ln_addr - address) / li->li_minlen;
527 			if (addr0 != 0) {
528 				RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1));
529 				RCHECK(WRITE_ULEB128(addr0));
530 			}
531 
532 			/*
533 			 * Generate DW_LNE_end_sequence.
534 			 */
535 			RCHECK(WRITE_VALUE(0, 1));
536 			RCHECK(WRITE_ULEB128(1));
537 			RCHECK(WRITE_VALUE(DW_LNE_end_sequence, 1));
538 			RESET_REGISTERS;
539 			continue;
540 		}
541 
542 		/*
543 		 * Generate standard opcodes for file, column, is_stmt or
544 		 * basic_block changes.
545 		 */
546 		if (ln->ln_fileno != file) {
547 			RCHECK(WRITE_VALUE(DW_LNS_set_file, 1));
548 			RCHECK(WRITE_ULEB128(ln->ln_fileno));
549 			file = ln->ln_fileno;
550 		}
551 		if (ln->ln_column != column) {
552 			RCHECK(WRITE_VALUE(DW_LNS_set_column, 1));
553 			RCHECK(WRITE_ULEB128(ln->ln_column));
554 			column = ln->ln_column;
555 		}
556 		if (ln->ln_stmt != is_stmt) {
557 			RCHECK(WRITE_VALUE(DW_LNS_negate_stmt, 1));
558 			is_stmt = ln->ln_stmt;
559 		}
560 		if (ln->ln_bblock && !basic_block) {
561 			RCHECK(WRITE_VALUE(DW_LNS_set_basic_block, 1));
562 			basic_block = 1;
563 		}
564 
565 		/*
566 		 * Calculate address and line number change.
567 		 */
568 		addr0 = (ln->ln_addr - address) / li->li_minlen;
569 		line0 = ln->ln_lineno - line;
570 
571 		if (addr0 == 0 && line0 == 0)
572 			continue;
573 
574 		/*
575 		 * Check if line delta is with the range and if the special
576 		 * opcode can be used.
577 		 */
578 		assert(li->li_lbase <= 0);
579 		if (line0 >= li->li_lbase &&
580 		    line0 <= li->li_lbase + li->li_lrange - 1) {
581 			spc = (line0 - li->li_lbase) +
582 			    (li->li_lrange * addr0) + li->li_opbase;
583 			if (spc <= 255) {
584 				RCHECK(WRITE_VALUE(spc, 1));
585 				basic_block = 0;
586 				goto next_line;
587 			}
588 		}
589 
590 		/* Generate DW_LNS_advance_line for line number change. */
591 		if (line0 != 0) {
592 			RCHECK(WRITE_VALUE(DW_LNS_advance_line, 1));
593 			RCHECK(WRITE_SLEB128(line0));
594 			line0 = 0;
595 			need_copy = 1;
596 		} else
597 			need_copy = basic_block;
598 
599 		if (addr0 != 0) {
600 			/* See if it can be handled by DW_LNS_const_add_pc. */
601 			spc = (line0 - li->li_lbase) +
602 			    (li->li_lrange * (addr0 - maddr)) + li->li_opbase;
603 			if (addr0 >= maddr && spc <= 255) {
604 				RCHECK(WRITE_VALUE(DW_LNS_const_add_pc, 1));
605 				RCHECK(WRITE_VALUE(spc, 1));
606 			} else {
607 				/* Otherwise we use DW_LNS_advance_pc. */
608 				RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1));
609 				RCHECK(WRITE_ULEB128(addr0));
610 			}
611 		}
612 
613 		if (need_copy) {
614 			RCHECK(WRITE_VALUE(DW_LNS_copy, 1));
615 			basic_block = 0;
616 		}
617 
618 	next_line:
619 		address = ln->ln_addr;
620 		line = ln->ln_lineno;
621 	}
622 
623 	return (DW_DLE_NONE);
624 
625 gen_fail:
626 	return (ret);
627 
628 #undef	RESET_REGISTERS
629 }
630 
631 static uint8_t
_dwarf_get_minlen(Dwarf_P_Debug dbg)632 _dwarf_get_minlen(Dwarf_P_Debug dbg)
633 {
634 
635 	assert(dbg != NULL);
636 
637 	switch (dbg->dbgp_isa) {
638 	case DW_ISA_ARM:
639 		return (2);
640 	case DW_ISA_X86:
641 	case DW_ISA_X86_64:
642 		return (1);
643 	default:
644 		return (4);
645 	}
646 }
647 
648 static uint8_t oplen[] = {0, 1, 1, 1, 1, 0, 0, 0, 1};
649 
650 int
_dwarf_lineno_gen(Dwarf_P_Debug dbg,Dwarf_Error * error)651 _dwarf_lineno_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
652 {
653 	Dwarf_LineInfo li;
654 	Dwarf_LineFile lf;
655 	Dwarf_P_Section ds;
656 	Dwarf_Rel_Section drs;
657 	Dwarf_Unsigned offset;
658 	int i, ret;
659 
660 	assert(dbg != NULL && dbg->dbgp_lineinfo != NULL);
661 
662 	li = dbg->dbgp_lineinfo;
663 	if (STAILQ_EMPTY(&li->li_lnlist))
664 		return (DW_DLE_NONE);
665 
666 	li->li_length = 0;
667 	li->li_version = 2;
668 	li->li_hdrlen = 0;
669 	li->li_minlen = _dwarf_get_minlen(dbg);
670 	li->li_defstmt = 1;
671 	li->li_lbase = -5;
672 	li->li_lrange = 14;
673 	li->li_opbase = 10;
674 
675 	/* Create .debug_line section. */
676 	if ((ret = _dwarf_section_init(dbg, &ds, ".debug_line", 0, error)) !=
677 	    DW_DLE_NONE)
678 		return (ret);
679 
680 	/* Create relocation section for .debug_line */
681 	if ((ret = _dwarf_reloc_section_init(dbg, &drs, ds, error)) !=
682 	    DW_DLE_NONE)
683 		goto gen_fail1;
684 
685 	/* Length placeholder. (We only use 32-bit DWARF format) */
686 	RCHECK(WRITE_VALUE(0, 4));
687 
688 	/* Write line number dwarf version. (DWARF2) */
689 	RCHECK(WRITE_VALUE(li->li_version, 2));
690 
691 	/* Header length placeholder. */
692 	offset = ds->ds_size;
693 	RCHECK(WRITE_VALUE(li->li_hdrlen, 4));
694 
695 	/* Write minimum instruction length. */
696 	RCHECK(WRITE_VALUE(li->li_minlen, 1));
697 
698 	/*
699 	 * Write initial value for is_stmt. XXX Which default value we
700 	 * should use?
701 	 */
702 	RCHECK(WRITE_VALUE(li->li_defstmt, 1));
703 
704 	/*
705 	 * Write line_base and line_range. FIXME These value needs to be
706 	 * fine tuned.
707 	 */
708 	RCHECK(WRITE_VALUE(li->li_lbase, 1));
709 	RCHECK(WRITE_VALUE(li->li_lrange, 1));
710 
711 	/* Write opcode_base. (DWARF2) */
712 	RCHECK(WRITE_VALUE(li->li_opbase, 1));
713 
714 	/* Write standard op length array. */
715 	RCHECK(WRITE_BLOCK(oplen, sizeof(oplen) / sizeof(oplen[0])));
716 
717 	/* Write the list of include directories. */
718 	for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++)
719 		RCHECK(WRITE_STRING(li->li_incdirs[i]));
720 	RCHECK(WRITE_VALUE(0, 1));
721 
722 	/* Write the list of filenames. */
723 	STAILQ_FOREACH(lf, &li->li_lflist, lf_next) {
724 		RCHECK(WRITE_STRING(lf->lf_fname));
725 		RCHECK(WRITE_ULEB128(lf->lf_dirndx));
726 		RCHECK(WRITE_ULEB128(lf->lf_mtime));
727 		RCHECK(WRITE_ULEB128(lf->lf_size));
728 	}
729 	RCHECK(WRITE_VALUE(0, 1));
730 
731 	/* Fill in the header length. */
732 	li->li_hdrlen = ds->ds_size - offset - 4;
733 	dbg->write(ds->ds_data, &offset, li->li_hdrlen, 4);
734 
735 	/* Generate the line number program. */
736 	RCHECK(_dwarf_lineno_gen_program(dbg, ds, drs, error));
737 
738 	/* Fill in the length of this line info. */
739 	li->li_length = ds->ds_size - 4;
740 	offset = 0;
741 	dbg->write(ds->ds_data, &offset, li->li_length, 4);
742 
743 	/* Notify the creation of .debug_line ELF section. */
744 	RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
745 
746 	/* Finalize relocation section for .debug_line. */
747 	RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error));
748 
749 	return (DW_DLE_NONE);
750 
751 gen_fail:
752 	_dwarf_reloc_section_free(dbg, &drs);
753 
754 gen_fail1:
755 	_dwarf_section_free(dbg, &ds);
756 
757 	return (ret);
758 }
759 
760 void
_dwarf_lineno_pro_cleanup(Dwarf_P_Debug dbg)761 _dwarf_lineno_pro_cleanup(Dwarf_P_Debug dbg)
762 {
763 	Dwarf_LineInfo li;
764 	Dwarf_LineFile lf, tlf;
765 	Dwarf_Line ln, tln;
766 	int i;
767 
768 	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
769 	if (dbg->dbgp_lineinfo == NULL)
770 		return;
771 
772 	li = dbg->dbgp_lineinfo;
773 	STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
774 		STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile,
775 		    lf_next);
776 		if (lf->lf_fname)
777 			free(lf->lf_fname);
778 		free(lf);
779 	}
780 	STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
781 		STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next);
782 		free(ln);
783 	}
784 	if (li->li_incdirs) {
785 		for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++)
786 			free(li->li_incdirs[i]);
787 		free(li->li_incdirs);
788 	}
789 	free(li);
790 	dbg->dbgp_lineinfo = NULL;
791 }
792