xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_print_lines.c (revision bc1f688b4872ace323eaddbb1a6365d054e7bf56)
1 /*
2 
3   Copyright (C) 2000,2002,2004,2005,2006 Silicon Graphics, Inc.  All Rights Reserved.
4   Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of version 2.1 of the GNU Lesser General Public License
8   as published by the Free Software Foundation.
9 
10   This program is distributed in the hope that it would be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14   Further, this software is distributed without any warranty that it is
15   free of the rightful claim of any third person regarding infringement
16   or the like.  Any license provided herein, whether implied or
17   otherwise, applies only to this software file.  Patent licenses, if
18   any, provided herein do not apply to combinations of this program with
19   other software, or any other product whatsoever.
20 
21   You should have received a copy of the GNU Lesser General Public
22   License along with this program; if not, write the Free Software
23   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
24   USA.
25 
26   Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
27   Mountain View, CA 94043, or:
28 
29   http://www.sgi.com
30 
31   For further information regarding this notice, see:
32 
33   http://oss.sgi.com/projects/GenInfo/NoticeExplan
34 
35 */
36 /* The address of the Free Software Foundation is
37    Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
38    Boston, MA 02110-1301, USA.
39    SGI has moved from the Crittenden Lane address.
40 */
41 
42 
43 
44 
45 #include "config.h"
46 #include "dwarf_incl.h"
47 #include <stdio.h>
48 #include <time.h>
49 #include "dwarf_line.h"
50 
51 /* FIXME Need to add prologue_end epilogue_begin isa fields. */
52 static void
53 print_line_header(void)
54 {
55     printf
56         ("                                                         s b e\n"
57          "                                                         t l s\n"
58          "                                                         m c e\n"
59          " section    op                                       col t k q\n"
60          " offset     code               address     file line umn ? ? ?\n");
61 }
62 
63 /* FIXME: print new line values:   prologue_end epilogue_begin isa */
64 static void
65 print_line_detail(char *prefix,
66                   int opcode,
67                   Dwarf_Unsigned address,
68                   unsigned long file,
69                   unsigned long line,
70                   unsigned long column,
71                   int is_stmt, int basic_block, int end_sequence,
72                   int prologue_end, int epilogue_begin, int isa)
73 {
74     printf("%-15s %2d 0x%08" DW_PR_DUx " "
75            "%2lu   %4lu %2lu   %1d %1d %1d\n",
76            prefix,
77            (int) opcode,
78            (Dwarf_Unsigned) address,
79            (unsigned long) file,
80            (unsigned long) line,
81            (unsigned long) column,
82            (int) is_stmt, (int) basic_block, (int) end_sequence);
83 
84 }
85 
86 
87 /*
88         return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
89         If err_count_out is non-NULL, this is a special 'check'
90         call.
91 */
92 int
93 _dwarf_internal_printlines(Dwarf_Die die, Dwarf_Error * error,
94    int * err_count_out, int only_line_header)
95 {
96     /*
97        This pointer is used to scan the portion of the .debug_line
98        section for the current cu. */
99     Dwarf_Small *line_ptr = 0;
100     Dwarf_Small *orig_line_ptr = 0;
101 
102     /*
103        This points to the last byte of the .debug_line portion for the
104        current cu. */
105     Dwarf_Small *line_ptr_end = 0;
106 
107     /*
108        Pointer to a DW_AT_stmt_list attribute in case it exists in the
109        die. */
110     Dwarf_Attribute stmt_list_attr = 0;
111 
112     /* Pointer to DW_AT_comp_dir attribute in die. */
113     Dwarf_Attribute comp_dir_attr = 0;
114 
115     /* Pointer to name of compilation directory. */
116     Dwarf_Small *comp_dir = NULL;
117 
118     /*
119        Offset into .debug_line specified by a DW_AT_stmt_list
120        attribute. */
121     Dwarf_Unsigned line_offset = 0;
122 
123     struct Line_Table_Prefix_s prefix;
124 
125 
126     /* These are the state machine state variables. */
127     Dwarf_Addr address = 0;
128     Dwarf_Word file = 1;
129     Dwarf_Word line = 1;
130     Dwarf_Word column = 0;
131     Dwarf_Bool is_stmt = false;
132     Dwarf_Bool basic_block = false;
133     Dwarf_Bool end_sequence = false;
134     Dwarf_Bool prologue_end = false;
135     Dwarf_Bool epilogue_begin = false;
136     Dwarf_Small isa = 0;
137 
138 
139     Dwarf_Sword i=0;
140 
141     /*
142        This is the current opcode read from the statement program. */
143     Dwarf_Small opcode=0;
144 
145 
146     /*
147        These variables are used to decode leb128 numbers. Leb128_num
148        holds the decoded number, and leb128_length is its length in
149        bytes. */
150     Dwarf_Word leb128_num=0;
151     Dwarf_Word leb128_length=0;
152     Dwarf_Sword advance_line=0;
153     Dwarf_Half attrform = 0;
154     /*
155        This is the operand of the latest fixed_advance_pc extended
156        opcode. */
157     Dwarf_Half fixed_advance_pc=0;
158 
159     /* In case there are wierd bytes 'after' the line table
160      * prologue this lets us print something. This is a gcc
161      * compiler bug and we expect the bytes count to be 12.
162      */
163     Dwarf_Small* bogus_bytes_ptr = 0;
164     Dwarf_Unsigned bogus_bytes_count = 0;
165 
166 
167     /* The Dwarf_Debug this die belongs to. */
168     Dwarf_Debug dbg=0;
169     int resattr = DW_DLV_ERROR;
170     int lres =    DW_DLV_ERROR;
171     int res  =    DW_DLV_ERROR;
172 
173     /* ***** BEGIN CODE ***** */
174 
175     if (error != NULL) {
176         *error = NULL;
177     }
178 
179     CHECK_DIE(die, DW_DLV_ERROR);
180     dbg = die->di_cu_context->cc_dbg;
181 
182     res = _dwarf_load_section(dbg, &dbg->de_debug_line,error);
183     if (res != DW_DLV_OK) {
184         return res;
185     }
186 
187     resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
188     if (resattr != DW_DLV_OK) {
189         return resattr;
190     }
191 
192 
193     /* The list of relevant FORMs is small.
194        DW_FORM_data4, DW_FORM_data8, DW_FORM_sec_offset
195     */
196     lres = dwarf_whatform(stmt_list_attr,&attrform,error);
197     if (lres != DW_DLV_OK) {
198         return lres;
199     }
200     if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 &&
201         attrform != DW_FORM_sec_offset ) {
202         _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
203         return (DW_DLV_ERROR);
204     }
205     lres = dwarf_global_formref(stmt_list_attr, &line_offset, error);
206     if (lres != DW_DLV_OK) {
207         return lres;
208     }
209 
210     if (line_offset >= dbg->de_debug_line.dss_size) {
211         _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
212         return (DW_DLV_ERROR);
213     }
214     orig_line_ptr = dbg->de_debug_line.dss_data;
215     line_ptr = dbg->de_debug_line.dss_data + line_offset;
216     dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);
217 
218     /*
219        If die has DW_AT_comp_dir attribute, get the string that names
220        the compilation directory. */
221     resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
222     if (resattr == DW_DLV_ERROR) {
223         return resattr;
224     }
225     if (resattr == DW_DLV_OK) {
226         int cres = DW_DLV_ERROR;
227         char *cdir = 0;
228 
229         cres = dwarf_formstring(comp_dir_attr, &cdir, error);
230         if (cres == DW_DLV_ERROR) {
231             return cres;
232         } else if (cres == DW_DLV_OK) {
233             comp_dir = (Dwarf_Small *) cdir;
234         }
235     }
236     if (resattr == DW_DLV_OK) {
237         dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
238     }
239 
240     dwarf_init_line_table_prefix(&prefix);
241     {
242         Dwarf_Small *line_ptr_out = 0;
243         int dres = dwarf_read_line_table_prefix(dbg,
244             line_ptr,dbg->de_debug_line.dss_size - line_offset,
245             &line_ptr_out,
246             &prefix,
247             &bogus_bytes_ptr,
248             &bogus_bytes_count,
249             error,
250             err_count_out);
251         if (dres == DW_DLV_ERROR) {
252             dwarf_free_line_table_prefix(&prefix);
253             return dres;
254         }
255         if (dres == DW_DLV_NO_ENTRY) {
256             dwarf_free_line_table_prefix(&prefix);
257             return dres;
258         }
259         line_ptr_end = prefix.pf_line_ptr_end;
260         line_ptr = line_ptr_out;
261     }
262     if(only_line_header) {
263          /* Just checking for header errors, nothing more here.*/
264          dwarf_free_line_table_prefix(&prefix);
265          return DW_DLV_OK;
266     }
267 
268 
269     printf("total line info length %ld bytes, "
270            "line offset 0x%" DW_PR_DUx " %" DW_PR_DSd "\n",
271            (long) prefix.pf_total_length,
272            (Dwarf_Unsigned) line_offset,
273            (Dwarf_Signed) line_offset);
274     printf("line table version %d\n",(int) prefix.pf_version);
275     printf("line table length field length %d prologue length %d\n",
276            (int)prefix.pf_length_field_length,
277            (int)prefix.pf_prologue_length);
278     printf("compilation_directory %s\n",
279            comp_dir ? ((char *) comp_dir) : "");
280 
281     printf("  min instruction length %d\n",
282            (int) prefix.pf_minimum_instruction_length);
283     printf("  default is stmt        %d\n", (int)
284            prefix.pf_default_is_stmt);
285     printf("  line base              %d\n", (int)
286            prefix.pf_line_base);
287     printf("  line_range             %d\n", (int)
288            prefix.pf_line_range);
289     printf("  opcode base            %d\n", (int)
290            prefix.pf_opcode_base);
291     printf("  standard opcode count  %d\n", (int)
292            prefix.pf_std_op_count);
293 
294     for (i = 1; i < prefix.pf_opcode_base; i++) {
295         printf("  opcode[%2d] length  %d\n", (int) i,
296                (int) prefix.pf_opcode_length_table[i - 1]);
297     }
298     printf("  include directories count %d\n", (int)
299            prefix.pf_include_directories_count);
300 
301 
302     for (i = 0; i < prefix.pf_include_directories_count; ++i) {
303         printf("  include dir[%d] %s\n",
304                (int) i, prefix.pf_include_directories[i]);
305     }
306     printf("  files count            %d\n", (int)
307            prefix.pf_files_count);
308 
309     for (i = 0; i < prefix.pf_files_count; ++i) {
310         struct Line_Table_File_Entry_s *lfile =
311             prefix.pf_line_table_file_entries + i;
312 
313         Dwarf_Unsigned tlm2 = lfile->lte_last_modification_time;
314         Dwarf_Unsigned di = lfile->lte_directory_index;
315         Dwarf_Unsigned fl = lfile->lte_length_of_file;
316 
317         printf("  file[%d]  %s (file-number: %d) \n",
318                (int) i, (char *) lfile->lte_filename,
319                (int)(i+1));
320 
321         printf("    dir index %d\n", (int) di);
322         {
323             time_t tt = (time_t) tlm2;
324 
325             printf("    last time 0x%x %s",     /* ctime supplies
326                                                    newline */
327                    (unsigned) tlm2, ctime(&tt));
328         }
329         printf("    file length %ld 0x%lx\n",
330                (long) fl, (unsigned long) fl);
331 
332 
333     }
334 
335 
336     {
337         Dwarf_Unsigned offset = 0;
338         if(bogus_bytes_count > 0) {
339             Dwarf_Unsigned wcount = bogus_bytes_count;
340             Dwarf_Unsigned boffset = bogus_bytes_ptr - orig_line_ptr;
341             printf("*** DWARF CHECK: the line table prologue  header_length "
342                 " is %" DW_PR_DUu " too high, we pretend it is smaller."
343                 "Section offset: %" DW_PR_DUu " (0x%" DW_PR_DUx ") ***\n",
344                 wcount, boffset,boffset);
345             *err_count_out += 1;
346         }
347         offset = line_ptr - orig_line_ptr;
348 
349         printf("  statement prog offset in section: %" DW_PR_DUu " 0x%" DW_PR_DUx "\n",
350                offset, offset);
351     }
352 
353     /* Initialize the part of the state machine dependent on the
354        prefix.  */
355     is_stmt = prefix.pf_default_is_stmt;
356 
357 
358     print_line_header();
359     /* Start of statement program.  */
360     while (line_ptr < line_ptr_end) {
361         int type = 0;
362 
363         printf(" [0x%06" DW_PR_DSx "] ",
364             (Dwarf_Signed) (line_ptr - orig_line_ptr));
365         opcode = *(Dwarf_Small *) line_ptr;
366         line_ptr++;
367         /* 'type' is the output */
368         WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base,
369                        prefix.pf_opcode_length_table, line_ptr,
370                        prefix.pf_std_op_count);
371 
372         if (type == LOP_DISCARD) {
373             int oc;
374             int opcnt = prefix.pf_opcode_length_table[opcode];
375 
376             printf("*** DWARF CHECK: DISCARD standard opcode %d "
377                 "with %d operands: "
378                 "not understood.", opcode, opcnt);
379             *err_count_out += 1;
380             for (oc = 0; oc < opcnt; oc++) {
381                 /*
382                  * Read and discard operands we don't
383                  * understand.
384                  * Arbitrary choice of unsigned read.
385                  * Signed read would work as well.
386                  */
387                 Dwarf_Unsigned utmp2;
388 
389                 DECODE_LEB128_UWORD(line_ptr, utmp2);
390                 printf(" %" DW_PR_DUu " (0x%" DW_PR_DUx ")",
391                        (Dwarf_Unsigned) utmp2,
392                        (Dwarf_Unsigned) utmp2);
393             }
394 
395             printf("***\n");
396             /* do nothing, necessary ops done */
397         } else if (type == LOP_SPECIAL) {
398             /* This op code is a special op in the object, no matter
399                that it might fall into the standard op range in this
400                compile Thatis, these are special opcodes between
401                special_opcode_base and MAX_LINE_OP_CODE.  (including
402                special_opcode_base and MAX_LINE_OP_CODE) */
403             char special[50];
404             unsigned origop = opcode;
405 
406             opcode = opcode - prefix.pf_opcode_base;
407             address = address + prefix.pf_minimum_instruction_length *
408                 (opcode / prefix.pf_line_range);
409             line =
410                 line + prefix.pf_line_base +
411                 opcode % prefix.pf_line_range;
412 
413             sprintf(special, "Specialop %3u", origop);
414             print_line_detail(special,
415                               opcode, address, (int) file, line, column,
416                               is_stmt, basic_block, end_sequence,
417                               prologue_end, epilogue_begin, isa);
418 
419             basic_block = false;
420 
421         } else if (type == LOP_STANDARD) {
422             switch (opcode) {
423 
424             case DW_LNS_copy:{
425 
426                     print_line_detail("DW_LNS_copy",
427                                       opcode, address, file, line,
428                                       column, is_stmt, basic_block,
429                                       end_sequence, prologue_end,
430                                       epilogue_begin, isa);
431 
432                     basic_block = false;
433                     break;
434                 }
435 
436             case DW_LNS_advance_pc:{
437                     Dwarf_Unsigned utmp2;
438 
439 
440                     DECODE_LEB128_UWORD(line_ptr, utmp2);
441                     printf("DW_LNS_advance_pc val %" DW_PR_DSd " 0x%" DW_PR_DUx "\n",
442                            (Dwarf_Signed) (Dwarf_Word) utmp2,
443                            (Dwarf_Unsigned) (Dwarf_Word) utmp2);
444                     leb128_num = (Dwarf_Word) utmp2;
445                     address =
446                         address +
447                         prefix.pf_minimum_instruction_length *
448                         leb128_num;
449                     break;
450                 }
451 
452             case DW_LNS_advance_line:{
453                     Dwarf_Signed stmp;
454 
455 
456                     DECODE_LEB128_SWORD(line_ptr, stmp);
457                     advance_line = (Dwarf_Sword) stmp;
458                     printf("DW_LNS_advance_line val %" DW_PR_DSd " 0x%" DW_PR_DSx "\n",
459                            (Dwarf_Signed) advance_line,
460                            (Dwarf_Signed) advance_line);
461                     line = line + advance_line;
462                     break;
463                 }
464 
465             case DW_LNS_set_file:{
466                     Dwarf_Unsigned utmp2;
467 
468 
469                     DECODE_LEB128_UWORD(line_ptr, utmp2);
470                     file = (Dwarf_Word) utmp2;
471                     printf("DW_LNS_set_file  %ld\n", (long) file);
472                     break;
473                 }
474 
475             case DW_LNS_set_column:{
476                     Dwarf_Unsigned utmp2;
477 
478 
479                     DECODE_LEB128_UWORD(line_ptr, utmp2);
480                     column = (Dwarf_Word) utmp2;
481                     printf("DW_LNS_set_column val %" DW_PR_DSd " 0x%" DW_PR_DSx "\n",
482                            (Dwarf_Signed) column, (Dwarf_Signed) column);
483                     break;
484                 }
485 
486             case DW_LNS_negate_stmt:{
487                     is_stmt = !is_stmt;
488                     printf("DW_LNS_negate_stmt\n");
489                     break;
490                 }
491 
492             case DW_LNS_set_basic_block:{
493 
494                     printf("DW_LNS_set_basic_block\n");
495                     basic_block = true;
496                     break;
497                 }
498 
499             case DW_LNS_const_add_pc:{
500                     opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base;
501                     address =
502                         address +
503                         prefix.pf_minimum_instruction_length * (opcode /
504                                                                 prefix.
505                                                                 pf_line_range);
506 
507                     printf("DW_LNS_const_add_pc new address 0x%" DW_PR_DSx "\n",
508                            (Dwarf_Signed) address);
509                     break;
510                 }
511 
512             case DW_LNS_fixed_advance_pc:{
513 
514                     READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
515                                    line_ptr, sizeof(Dwarf_Half));
516                     line_ptr += sizeof(Dwarf_Half);
517                     address = address + fixed_advance_pc;
518                     printf("DW_LNS_fixed_advance_pc val %" DW_PR_DSd
519                        " 0x%" DW_PR_DSx " new address 0x%" DW_PR_DSx "\n",
520                            (Dwarf_Signed) fixed_advance_pc,
521                            (Dwarf_Signed) fixed_advance_pc,
522                            (Dwarf_Signed) address);
523                     break;
524                 }
525             case DW_LNS_set_prologue_end:{
526 
527                     prologue_end = true;
528                     printf("DW_LNS_set_prologue_end set true.\n");
529                     break;
530 
531 
532                 }
533                 /* New in DWARF3 */
534             case DW_LNS_set_epilogue_begin:{
535                     epilogue_begin = true;
536                     printf("DW_LNS_set_epilogue_begin set true.\n");
537                     break;
538                 }
539 
540                 /* New in DWARF3 */
541             case DW_LNS_set_isa:{
542                     Dwarf_Unsigned utmp2;
543 
544                     DECODE_LEB128_UWORD(line_ptr, utmp2);
545                     isa = utmp2;
546                     printf("DW_LNS_set_isa new value 0x%" DW_PR_DUx ".\n",
547                            (Dwarf_Unsigned) utmp2);
548                     if (isa != utmp2) {
549                         /* The value of the isa did not fit in our
550                            local so we record it wrong. declare an
551                            error. */
552                         dwarf_free_line_table_prefix(&prefix);
553 
554                         _dwarf_error(dbg, error,
555                                      DW_DLE_LINE_NUM_OPERANDS_BAD);
556                         return (DW_DLV_ERROR);
557                     }
558                     break;
559                 }
560             }
561 
562 
563         } else if (type == LOP_EXTENDED) {
564             Dwarf_Unsigned utmp3 = 0;
565             Dwarf_Word instr_length = 0;
566             Dwarf_Small ext_opcode = 0;
567 
568             DECODE_LEB128_UWORD(line_ptr, utmp3);
569             instr_length = (Dwarf_Word) utmp3;
570             ext_opcode = *(Dwarf_Small *) line_ptr;
571             line_ptr++;
572             switch (ext_opcode) {
573 
574             case DW_LNE_end_sequence:{
575                     end_sequence = true;
576 
577                     print_line_detail("DW_LNE_end_sequence extended",
578                                       opcode, address, file, line,
579                                       column, is_stmt, basic_block,
580                                       end_sequence, prologue_end,
581                                       epilogue_begin, isa);
582 
583                     address = 0;
584                     file = 1;
585                     line = 1;
586                     column = 0;
587                     is_stmt = prefix.pf_default_is_stmt;
588                     basic_block = false;
589                     end_sequence = false;
590                     prologue_end = false;
591                     epilogue_begin = false;
592 
593 
594                     break;
595                 }
596 
597             case DW_LNE_set_address:{
598                     {
599                         READ_UNALIGNED(dbg, address, Dwarf_Addr,
600                                        line_ptr,
601                                        die->di_cu_context->cc_address_size);
602 
603                         line_ptr += die->di_cu_context->cc_address_size;
604                         printf("DW_LNE_set_address address 0x%" DW_PR_DUx "\n",
605                                (Dwarf_Unsigned) address);
606                     }
607 
608                     break;
609                 }
610 
611             case DW_LNE_define_file:{
612                     Dwarf_Unsigned di = 0;
613                     Dwarf_Unsigned tlm = 0;
614                     Dwarf_Unsigned fl = 0;
615 
616                     Dwarf_Small *fn = (Dwarf_Small *) line_ptr;
617                     line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
618 
619                     di = _dwarf_decode_u_leb128(line_ptr,
620                                                 &leb128_length);
621                     line_ptr = line_ptr + leb128_length;
622 
623                     tlm = _dwarf_decode_u_leb128(line_ptr,
624                                                  &leb128_length);
625                     line_ptr = line_ptr + leb128_length;
626 
627                     fl = _dwarf_decode_u_leb128(line_ptr,
628                                                 &leb128_length);
629                     line_ptr = line_ptr + leb128_length;
630 
631 
632                     printf("DW_LNE_define_file %s \n", fn);
633                     printf("    dir index %d\n", (int) di);
634                     {
635                         time_t tt3 = (time_t) tlm;
636 
637                         /* ctime supplies newline */
638                         printf("    last time 0x%x %s",
639                                (unsigned) tlm, ctime(&tt3));
640                     }
641                     printf("    file length %ld 0x%lx\n",
642                            (long) fl, (unsigned long) fl);
643 
644                     break;
645                 }
646 
647             default:{
648                  /* This is an extended op code we do not know about,
649                     other than we know now many bytes it is
650                     (and the op code and the bytes of operand). */
651 
652                  Dwarf_Unsigned remaining_bytes = instr_length -1;
653                  if(instr_length < 1 || remaining_bytes > DW_LNE_LEN_MAX) {
654                       dwarf_free_line_table_prefix(&prefix);
655                       _dwarf_error(dbg, error,
656                                  DW_DLE_LINE_EXT_OPCODE_BAD);
657                       return (DW_DLV_ERROR);
658                  }
659                  printf("DW_LNE extended op 0x%x ",ext_opcode);
660                  printf("Bytecount: " DW_PR_DUu , instr_length);
661                  if(remaining_bytes > 0) {
662                      printf(" linedata: 0x");
663                      while (remaining_bytes > 0) {
664                         printf("%02x",(unsigned char)(*(line_ptr)));
665                         line_ptr++;
666                         remaining_bytes--;
667                      }
668                  }
669                  printf("\n");
670                 }
671                 break;
672             }
673 
674         }
675     }
676 
677     dwarf_free_line_table_prefix(&prefix);
678     return (DW_DLV_OK);
679 }
680 
681 /*
682         This is support for dwarfdump: making it possible
683         for clients wanting line detail info on stdout
684         to get that detail without including internal libdwarf
685         header information.
686         Caller passes in compilation unit DIE.
687         The _dwarf_ version is obsolete (though supported for
688         compatibility).
689         The dwarf_ version is preferred.
690         The functions are intentionally identical: having
691         _dwarf_print_lines call dwarf_print_lines might
692         better emphasize they are intentionally identical, but
693         that seemed slightly silly given how short the functions are.
694         Interface adds error_count (output value) February 2009.
695 */
696 int
697 dwarf_print_lines(Dwarf_Die die, Dwarf_Error * error,int *error_count)
698 {
699     int only_line_header = 0;
700     int res = _dwarf_internal_printlines(die, error,
701         error_count,
702         only_line_header);
703     if (res != DW_DLV_OK) {
704         return res;
705     }
706     return res;
707 }
708 int
709 _dwarf_print_lines(Dwarf_Die die, Dwarf_Error * error)
710 {
711     int only_line_header = 0;
712     int err_count = 0;
713     int res = _dwarf_internal_printlines(die, error,
714         &err_count,
715         only_line_header);
716     /* No way to get error count back in this interface */
717     if (res != DW_DLV_OK) {
718         return res;
719     }
720     return res;
721 }
722 
723 /* The check is in case we are not printing full line data,
724    this gets some of the issues noted with .debug_line,
725    but not all. Call dwarf_print_lines() to get all issues.
726    Intended for apps like dwarfdump.
727 */
728 void
729 dwarf_check_lineheader(Dwarf_Die die, int *err_count_out)
730 {
731     Dwarf_Error err;
732     int only_line_header = 1;
733     _dwarf_internal_printlines(die, &err,err_count_out,
734         only_line_header);
735     return;
736 }
737 
738