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