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