libdwarf_lineno.c revision 276371
1260684Skaiw/*-
2260684Skaiw * Copyright (c) 2009,2010 Kai Wang
3260684Skaiw * All rights reserved.
4260684Skaiw *
5260684Skaiw * Redistribution and use in source and binary forms, with or without
6260684Skaiw * modification, are permitted provided that the following conditions
7260684Skaiw * are met:
8260684Skaiw * 1. Redistributions of source code must retain the above copyright
9260684Skaiw *    notice, this list of conditions and the following disclaimer.
10260684Skaiw * 2. Redistributions in binary form must reproduce the above copyright
11260684Skaiw *    notice, this list of conditions and the following disclaimer in the
12260684Skaiw *    documentation and/or other materials provided with the distribution.
13260684Skaiw *
14260684Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15260684Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16260684Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17260684Skaiw * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18260684Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19260684Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20260684Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21260684Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22260684Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23260684Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24260684Skaiw * SUCH DAMAGE.
25260684Skaiw */
26260684Skaiw
27260684Skaiw#include "_libdwarf.h"
28260684Skaiw
29276371SemasteELFTC_VCSID("$Id: libdwarf_lineno.c 3100 2014-10-25 20:34:29Z jkoshy $");
30260684Skaiw
31260684Skaiwstatic int
32260684Skaiw_dwarf_lineno_add_file(Dwarf_LineInfo li, uint8_t **p, const char *compdir,
33260684Skaiw    Dwarf_Error *error, Dwarf_Debug dbg)
34260684Skaiw{
35260684Skaiw	Dwarf_LineFile lf;
36260684Skaiw	const char *dirname;
37260684Skaiw	uint8_t *src;
38260684Skaiw	int slen;
39260684Skaiw
40260684Skaiw	src = *p;
41260684Skaiw
42260684Skaiw	if ((lf = malloc(sizeof(struct _Dwarf_LineFile))) == NULL) {
43260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
44260684Skaiw		return (DW_DLE_MEMORY);
45260684Skaiw	}
46260684Skaiw
47260684Skaiw	lf->lf_fullpath = NULL;
48260684Skaiw	lf->lf_fname = (char *) src;
49260684Skaiw	src += strlen(lf->lf_fname) + 1;
50260684Skaiw	lf->lf_dirndx = _dwarf_decode_uleb128(&src);
51260684Skaiw	if (lf->lf_dirndx > li->li_inclen) {
52260684Skaiw		free(lf);
53260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_DIR_INDEX_BAD);
54260684Skaiw		return (DW_DLE_DIR_INDEX_BAD);
55260684Skaiw	}
56260684Skaiw
57260684Skaiw	/* Make full pathname if need. */
58260684Skaiw	if (*lf->lf_fname != '/') {
59260684Skaiw		dirname = compdir;
60260684Skaiw		if (lf->lf_dirndx > 0)
61260684Skaiw			dirname = li->li_incdirs[lf->lf_dirndx - 1];
62260684Skaiw		if (dirname != NULL) {
63260684Skaiw			slen = strlen(dirname) + strlen(lf->lf_fname) + 2;
64260684Skaiw			if ((lf->lf_fullpath = malloc(slen)) == NULL) {
65260684Skaiw				free(lf);
66260684Skaiw				DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
67260684Skaiw				return (DW_DLE_MEMORY);
68260684Skaiw			}
69260684Skaiw			snprintf(lf->lf_fullpath, slen, "%s/%s", dirname,
70260684Skaiw			    lf->lf_fname);
71260684Skaiw		}
72260684Skaiw	}
73260684Skaiw
74260684Skaiw	lf->lf_mtime = _dwarf_decode_uleb128(&src);
75260684Skaiw	lf->lf_size = _dwarf_decode_uleb128(&src);
76260684Skaiw	STAILQ_INSERT_TAIL(&li->li_lflist, lf, lf_next);
77260684Skaiw	li->li_lflen++;
78260684Skaiw
79260684Skaiw	*p = src;
80260684Skaiw
81260684Skaiw	return (DW_DLE_NONE);
82260684Skaiw}
83260684Skaiw
84260684Skaiwstatic int
85260684Skaiw_dwarf_lineno_run_program(Dwarf_CU cu, Dwarf_LineInfo li, uint8_t *p,
86260684Skaiw    uint8_t *pe, const char *compdir, Dwarf_Error *error)
87260684Skaiw{
88260684Skaiw	Dwarf_Debug dbg;
89260684Skaiw	Dwarf_Line ln, tln;
90276371Semaste	uint64_t address, file, line, column, opsize;
91260684Skaiw	int is_stmt, basic_block, end_sequence;
92260684Skaiw	int ret;
93260684Skaiw
94260684Skaiw#define	RESET_REGISTERS						\
95260684Skaiw	do {							\
96260684Skaiw		address	       = 0;				\
97260684Skaiw		file	       = 1;				\
98260684Skaiw		line	       = 1;				\
99260684Skaiw		column	       = 0;				\
100260684Skaiw		is_stmt	       = li->li_defstmt;		\
101260684Skaiw		basic_block    = 0;				\
102260684Skaiw		end_sequence   = 0;				\
103260684Skaiw	} while(0)
104260684Skaiw
105260684Skaiw#define	APPEND_ROW						\
106260684Skaiw	do {							\
107260684Skaiw		ln = malloc(sizeof(struct _Dwarf_Line));	\
108260684Skaiw		if (ln == NULL) {				\
109260684Skaiw			ret = DW_DLE_MEMORY;			\
110260684Skaiw			DWARF_SET_ERROR(dbg, error, ret);	\
111260684Skaiw			goto prog_fail;				\
112260684Skaiw		}						\
113260684Skaiw		ln->ln_li     = li;				\
114260684Skaiw		ln->ln_addr   = address;			\
115260684Skaiw		ln->ln_symndx = 0;				\
116260684Skaiw		ln->ln_fileno = file;				\
117260684Skaiw		ln->ln_lineno = line;				\
118260684Skaiw		ln->ln_column = column;				\
119260684Skaiw		ln->ln_bblock = basic_block;			\
120260684Skaiw		ln->ln_stmt   = is_stmt;			\
121260684Skaiw		ln->ln_endseq = end_sequence;			\
122260684Skaiw		STAILQ_INSERT_TAIL(&li->li_lnlist, ln, ln_next);\
123260684Skaiw		li->li_lnlen++;					\
124260684Skaiw	} while(0)
125260684Skaiw
126260684Skaiw#define	LINE(x) (li->li_lbase + (((x) - li->li_opbase) % li->li_lrange))
127260684Skaiw#define	ADDRESS(x) ((((x) - li->li_opbase) / li->li_lrange) * li->li_minlen)
128260684Skaiw
129260684Skaiw	dbg = cu->cu_dbg;
130260684Skaiw
131260684Skaiw	/*
132260684Skaiw	 * Set registers to their default values.
133260684Skaiw	 */
134260684Skaiw	RESET_REGISTERS;
135260684Skaiw
136260684Skaiw	/*
137260684Skaiw	 * Start line number program.
138260684Skaiw	 */
139260684Skaiw	while (p < pe) {
140260684Skaiw		if (*p == 0) {
141260684Skaiw
142260684Skaiw			/*
143260684Skaiw			 * Extended Opcodes.
144260684Skaiw			 */
145260684Skaiw
146260684Skaiw			p++;
147260684Skaiw			opsize = _dwarf_decode_uleb128(&p);
148260684Skaiw			switch (*p) {
149260684Skaiw			case DW_LNE_end_sequence:
150260684Skaiw				p++;
151260684Skaiw				end_sequence = 1;
152260684Skaiw				APPEND_ROW;
153260684Skaiw				RESET_REGISTERS;
154260684Skaiw				break;
155260684Skaiw			case DW_LNE_set_address:
156260684Skaiw				p++;
157260684Skaiw				address = dbg->decode(&p, cu->cu_pointer_size);
158260684Skaiw				break;
159260684Skaiw			case DW_LNE_define_file:
160260684Skaiw				p++;
161260684Skaiw				ret = _dwarf_lineno_add_file(li, &p, compdir,
162260684Skaiw				    error, dbg);
163260684Skaiw				if (ret != DW_DLE_NONE)
164260684Skaiw					goto prog_fail;
165260684Skaiw				break;
166260684Skaiw			default:
167260684Skaiw				/* Unrecognized extened opcodes. */
168260684Skaiw				p += opsize;
169260684Skaiw			}
170260684Skaiw
171260684Skaiw		} else if (*p > 0 && *p < li->li_opbase) {
172260684Skaiw
173260684Skaiw			/*
174260684Skaiw			 * Standard Opcodes.
175260684Skaiw			 */
176260684Skaiw
177260684Skaiw			switch (*p++) {
178260684Skaiw			case DW_LNS_copy:
179260684Skaiw				APPEND_ROW;
180260684Skaiw				basic_block = 0;
181260684Skaiw				break;
182260684Skaiw			case DW_LNS_advance_pc:
183260684Skaiw				address += _dwarf_decode_uleb128(&p) *
184260684Skaiw				    li->li_minlen;
185260684Skaiw				break;
186260684Skaiw			case DW_LNS_advance_line:
187260684Skaiw				line += _dwarf_decode_sleb128(&p);
188260684Skaiw				break;
189260684Skaiw			case DW_LNS_set_file:
190260684Skaiw				file = _dwarf_decode_uleb128(&p);
191260684Skaiw				break;
192260684Skaiw			case DW_LNS_set_column:
193260684Skaiw				column = _dwarf_decode_uleb128(&p);
194260684Skaiw				break;
195260684Skaiw			case DW_LNS_negate_stmt:
196260684Skaiw				is_stmt = !is_stmt;
197260684Skaiw				break;
198260684Skaiw			case DW_LNS_set_basic_block:
199260684Skaiw				basic_block = 1;
200260684Skaiw				break;
201260684Skaiw			case DW_LNS_const_add_pc:
202260684Skaiw				address += ADDRESS(255);
203260684Skaiw				break;
204260684Skaiw			case DW_LNS_fixed_advance_pc:
205260684Skaiw				address += dbg->decode(&p, 2);
206260684Skaiw				break;
207260684Skaiw			case DW_LNS_set_prologue_end:
208260684Skaiw				break;
209260684Skaiw			case DW_LNS_set_epilogue_begin:
210260684Skaiw				break;
211260684Skaiw			case DW_LNS_set_isa:
212276371Semaste				(void) _dwarf_decode_uleb128(&p);
213260684Skaiw				break;
214260684Skaiw			default:
215260684Skaiw				/* Unrecognized extened opcodes. What to do? */
216260684Skaiw				break;
217260684Skaiw			}
218260684Skaiw
219260684Skaiw		} else {
220260684Skaiw
221260684Skaiw			/*
222260684Skaiw			 * Special Opcodes.
223260684Skaiw			 */
224260684Skaiw
225260684Skaiw			line += LINE(*p);
226260684Skaiw			address += ADDRESS(*p);
227260684Skaiw			APPEND_ROW;
228260684Skaiw			basic_block = 0;
229260684Skaiw			p++;
230260684Skaiw		}
231260684Skaiw	}
232260684Skaiw
233260684Skaiw	return (DW_DLE_NONE);
234260684Skaiw
235260684Skaiwprog_fail:
236260684Skaiw
237260684Skaiw	STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
238260684Skaiw		STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next);
239260684Skaiw		free(ln);
240260684Skaiw	}
241260684Skaiw
242260684Skaiw	return (ret);
243260684Skaiw
244260684Skaiw#undef	RESET_REGISTERS
245260684Skaiw#undef	APPEND_ROW
246260684Skaiw#undef	LINE
247260684Skaiw#undef	ADDRESS
248260684Skaiw}
249260684Skaiw
250260684Skaiwint
251260684Skaiw_dwarf_lineno_init(Dwarf_Die die, uint64_t offset, Dwarf_Error *error)
252260684Skaiw{
253260684Skaiw	Dwarf_Debug dbg;
254260684Skaiw	Dwarf_Section *ds;
255260684Skaiw	Dwarf_CU cu;
256260684Skaiw	Dwarf_Attribute at;
257260684Skaiw	Dwarf_LineInfo li;
258260684Skaiw	Dwarf_LineFile lf, tlf;
259260684Skaiw	const char *compdir;
260260684Skaiw	uint64_t length, hdroff, endoff;
261260684Skaiw	uint8_t *p;
262260684Skaiw	int dwarf_size, i, ret;
263260684Skaiw
264260684Skaiw	cu = die->die_cu;
265260684Skaiw	assert(cu != NULL);
266260684Skaiw
267260684Skaiw	dbg = cu->cu_dbg;
268260684Skaiw	assert(dbg != NULL);
269260684Skaiw
270260684Skaiw	if ((ds = _dwarf_find_section(dbg, ".debug_line")) == NULL)
271260684Skaiw		return (DW_DLE_NONE);
272260684Skaiw
273260684Skaiw	/*
274260684Skaiw	 * Try to find out the dir where the CU was compiled. Later we
275260684Skaiw	 * will use the dir to create full pathnames, if need.
276260684Skaiw	 */
277260684Skaiw	compdir = NULL;
278260684Skaiw	at = _dwarf_attr_find(die, DW_AT_comp_dir);
279260684Skaiw	if (at != NULL) {
280260684Skaiw		switch (at->at_form) {
281260684Skaiw		case DW_FORM_strp:
282260684Skaiw			compdir = at->u[1].s;
283260684Skaiw			break;
284260684Skaiw		case DW_FORM_string:
285260684Skaiw			compdir = at->u[0].s;
286260684Skaiw			break;
287260684Skaiw		default:
288260684Skaiw			break;
289260684Skaiw		}
290260684Skaiw	}
291260684Skaiw
292260684Skaiw	length = dbg->read(ds->ds_data, &offset, 4);
293260684Skaiw	if (length == 0xffffffff) {
294260684Skaiw		dwarf_size = 8;
295260684Skaiw		length = dbg->read(ds->ds_data, &offset, 8);
296260684Skaiw	} else
297260684Skaiw		dwarf_size = 4;
298260684Skaiw
299260684Skaiw	if (length > ds->ds_size - offset) {
300260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD);
301260684Skaiw		return (DW_DLE_DEBUG_LINE_LENGTH_BAD);
302260684Skaiw	}
303260684Skaiw
304260684Skaiw	if ((li = calloc(1, sizeof(struct _Dwarf_LineInfo))) == NULL) {
305260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
306260684Skaiw		return (DW_DLE_MEMORY);
307260684Skaiw	}
308260684Skaiw
309260684Skaiw	/*
310260684Skaiw	 * Read in line number program header.
311260684Skaiw	 */
312260684Skaiw	li->li_length = length;
313260684Skaiw	endoff = offset + length;
314260684Skaiw	li->li_version = dbg->read(ds->ds_data, &offset, 2); /* FIXME: verify version */
315260684Skaiw	li->li_hdrlen = dbg->read(ds->ds_data, &offset, dwarf_size);
316260684Skaiw	hdroff = offset;
317260684Skaiw	li->li_minlen = dbg->read(ds->ds_data, &offset, 1);
318260684Skaiw	li->li_defstmt = dbg->read(ds->ds_data, &offset, 1);
319260684Skaiw	li->li_lbase = dbg->read(ds->ds_data, &offset, 1);
320260684Skaiw	li->li_lrange = dbg->read(ds->ds_data, &offset, 1);
321260684Skaiw	li->li_opbase = dbg->read(ds->ds_data, &offset, 1);
322260684Skaiw	STAILQ_INIT(&li->li_lflist);
323260684Skaiw	STAILQ_INIT(&li->li_lnlist);
324260684Skaiw
325260684Skaiw	if ((int)li->li_hdrlen - 5 < li->li_opbase - 1) {
326260684Skaiw		ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
327260684Skaiw		DWARF_SET_ERROR(dbg, error, ret);
328260684Skaiw		goto fail_cleanup;
329260684Skaiw	}
330260684Skaiw
331260684Skaiw	if ((li->li_oplen = malloc(li->li_opbase)) == NULL) {
332260684Skaiw		ret = DW_DLE_MEMORY;
333260684Skaiw		DWARF_SET_ERROR(dbg, error, ret);
334260684Skaiw		goto fail_cleanup;
335260684Skaiw	}
336260684Skaiw
337260684Skaiw	/*
338260684Skaiw	 * Read in std opcode arg length list. Note that the first
339260684Skaiw	 * element is not used.
340260684Skaiw	 */
341260684Skaiw	for (i = 1; i < li->li_opbase; i++)
342260684Skaiw		li->li_oplen[i] = dbg->read(ds->ds_data, &offset, 1);
343260684Skaiw
344260684Skaiw	/*
345260684Skaiw	 * Check how many strings in the include dir string array.
346260684Skaiw	 */
347260684Skaiw	length = 0;
348260684Skaiw	p = ds->ds_data + offset;
349260684Skaiw	while (*p != '\0') {
350260684Skaiw		while (*p++ != '\0')
351260684Skaiw			;
352260684Skaiw		length++;
353260684Skaiw	}
354260684Skaiw	li->li_inclen = length;
355260684Skaiw
356260684Skaiw	/* Sanity check. */
357260684Skaiw	if (p - ds->ds_data > (int) ds->ds_size) {
358260684Skaiw		ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
359260684Skaiw		DWARF_SET_ERROR(dbg, error, ret);
360260684Skaiw		goto fail_cleanup;
361260684Skaiw	}
362260684Skaiw
363260684Skaiw	if (length != 0) {
364260684Skaiw		if ((li->li_incdirs = malloc(length * sizeof(char *))) ==
365260684Skaiw		    NULL) {
366260684Skaiw			ret = DW_DLE_MEMORY;
367260684Skaiw			DWARF_SET_ERROR(dbg, error, ret);
368260684Skaiw			goto fail_cleanup;
369260684Skaiw		}
370260684Skaiw	}
371260684Skaiw
372260684Skaiw	/* Fill in include dir array. */
373260684Skaiw	i = 0;
374260684Skaiw	p = ds->ds_data + offset;
375260684Skaiw	while (*p != '\0') {
376260684Skaiw		li->li_incdirs[i++] = (char *) p;
377260684Skaiw		while (*p++ != '\0')
378260684Skaiw			;
379260684Skaiw	}
380260684Skaiw
381260684Skaiw	p++;
382260684Skaiw
383260684Skaiw	/*
384260684Skaiw	 * Process file list.
385260684Skaiw	 */
386260684Skaiw	while (*p != '\0') {
387260684Skaiw		ret = _dwarf_lineno_add_file(li, &p, compdir, error, dbg);
388260684Skaiw		if (ret != DW_DLE_NONE)
389260684Skaiw			goto fail_cleanup;
390260684Skaiw		if (p - ds->ds_data > (int) ds->ds_size) {
391260684Skaiw			ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
392260684Skaiw			DWARF_SET_ERROR(dbg, error, ret);
393260684Skaiw			goto fail_cleanup;
394260684Skaiw		}
395260684Skaiw	}
396260684Skaiw
397260684Skaiw	p++;
398260684Skaiw
399260684Skaiw	/* Sanity check. */
400260684Skaiw	if (p - ds->ds_data - hdroff != li->li_hdrlen) {
401260684Skaiw		ret = DW_DLE_DEBUG_LINE_LENGTH_BAD;
402260684Skaiw		DWARF_SET_ERROR(dbg, error, ret);
403260684Skaiw		goto fail_cleanup;
404260684Skaiw	}
405260684Skaiw
406260684Skaiw	/*
407260684Skaiw	 * Process line number program.
408260684Skaiw	 */
409260684Skaiw	ret = _dwarf_lineno_run_program(cu, li, p, ds->ds_data + endoff, compdir,
410260684Skaiw	    error);
411260684Skaiw	if (ret != DW_DLE_NONE)
412260684Skaiw		goto fail_cleanup;
413260684Skaiw
414260684Skaiw	cu->cu_lineinfo = li;
415260684Skaiw
416260684Skaiw	return (DW_DLE_NONE);
417260684Skaiw
418260684Skaiwfail_cleanup:
419260684Skaiw
420260684Skaiw	STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
421260684Skaiw		STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile, lf_next);
422260684Skaiw		if (lf->lf_fullpath)
423260684Skaiw			free(lf->lf_fullpath);
424260684Skaiw		free(lf);
425260684Skaiw	}
426260684Skaiw
427260684Skaiw	if (li->li_oplen)
428260684Skaiw		free(li->li_oplen);
429260684Skaiw	if (li->li_incdirs)
430260684Skaiw		free(li->li_incdirs);
431260684Skaiw	free(li);
432260684Skaiw
433260684Skaiw	return (ret);
434260684Skaiw}
435260684Skaiw
436260684Skaiwvoid
437260684Skaiw_dwarf_lineno_cleanup(Dwarf_LineInfo li)
438260684Skaiw{
439260684Skaiw	Dwarf_LineFile lf, tlf;
440260684Skaiw	Dwarf_Line ln, tln;
441260684Skaiw
442260684Skaiw	if (li == NULL)
443260684Skaiw		return;
444260684Skaiw	STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
445260684Skaiw		STAILQ_REMOVE(&li->li_lflist, lf,
446260684Skaiw		    _Dwarf_LineFile, lf_next);
447260684Skaiw		if (lf->lf_fullpath)
448260684Skaiw			free(lf->lf_fullpath);
449260684Skaiw		free(lf);
450260684Skaiw	}
451260684Skaiw	STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
452260684Skaiw		STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line,
453260684Skaiw		    ln_next);
454260684Skaiw		free(ln);
455260684Skaiw	}
456260684Skaiw	if (li->li_oplen)
457260684Skaiw		free(li->li_oplen);
458260684Skaiw	if (li->li_incdirs)
459260684Skaiw		free(li->li_incdirs);
460260684Skaiw	if (li->li_lnarray)
461260684Skaiw		free(li->li_lnarray);
462260684Skaiw	if (li->li_lfnarray)
463260684Skaiw		free(li->li_lfnarray);
464260684Skaiw	free(li);
465260684Skaiw}
466260684Skaiw
467260684Skaiwstatic int
468260684Skaiw_dwarf_lineno_gen_program(Dwarf_P_Debug dbg, Dwarf_P_Section ds,
469260684Skaiw    Dwarf_Rel_Section drs, Dwarf_Error * error)
470260684Skaiw{
471260684Skaiw	Dwarf_LineInfo li;
472260684Skaiw	Dwarf_Line ln;
473260684Skaiw	Dwarf_Unsigned address, file, line, spc;
474260684Skaiw	Dwarf_Unsigned addr0, maddr;
475260684Skaiw	Dwarf_Signed line0, column;
476276371Semaste	int is_stmt, basic_block;
477260684Skaiw	int need_copy;
478260684Skaiw	int ret;
479260684Skaiw
480260684Skaiw#define	RESET_REGISTERS						\
481260684Skaiw	do {							\
482260684Skaiw		address	       = 0;				\
483260684Skaiw		file	       = 1;				\
484260684Skaiw		line	       = 1;				\
485260684Skaiw		column	       = 0;				\
486260684Skaiw		is_stmt	       = li->li_defstmt;		\
487260684Skaiw		basic_block    = 0;				\
488260684Skaiw	} while(0)
489260684Skaiw
490260684Skaiw	li = dbg->dbgp_lineinfo;
491260684Skaiw	maddr = (255 - li->li_opbase) / li->li_lrange;
492260684Skaiw
493260684Skaiw	RESET_REGISTERS;
494260684Skaiw
495260684Skaiw	STAILQ_FOREACH(ln, &li->li_lnlist, ln_next) {
496260684Skaiw		if (ln->ln_symndx > 0) {
497260684Skaiw			/*
498260684Skaiw			 * Generate DW_LNE_set_address extended op.
499260684Skaiw			 */
500260684Skaiw			RCHECK(WRITE_VALUE(0, 1));
501260684Skaiw			RCHECK(WRITE_ULEB128(dbg->dbg_pointer_size + 1));
502260684Skaiw			RCHECK(WRITE_VALUE(DW_LNE_set_address, 1));
503260684Skaiw			RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds,
504260684Skaiw			    dwarf_drt_data_reloc, dbg->dbg_pointer_size,
505260684Skaiw			    ds->ds_size, ln->ln_symndx, ln->ln_addr,
506260684Skaiw			    NULL, error));
507260684Skaiw			address = ln->ln_addr;
508260684Skaiw			continue;
509260684Skaiw		} else if (ln->ln_endseq) {
510260684Skaiw			addr0 = (ln->ln_addr - address) / li->li_minlen;
511260684Skaiw			if (addr0 != 0) {
512260684Skaiw				RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1));
513260684Skaiw				RCHECK(WRITE_ULEB128(addr0));
514260684Skaiw			}
515260684Skaiw
516260684Skaiw			/*
517260684Skaiw			 * Generate DW_LNE_end_sequence.
518260684Skaiw			 */
519260684Skaiw			RCHECK(WRITE_VALUE(0, 1));
520260684Skaiw			RCHECK(WRITE_ULEB128(1));
521260684Skaiw			RCHECK(WRITE_VALUE(DW_LNE_end_sequence, 1));
522260684Skaiw			RESET_REGISTERS;
523260684Skaiw			continue;
524260684Skaiw		}
525260684Skaiw
526260684Skaiw		/*
527260684Skaiw		 * Generate standard opcodes for file, column, is_stmt or
528260684Skaiw		 * basic_block changes.
529260684Skaiw		 */
530260684Skaiw		if (ln->ln_fileno != file) {
531260684Skaiw			RCHECK(WRITE_VALUE(DW_LNS_set_file, 1));
532260684Skaiw			RCHECK(WRITE_ULEB128(ln->ln_fileno));
533260684Skaiw			file = ln->ln_fileno;
534260684Skaiw		}
535260684Skaiw		if (ln->ln_column != column) {
536260684Skaiw			RCHECK(WRITE_VALUE(DW_LNS_set_column, 1));
537260684Skaiw			RCHECK(WRITE_ULEB128(ln->ln_column));
538260684Skaiw			column = ln->ln_column;
539260684Skaiw		}
540260684Skaiw		if (ln->ln_stmt != is_stmt) {
541260684Skaiw			RCHECK(WRITE_VALUE(DW_LNS_negate_stmt, 1));
542260684Skaiw			is_stmt = ln->ln_stmt;
543260684Skaiw		}
544260684Skaiw		if (ln->ln_bblock && !basic_block) {
545260684Skaiw			RCHECK(WRITE_VALUE(DW_LNS_set_basic_block, 1));
546260684Skaiw			basic_block = 1;
547260684Skaiw		}
548260684Skaiw
549260684Skaiw		/*
550260684Skaiw		 * Calculate address and line number change.
551260684Skaiw		 */
552260684Skaiw		addr0 = (ln->ln_addr - address) / li->li_minlen;
553260684Skaiw		line0 = ln->ln_lineno - line;
554260684Skaiw
555260684Skaiw		if (addr0 == 0 && line0 == 0)
556260684Skaiw			continue;
557260684Skaiw
558260684Skaiw		/*
559260684Skaiw		 * Check if line delta is with the range and if the special
560260684Skaiw		 * opcode can be used.
561260684Skaiw		 */
562260684Skaiw		assert(li->li_lbase <= 0);
563260684Skaiw		if (line0 >= li->li_lbase &&
564260684Skaiw		    line0 <= li->li_lbase + li->li_lrange - 1) {
565260684Skaiw			spc = (line0 - li->li_lbase) +
566260684Skaiw			    (li->li_lrange * addr0) + li->li_opbase;
567260684Skaiw			if (spc <= 255) {
568260684Skaiw				RCHECK(WRITE_VALUE(spc, 1));
569260684Skaiw				basic_block = 0;
570260684Skaiw				goto next_line;
571260684Skaiw			}
572260684Skaiw		}
573260684Skaiw
574260684Skaiw		/* Generate DW_LNS_advance_line for line number change. */
575260684Skaiw		if (line0 != 0) {
576260684Skaiw			RCHECK(WRITE_VALUE(DW_LNS_advance_line, 1));
577260684Skaiw			RCHECK(WRITE_SLEB128(line0));
578260684Skaiw			line0 = 0;
579260684Skaiw			need_copy = 1;
580260684Skaiw		} else
581260684Skaiw			need_copy = basic_block;
582260684Skaiw
583260684Skaiw		if (addr0 != 0) {
584260684Skaiw			/* See if it can be handled by DW_LNS_const_add_pc. */
585260684Skaiw			spc = (line0 - li->li_lbase) +
586260684Skaiw			    (li->li_lrange * (addr0 - maddr)) + li->li_opbase;
587260684Skaiw			if (addr0 >= maddr && spc <= 255) {
588260684Skaiw				RCHECK(WRITE_VALUE(DW_LNS_const_add_pc, 1));
589260684Skaiw				RCHECK(WRITE_VALUE(spc, 1));
590260684Skaiw			} else {
591260684Skaiw				/* Otherwise we use DW_LNS_advance_pc. */
592260684Skaiw				RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1));
593260684Skaiw				RCHECK(WRITE_ULEB128(addr0));
594260684Skaiw			}
595260684Skaiw		}
596260684Skaiw
597260684Skaiw		if (need_copy) {
598260684Skaiw			RCHECK(WRITE_VALUE(DW_LNS_copy, 1));
599260684Skaiw			basic_block = 0;
600260684Skaiw		}
601260684Skaiw
602260684Skaiw	next_line:
603260684Skaiw		address = ln->ln_addr;
604260684Skaiw		line = ln->ln_lineno;
605260684Skaiw	}
606260684Skaiw
607260684Skaiw	return (DW_DLE_NONE);
608260684Skaiw
609260684Skaiwgen_fail:
610260684Skaiw	return (ret);
611260684Skaiw
612260684Skaiw#undef	RESET_REGISTERS
613260684Skaiw}
614260684Skaiw
615260684Skaiwstatic uint8_t
616260684Skaiw_dwarf_get_minlen(Dwarf_P_Debug dbg)
617260684Skaiw{
618260684Skaiw
619260684Skaiw	assert(dbg != NULL);
620260684Skaiw
621260684Skaiw	switch (dbg->dbgp_isa) {
622260684Skaiw	case DW_ISA_ARM:
623260684Skaiw		return (2);
624260684Skaiw	case DW_ISA_X86:
625260684Skaiw	case DW_ISA_X86_64:
626260684Skaiw		return (1);
627260684Skaiw	default:
628260684Skaiw		return (4);
629260684Skaiw	}
630260684Skaiw}
631260684Skaiw
632260684Skaiwstatic uint8_t oplen[] = {0, 1, 1, 1, 1, 0, 0, 0, 1};
633260684Skaiw
634260684Skaiwint
635260684Skaiw_dwarf_lineno_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
636260684Skaiw{
637260684Skaiw	Dwarf_LineInfo li;
638260684Skaiw	Dwarf_LineFile lf;
639260684Skaiw	Dwarf_P_Section ds;
640260684Skaiw	Dwarf_Rel_Section drs;
641260684Skaiw	Dwarf_Unsigned offset;
642260684Skaiw	int i, ret;
643260684Skaiw
644260684Skaiw	assert(dbg != NULL && dbg->dbgp_lineinfo != NULL);
645260684Skaiw
646260684Skaiw	li = dbg->dbgp_lineinfo;
647260684Skaiw	if (STAILQ_EMPTY(&li->li_lnlist))
648260684Skaiw		return (DW_DLE_NONE);
649260684Skaiw
650260684Skaiw	li->li_length = 0;
651260684Skaiw	li->li_version = 2;
652260684Skaiw	li->li_hdrlen = 0;
653260684Skaiw	li->li_minlen = _dwarf_get_minlen(dbg);
654260684Skaiw	li->li_defstmt = 1;
655260684Skaiw	li->li_lbase = -5;
656260684Skaiw	li->li_lrange = 14;
657260684Skaiw	li->li_opbase = 10;
658260684Skaiw
659260684Skaiw	/* Create .debug_line section. */
660260684Skaiw	if ((ret = _dwarf_section_init(dbg, &ds, ".debug_line", 0, error)) !=
661260684Skaiw	    DW_DLE_NONE)
662260684Skaiw		return (ret);
663260684Skaiw
664260684Skaiw	/* Create relocation section for .debug_line */
665260684Skaiw	if ((ret = _dwarf_reloc_section_init(dbg, &drs, ds, error)) !=
666260684Skaiw	    DW_DLE_NONE)
667260684Skaiw		goto gen_fail1;
668260684Skaiw
669260684Skaiw	/* Length placeholder. (We only use 32-bit DWARF format) */
670260684Skaiw	RCHECK(WRITE_VALUE(0, 4));
671260684Skaiw
672260684Skaiw	/* Write line number dwarf version. (DWARF2) */
673260684Skaiw	RCHECK(WRITE_VALUE(li->li_version, 2));
674260684Skaiw
675260684Skaiw	/* Header length placeholder. */
676260684Skaiw	offset = ds->ds_size;
677260684Skaiw	RCHECK(WRITE_VALUE(li->li_hdrlen, 4));
678260684Skaiw
679260684Skaiw	/* Write minimum instruction length. */
680260684Skaiw	RCHECK(WRITE_VALUE(li->li_minlen, 1));
681260684Skaiw
682260684Skaiw	/*
683260684Skaiw	 * Write initial value for is_stmt. XXX Which default value we
684260684Skaiw	 * should use?
685260684Skaiw	 */
686260684Skaiw	RCHECK(WRITE_VALUE(li->li_defstmt, 1));
687260684Skaiw
688260684Skaiw	/*
689260684Skaiw	 * Write line_base and line_range. FIXME These value needs to be
690260684Skaiw	 * fine tuned.
691260684Skaiw	 */
692260684Skaiw	RCHECK(WRITE_VALUE(li->li_lbase, 1));
693260684Skaiw	RCHECK(WRITE_VALUE(li->li_lrange, 1));
694260684Skaiw
695260684Skaiw	/* Write opcode_base. (DWARF2) */
696260684Skaiw	RCHECK(WRITE_VALUE(li->li_opbase, 1));
697260684Skaiw
698260684Skaiw	/* Write standard op length array. */
699260684Skaiw	RCHECK(WRITE_BLOCK(oplen, sizeof(oplen) / sizeof(oplen[0])));
700260684Skaiw
701260684Skaiw	/* Write the list of include directories. */
702260684Skaiw	for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++)
703260684Skaiw		RCHECK(WRITE_STRING(li->li_incdirs[i]));
704260684Skaiw	RCHECK(WRITE_VALUE(0, 1));
705260684Skaiw
706260684Skaiw	/* Write the list of filenames. */
707260684Skaiw	STAILQ_FOREACH(lf, &li->li_lflist, lf_next) {
708260684Skaiw		RCHECK(WRITE_STRING(lf->lf_fname));
709260684Skaiw		RCHECK(WRITE_ULEB128(lf->lf_dirndx));
710260684Skaiw		RCHECK(WRITE_ULEB128(lf->lf_mtime));
711260684Skaiw		RCHECK(WRITE_ULEB128(lf->lf_size));
712260684Skaiw	}
713260684Skaiw	RCHECK(WRITE_VALUE(0, 1));
714260684Skaiw
715260684Skaiw	/* Fill in the header length. */
716260684Skaiw	li->li_hdrlen = ds->ds_size - offset - 4;
717260684Skaiw	dbg->write(ds->ds_data, &offset, li->li_hdrlen, 4);
718260684Skaiw
719260684Skaiw	/* Generate the line number program. */
720260684Skaiw	RCHECK(_dwarf_lineno_gen_program(dbg, ds, drs, error));
721260684Skaiw
722260684Skaiw	/* Fill in the length of this line info. */
723260684Skaiw	li->li_length = ds->ds_size - 4;
724260684Skaiw	offset = 0;
725260684Skaiw	dbg->write(ds->ds_data, &offset, li->li_length, 4);
726260684Skaiw
727260684Skaiw	/* Notify the creation of .debug_line ELF section. */
728260684Skaiw	RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
729260684Skaiw
730260684Skaiw	/* Finalize relocation section for .debug_line. */
731260684Skaiw	RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error));
732260684Skaiw
733260684Skaiw	return (DW_DLE_NONE);
734260684Skaiw
735260684Skaiwgen_fail:
736260684Skaiw	_dwarf_reloc_section_free(dbg, &drs);
737260684Skaiw
738260684Skaiwgen_fail1:
739260684Skaiw	_dwarf_section_free(dbg, &ds);
740260684Skaiw
741260684Skaiw	return (ret);
742260684Skaiw}
743260684Skaiw
744260684Skaiwvoid
745260684Skaiw_dwarf_lineno_pro_cleanup(Dwarf_P_Debug dbg)
746260684Skaiw{
747260684Skaiw	Dwarf_LineInfo li;
748260684Skaiw	Dwarf_LineFile lf, tlf;
749260684Skaiw	Dwarf_Line ln, tln;
750260684Skaiw	int i;
751260684Skaiw
752260684Skaiw	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
753260684Skaiw	if (dbg->dbgp_lineinfo == NULL)
754260684Skaiw		return;
755260684Skaiw
756260684Skaiw	li = dbg->dbgp_lineinfo;
757260684Skaiw	STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) {
758260684Skaiw		STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile,
759260684Skaiw		    lf_next);
760260684Skaiw		if (lf->lf_fname)
761260684Skaiw			free(lf->lf_fname);
762260684Skaiw		free(lf);
763260684Skaiw	}
764260684Skaiw	STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) {
765260684Skaiw		STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next);
766260684Skaiw		free(ln);
767260684Skaiw	}
768260684Skaiw	if (li->li_incdirs) {
769260684Skaiw		for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++)
770260684Skaiw			free(li->li_incdirs[i]);
771260684Skaiw		free(li->li_incdirs);
772260684Skaiw	}
773260684Skaiw	free(li);
774260684Skaiw	dbg->dbgp_lineinfo = NULL;
775260684Skaiw}
776