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