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 29280932SemasteELFTC_VCSID("$Id: libdwarf_lineno.c 3164 2015-02-19 01:20:12Z kaiwang27 $"); 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); 318280932Semaste if (li->li_version == 4) 319280932Semaste li->li_maxop = dbg->read(ds->ds_data, &offset, 1); 320260684Skaiw li->li_defstmt = dbg->read(ds->ds_data, &offset, 1); 321260684Skaiw li->li_lbase = dbg->read(ds->ds_data, &offset, 1); 322260684Skaiw li->li_lrange = dbg->read(ds->ds_data, &offset, 1); 323260684Skaiw li->li_opbase = dbg->read(ds->ds_data, &offset, 1); 324260684Skaiw STAILQ_INIT(&li->li_lflist); 325260684Skaiw STAILQ_INIT(&li->li_lnlist); 326260684Skaiw 327260684Skaiw if ((int)li->li_hdrlen - 5 < li->li_opbase - 1) { 328260684Skaiw ret = DW_DLE_DEBUG_LINE_LENGTH_BAD; 329260684Skaiw DWARF_SET_ERROR(dbg, error, ret); 330260684Skaiw goto fail_cleanup; 331260684Skaiw } 332260684Skaiw 333260684Skaiw if ((li->li_oplen = malloc(li->li_opbase)) == NULL) { 334260684Skaiw ret = DW_DLE_MEMORY; 335260684Skaiw DWARF_SET_ERROR(dbg, error, ret); 336260684Skaiw goto fail_cleanup; 337260684Skaiw } 338260684Skaiw 339260684Skaiw /* 340260684Skaiw * Read in std opcode arg length list. Note that the first 341260684Skaiw * element is not used. 342260684Skaiw */ 343260684Skaiw for (i = 1; i < li->li_opbase; i++) 344260684Skaiw li->li_oplen[i] = dbg->read(ds->ds_data, &offset, 1); 345260684Skaiw 346260684Skaiw /* 347260684Skaiw * Check how many strings in the include dir string array. 348260684Skaiw */ 349260684Skaiw length = 0; 350260684Skaiw p = ds->ds_data + offset; 351260684Skaiw while (*p != '\0') { 352260684Skaiw while (*p++ != '\0') 353260684Skaiw ; 354260684Skaiw length++; 355260684Skaiw } 356260684Skaiw li->li_inclen = length; 357260684Skaiw 358260684Skaiw /* Sanity check. */ 359260684Skaiw if (p - ds->ds_data > (int) ds->ds_size) { 360260684Skaiw ret = DW_DLE_DEBUG_LINE_LENGTH_BAD; 361260684Skaiw DWARF_SET_ERROR(dbg, error, ret); 362260684Skaiw goto fail_cleanup; 363260684Skaiw } 364260684Skaiw 365260684Skaiw if (length != 0) { 366260684Skaiw if ((li->li_incdirs = malloc(length * sizeof(char *))) == 367260684Skaiw NULL) { 368260684Skaiw ret = DW_DLE_MEMORY; 369260684Skaiw DWARF_SET_ERROR(dbg, error, ret); 370260684Skaiw goto fail_cleanup; 371260684Skaiw } 372260684Skaiw } 373260684Skaiw 374260684Skaiw /* Fill in include dir array. */ 375260684Skaiw i = 0; 376260684Skaiw p = ds->ds_data + offset; 377260684Skaiw while (*p != '\0') { 378260684Skaiw li->li_incdirs[i++] = (char *) p; 379260684Skaiw while (*p++ != '\0') 380260684Skaiw ; 381260684Skaiw } 382260684Skaiw 383260684Skaiw p++; 384260684Skaiw 385260684Skaiw /* 386260684Skaiw * Process file list. 387260684Skaiw */ 388260684Skaiw while (*p != '\0') { 389260684Skaiw ret = _dwarf_lineno_add_file(li, &p, compdir, error, dbg); 390260684Skaiw if (ret != DW_DLE_NONE) 391260684Skaiw goto fail_cleanup; 392260684Skaiw if (p - ds->ds_data > (int) ds->ds_size) { 393260684Skaiw ret = DW_DLE_DEBUG_LINE_LENGTH_BAD; 394260684Skaiw DWARF_SET_ERROR(dbg, error, ret); 395260684Skaiw goto fail_cleanup; 396260684Skaiw } 397260684Skaiw } 398260684Skaiw 399260684Skaiw p++; 400260684Skaiw 401260684Skaiw /* Sanity check. */ 402260684Skaiw if (p - ds->ds_data - hdroff != li->li_hdrlen) { 403260684Skaiw ret = DW_DLE_DEBUG_LINE_LENGTH_BAD; 404260684Skaiw DWARF_SET_ERROR(dbg, error, ret); 405260684Skaiw goto fail_cleanup; 406260684Skaiw } 407260684Skaiw 408260684Skaiw /* 409260684Skaiw * Process line number program. 410260684Skaiw */ 411260684Skaiw ret = _dwarf_lineno_run_program(cu, li, p, ds->ds_data + endoff, compdir, 412260684Skaiw error); 413260684Skaiw if (ret != DW_DLE_NONE) 414260684Skaiw goto fail_cleanup; 415260684Skaiw 416260684Skaiw cu->cu_lineinfo = li; 417260684Skaiw 418260684Skaiw return (DW_DLE_NONE); 419260684Skaiw 420260684Skaiwfail_cleanup: 421260684Skaiw 422260684Skaiw STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) { 423260684Skaiw STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile, lf_next); 424260684Skaiw if (lf->lf_fullpath) 425260684Skaiw free(lf->lf_fullpath); 426260684Skaiw free(lf); 427260684Skaiw } 428260684Skaiw 429260684Skaiw if (li->li_oplen) 430260684Skaiw free(li->li_oplen); 431260684Skaiw if (li->li_incdirs) 432260684Skaiw free(li->li_incdirs); 433260684Skaiw free(li); 434260684Skaiw 435260684Skaiw return (ret); 436260684Skaiw} 437260684Skaiw 438260684Skaiwvoid 439260684Skaiw_dwarf_lineno_cleanup(Dwarf_LineInfo li) 440260684Skaiw{ 441260684Skaiw Dwarf_LineFile lf, tlf; 442260684Skaiw Dwarf_Line ln, tln; 443260684Skaiw 444260684Skaiw if (li == NULL) 445260684Skaiw return; 446260684Skaiw STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) { 447260684Skaiw STAILQ_REMOVE(&li->li_lflist, lf, 448260684Skaiw _Dwarf_LineFile, lf_next); 449260684Skaiw if (lf->lf_fullpath) 450260684Skaiw free(lf->lf_fullpath); 451260684Skaiw free(lf); 452260684Skaiw } 453260684Skaiw STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) { 454260684Skaiw STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, 455260684Skaiw ln_next); 456260684Skaiw free(ln); 457260684Skaiw } 458260684Skaiw if (li->li_oplen) 459260684Skaiw free(li->li_oplen); 460260684Skaiw if (li->li_incdirs) 461260684Skaiw free(li->li_incdirs); 462260684Skaiw if (li->li_lnarray) 463260684Skaiw free(li->li_lnarray); 464260684Skaiw if (li->li_lfnarray) 465260684Skaiw free(li->li_lfnarray); 466260684Skaiw free(li); 467260684Skaiw} 468260684Skaiw 469260684Skaiwstatic int 470260684Skaiw_dwarf_lineno_gen_program(Dwarf_P_Debug dbg, Dwarf_P_Section ds, 471260684Skaiw Dwarf_Rel_Section drs, Dwarf_Error * error) 472260684Skaiw{ 473260684Skaiw Dwarf_LineInfo li; 474260684Skaiw Dwarf_Line ln; 475260684Skaiw Dwarf_Unsigned address, file, line, spc; 476260684Skaiw Dwarf_Unsigned addr0, maddr; 477260684Skaiw Dwarf_Signed line0, column; 478276371Semaste int is_stmt, basic_block; 479260684Skaiw int need_copy; 480260684Skaiw int ret; 481260684Skaiw 482260684Skaiw#define RESET_REGISTERS \ 483260684Skaiw do { \ 484260684Skaiw address = 0; \ 485260684Skaiw file = 1; \ 486260684Skaiw line = 1; \ 487260684Skaiw column = 0; \ 488260684Skaiw is_stmt = li->li_defstmt; \ 489260684Skaiw basic_block = 0; \ 490260684Skaiw } while(0) 491260684Skaiw 492260684Skaiw li = dbg->dbgp_lineinfo; 493260684Skaiw maddr = (255 - li->li_opbase) / li->li_lrange; 494260684Skaiw 495260684Skaiw RESET_REGISTERS; 496260684Skaiw 497260684Skaiw STAILQ_FOREACH(ln, &li->li_lnlist, ln_next) { 498260684Skaiw if (ln->ln_symndx > 0) { 499260684Skaiw /* 500260684Skaiw * Generate DW_LNE_set_address extended op. 501260684Skaiw */ 502260684Skaiw RCHECK(WRITE_VALUE(0, 1)); 503260684Skaiw RCHECK(WRITE_ULEB128(dbg->dbg_pointer_size + 1)); 504260684Skaiw RCHECK(WRITE_VALUE(DW_LNE_set_address, 1)); 505260684Skaiw RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, 506260684Skaiw dwarf_drt_data_reloc, dbg->dbg_pointer_size, 507260684Skaiw ds->ds_size, ln->ln_symndx, ln->ln_addr, 508260684Skaiw NULL, error)); 509260684Skaiw address = ln->ln_addr; 510260684Skaiw continue; 511260684Skaiw } else if (ln->ln_endseq) { 512260684Skaiw addr0 = (ln->ln_addr - address) / li->li_minlen; 513260684Skaiw if (addr0 != 0) { 514260684Skaiw RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1)); 515260684Skaiw RCHECK(WRITE_ULEB128(addr0)); 516260684Skaiw } 517260684Skaiw 518260684Skaiw /* 519260684Skaiw * Generate DW_LNE_end_sequence. 520260684Skaiw */ 521260684Skaiw RCHECK(WRITE_VALUE(0, 1)); 522260684Skaiw RCHECK(WRITE_ULEB128(1)); 523260684Skaiw RCHECK(WRITE_VALUE(DW_LNE_end_sequence, 1)); 524260684Skaiw RESET_REGISTERS; 525260684Skaiw continue; 526260684Skaiw } 527260684Skaiw 528260684Skaiw /* 529260684Skaiw * Generate standard opcodes for file, column, is_stmt or 530260684Skaiw * basic_block changes. 531260684Skaiw */ 532260684Skaiw if (ln->ln_fileno != file) { 533260684Skaiw RCHECK(WRITE_VALUE(DW_LNS_set_file, 1)); 534260684Skaiw RCHECK(WRITE_ULEB128(ln->ln_fileno)); 535260684Skaiw file = ln->ln_fileno; 536260684Skaiw } 537260684Skaiw if (ln->ln_column != column) { 538260684Skaiw RCHECK(WRITE_VALUE(DW_LNS_set_column, 1)); 539260684Skaiw RCHECK(WRITE_ULEB128(ln->ln_column)); 540260684Skaiw column = ln->ln_column; 541260684Skaiw } 542260684Skaiw if (ln->ln_stmt != is_stmt) { 543260684Skaiw RCHECK(WRITE_VALUE(DW_LNS_negate_stmt, 1)); 544260684Skaiw is_stmt = ln->ln_stmt; 545260684Skaiw } 546260684Skaiw if (ln->ln_bblock && !basic_block) { 547260684Skaiw RCHECK(WRITE_VALUE(DW_LNS_set_basic_block, 1)); 548260684Skaiw basic_block = 1; 549260684Skaiw } 550260684Skaiw 551260684Skaiw /* 552260684Skaiw * Calculate address and line number change. 553260684Skaiw */ 554260684Skaiw addr0 = (ln->ln_addr - address) / li->li_minlen; 555260684Skaiw line0 = ln->ln_lineno - line; 556260684Skaiw 557260684Skaiw if (addr0 == 0 && line0 == 0) 558260684Skaiw continue; 559260684Skaiw 560260684Skaiw /* 561260684Skaiw * Check if line delta is with the range and if the special 562260684Skaiw * opcode can be used. 563260684Skaiw */ 564260684Skaiw assert(li->li_lbase <= 0); 565260684Skaiw if (line0 >= li->li_lbase && 566260684Skaiw line0 <= li->li_lbase + li->li_lrange - 1) { 567260684Skaiw spc = (line0 - li->li_lbase) + 568260684Skaiw (li->li_lrange * addr0) + li->li_opbase; 569260684Skaiw if (spc <= 255) { 570260684Skaiw RCHECK(WRITE_VALUE(spc, 1)); 571260684Skaiw basic_block = 0; 572260684Skaiw goto next_line; 573260684Skaiw } 574260684Skaiw } 575260684Skaiw 576260684Skaiw /* Generate DW_LNS_advance_line for line number change. */ 577260684Skaiw if (line0 != 0) { 578260684Skaiw RCHECK(WRITE_VALUE(DW_LNS_advance_line, 1)); 579260684Skaiw RCHECK(WRITE_SLEB128(line0)); 580260684Skaiw line0 = 0; 581260684Skaiw need_copy = 1; 582260684Skaiw } else 583260684Skaiw need_copy = basic_block; 584260684Skaiw 585260684Skaiw if (addr0 != 0) { 586260684Skaiw /* See if it can be handled by DW_LNS_const_add_pc. */ 587260684Skaiw spc = (line0 - li->li_lbase) + 588260684Skaiw (li->li_lrange * (addr0 - maddr)) + li->li_opbase; 589260684Skaiw if (addr0 >= maddr && spc <= 255) { 590260684Skaiw RCHECK(WRITE_VALUE(DW_LNS_const_add_pc, 1)); 591260684Skaiw RCHECK(WRITE_VALUE(spc, 1)); 592260684Skaiw } else { 593260684Skaiw /* Otherwise we use DW_LNS_advance_pc. */ 594260684Skaiw RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1)); 595260684Skaiw RCHECK(WRITE_ULEB128(addr0)); 596260684Skaiw } 597260684Skaiw } 598260684Skaiw 599260684Skaiw if (need_copy) { 600260684Skaiw RCHECK(WRITE_VALUE(DW_LNS_copy, 1)); 601260684Skaiw basic_block = 0; 602260684Skaiw } 603260684Skaiw 604260684Skaiw next_line: 605260684Skaiw address = ln->ln_addr; 606260684Skaiw line = ln->ln_lineno; 607260684Skaiw } 608260684Skaiw 609260684Skaiw return (DW_DLE_NONE); 610260684Skaiw 611260684Skaiwgen_fail: 612260684Skaiw return (ret); 613260684Skaiw 614260684Skaiw#undef RESET_REGISTERS 615260684Skaiw} 616260684Skaiw 617260684Skaiwstatic uint8_t 618260684Skaiw_dwarf_get_minlen(Dwarf_P_Debug dbg) 619260684Skaiw{ 620260684Skaiw 621260684Skaiw assert(dbg != NULL); 622260684Skaiw 623260684Skaiw switch (dbg->dbgp_isa) { 624260684Skaiw case DW_ISA_ARM: 625260684Skaiw return (2); 626260684Skaiw case DW_ISA_X86: 627260684Skaiw case DW_ISA_X86_64: 628260684Skaiw return (1); 629260684Skaiw default: 630260684Skaiw return (4); 631260684Skaiw } 632260684Skaiw} 633260684Skaiw 634260684Skaiwstatic uint8_t oplen[] = {0, 1, 1, 1, 1, 0, 0, 0, 1}; 635260684Skaiw 636260684Skaiwint 637260684Skaiw_dwarf_lineno_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) 638260684Skaiw{ 639260684Skaiw Dwarf_LineInfo li; 640260684Skaiw Dwarf_LineFile lf; 641260684Skaiw Dwarf_P_Section ds; 642260684Skaiw Dwarf_Rel_Section drs; 643260684Skaiw Dwarf_Unsigned offset; 644260684Skaiw int i, ret; 645260684Skaiw 646260684Skaiw assert(dbg != NULL && dbg->dbgp_lineinfo != NULL); 647260684Skaiw 648260684Skaiw li = dbg->dbgp_lineinfo; 649260684Skaiw if (STAILQ_EMPTY(&li->li_lnlist)) 650260684Skaiw return (DW_DLE_NONE); 651260684Skaiw 652260684Skaiw li->li_length = 0; 653260684Skaiw li->li_version = 2; 654260684Skaiw li->li_hdrlen = 0; 655260684Skaiw li->li_minlen = _dwarf_get_minlen(dbg); 656260684Skaiw li->li_defstmt = 1; 657260684Skaiw li->li_lbase = -5; 658260684Skaiw li->li_lrange = 14; 659260684Skaiw li->li_opbase = 10; 660260684Skaiw 661260684Skaiw /* Create .debug_line section. */ 662260684Skaiw if ((ret = _dwarf_section_init(dbg, &ds, ".debug_line", 0, error)) != 663260684Skaiw DW_DLE_NONE) 664260684Skaiw return (ret); 665260684Skaiw 666260684Skaiw /* Create relocation section for .debug_line */ 667260684Skaiw if ((ret = _dwarf_reloc_section_init(dbg, &drs, ds, error)) != 668260684Skaiw DW_DLE_NONE) 669260684Skaiw goto gen_fail1; 670260684Skaiw 671260684Skaiw /* Length placeholder. (We only use 32-bit DWARF format) */ 672260684Skaiw RCHECK(WRITE_VALUE(0, 4)); 673260684Skaiw 674260684Skaiw /* Write line number dwarf version. (DWARF2) */ 675260684Skaiw RCHECK(WRITE_VALUE(li->li_version, 2)); 676260684Skaiw 677260684Skaiw /* Header length placeholder. */ 678260684Skaiw offset = ds->ds_size; 679260684Skaiw RCHECK(WRITE_VALUE(li->li_hdrlen, 4)); 680260684Skaiw 681260684Skaiw /* Write minimum instruction length. */ 682260684Skaiw RCHECK(WRITE_VALUE(li->li_minlen, 1)); 683260684Skaiw 684260684Skaiw /* 685260684Skaiw * Write initial value for is_stmt. XXX Which default value we 686260684Skaiw * should use? 687260684Skaiw */ 688260684Skaiw RCHECK(WRITE_VALUE(li->li_defstmt, 1)); 689260684Skaiw 690260684Skaiw /* 691260684Skaiw * Write line_base and line_range. FIXME These value needs to be 692260684Skaiw * fine tuned. 693260684Skaiw */ 694260684Skaiw RCHECK(WRITE_VALUE(li->li_lbase, 1)); 695260684Skaiw RCHECK(WRITE_VALUE(li->li_lrange, 1)); 696260684Skaiw 697260684Skaiw /* Write opcode_base. (DWARF2) */ 698260684Skaiw RCHECK(WRITE_VALUE(li->li_opbase, 1)); 699260684Skaiw 700260684Skaiw /* Write standard op length array. */ 701260684Skaiw RCHECK(WRITE_BLOCK(oplen, sizeof(oplen) / sizeof(oplen[0]))); 702260684Skaiw 703260684Skaiw /* Write the list of include directories. */ 704260684Skaiw for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++) 705260684Skaiw RCHECK(WRITE_STRING(li->li_incdirs[i])); 706260684Skaiw RCHECK(WRITE_VALUE(0, 1)); 707260684Skaiw 708260684Skaiw /* Write the list of filenames. */ 709260684Skaiw STAILQ_FOREACH(lf, &li->li_lflist, lf_next) { 710260684Skaiw RCHECK(WRITE_STRING(lf->lf_fname)); 711260684Skaiw RCHECK(WRITE_ULEB128(lf->lf_dirndx)); 712260684Skaiw RCHECK(WRITE_ULEB128(lf->lf_mtime)); 713260684Skaiw RCHECK(WRITE_ULEB128(lf->lf_size)); 714260684Skaiw } 715260684Skaiw RCHECK(WRITE_VALUE(0, 1)); 716260684Skaiw 717260684Skaiw /* Fill in the header length. */ 718260684Skaiw li->li_hdrlen = ds->ds_size - offset - 4; 719260684Skaiw dbg->write(ds->ds_data, &offset, li->li_hdrlen, 4); 720260684Skaiw 721260684Skaiw /* Generate the line number program. */ 722260684Skaiw RCHECK(_dwarf_lineno_gen_program(dbg, ds, drs, error)); 723260684Skaiw 724260684Skaiw /* Fill in the length of this line info. */ 725260684Skaiw li->li_length = ds->ds_size - 4; 726260684Skaiw offset = 0; 727260684Skaiw dbg->write(ds->ds_data, &offset, li->li_length, 4); 728260684Skaiw 729260684Skaiw /* Notify the creation of .debug_line ELF section. */ 730260684Skaiw RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); 731260684Skaiw 732260684Skaiw /* Finalize relocation section for .debug_line. */ 733260684Skaiw RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error)); 734260684Skaiw 735260684Skaiw return (DW_DLE_NONE); 736260684Skaiw 737260684Skaiwgen_fail: 738260684Skaiw _dwarf_reloc_section_free(dbg, &drs); 739260684Skaiw 740260684Skaiwgen_fail1: 741260684Skaiw _dwarf_section_free(dbg, &ds); 742260684Skaiw 743260684Skaiw return (ret); 744260684Skaiw} 745260684Skaiw 746260684Skaiwvoid 747260684Skaiw_dwarf_lineno_pro_cleanup(Dwarf_P_Debug dbg) 748260684Skaiw{ 749260684Skaiw Dwarf_LineInfo li; 750260684Skaiw Dwarf_LineFile lf, tlf; 751260684Skaiw Dwarf_Line ln, tln; 752260684Skaiw int i; 753260684Skaiw 754260684Skaiw assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); 755260684Skaiw if (dbg->dbgp_lineinfo == NULL) 756260684Skaiw return; 757260684Skaiw 758260684Skaiw li = dbg->dbgp_lineinfo; 759260684Skaiw STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) { 760260684Skaiw STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile, 761260684Skaiw lf_next); 762260684Skaiw if (lf->lf_fname) 763260684Skaiw free(lf->lf_fname); 764260684Skaiw free(lf); 765260684Skaiw } 766260684Skaiw STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) { 767260684Skaiw STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next); 768260684Skaiw free(ln); 769260684Skaiw } 770260684Skaiw if (li->li_incdirs) { 771260684Skaiw for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++) 772260684Skaiw free(li->li_incdirs[i]); 773260684Skaiw free(li->li_incdirs); 774260684Skaiw } 775260684Skaiw free(li); 776260684Skaiw dbg->dbgp_lineinfo = NULL; 777260684Skaiw} 778