1 /* xcoff.c -- Get debug data from an XCOFF file for backtraces.
2 Copyright (C) 2012-2024 Free Software Foundation, Inc.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
12 (2) Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
17 (3) The name of the author may not be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE. */
38 #include <sys/types.h>
44 #include "backtrace.h"
47 /* The configure script must tell us whether we are 32-bit or 64-bit
48 XCOFF. We could make this code test and support either possibility,
49 but there is no point. This code only works for the currently
50 running executable, which means that we know the XCOFF mode at
53 #if BACKTRACE_XCOFF_SIZE != 32 && BACKTRACE_XCOFF_SIZE != 64
54 #error "Unknown BACKTRACE_XCOFF_SIZE"
57 /* XCOFF file header. */
59 #if BACKTRACE_XCOFF_SIZE == 32
71 #define XCOFF_MAGIC 0737
73 #else /* BACKTRACE_XCOFF_SIZE != 32 */
85 #define XCOFF_MAGIC 0767
87 #endif /* BACKTRACE_XCOFF_SIZE != 32 */
89 #define F_SHROBJ 0x2000 /* File is a shared object. */
91 /* XCOFF section header. */
93 #if BACKTRACE_XCOFF_SIZE == 32
108 #define _OVERFLOW_MARKER 65535
110 #else /* BACKTRACE_XCOFF_SIZE != 32 */
125 #endif /* BACKTRACE_XCOFF_SIZE != 32 */
127 #define STYP_DWARF 0x10 /* DWARF debugging section. */
128 #define STYP_TEXT 0x20 /* Executable text (code) section. */
129 #define STYP_OVRFLO 0x8000 /* Line-number field overflow section. */
131 #define SSUBTYP_DWINFO 0x10000 /* DWARF info section. */
132 #define SSUBTYP_DWLINE 0x20000 /* DWARF line-number section. */
133 #define SSUBTYP_DWARNGE 0x50000 /* DWARF aranges section. */
134 #define SSUBTYP_DWABREV 0x60000 /* DWARF abbreviation section. */
135 #define SSUBTYP_DWSTR 0x70000 /* DWARF strings section. */
136 #define SSUBTYP_DWRNGES 0x80000 /* DWARF ranges section. */
142 #if BACKTRACE_XCOFF_SIZE == 32
146 char _name
[SYMNMLEN
];
152 #define n_name _u._name
153 #define n_zeroes _u._s._zeroes
154 #define n_offset_ _u._s._offset
161 } __attribute__ ((packed
)) b_xcoff_syment
;
163 #else /* BACKTRACE_XCOFF_SIZE != 32 */
172 } __attribute__ ((packed
)) b_xcoff_syment
;
174 #endif /* BACKTRACE_XCOFF_SIZE != 32 */
178 #define C_EXT 2 /* External symbol. */
179 #define C_FCN 101 /* Beginning or end of function. */
180 #define C_FILE 103 /* Source file name. */
181 #define C_HIDEXT 107 /* Unnamed external symbol. */
182 #define C_BINCL 108 /* Beginning of include file. */
183 #define C_EINCL 109 /* End of include file. */
184 #define C_WEAKEXT 111 /* Weak external symbol. */
186 #define ISFCN(x) ((x) & 0x0020)
188 /* XCOFF AUX entry. */
194 #if BACKTRACE_XCOFF_SIZE == 32
206 char x_fname
[FILNMLEN
];
210 char pad
[FILNMLEN
-8];
214 #if BACKTRACE_XCOFF_SIZE == 32
229 uint8_t pad
[AUXESZ
-1];
232 } __attribute__ ((packed
)) b_xcoff_auxent
;
234 /* XCOFF line number entry. */
236 #if BACKTRACE_XCOFF_SIZE == 32
248 #else /* BACKTRACE_XCOFF_SIZE != 32 */
260 #endif /* BACKTRACE_XCOFF_SIZE != 32 */
262 #if BACKTRACE_XCOFF_SIZE == 32
263 #define XCOFF_AIX_TEXTBASE 0x10000000u
265 #define XCOFF_AIX_TEXTBASE 0x100000000ul
268 /* AIX big archive fixed-length header. */
270 #define AIAMAGBIG "<bigaf>\n"
273 char fl_magic
[8]; /* Archive magic string. */
274 char fl_memoff
[20]; /* Offset to member table. */
275 char fl_gstoff
[20]; /* Offset to global symbol table. */
276 char fl_gst64off
[20]; /* Offset to global symbol table for 64-bit objects. */
277 char fl_fstmoff
[20]; /* Offset to first archive member. */
278 char fl_freeoff
[20]; /* Offset to first member on free list. */
281 /* AIX big archive file member header. */
284 char ar_size
[20]; /* File member size - decimal. */
285 char ar_nxtmem
[20]; /* Next member offset - decimal. */
286 char ar_prvmem
[20]; /* Previous member offset - decimal. */
287 char ar_date
[12]; /* File member date - decimal. */
288 char ar_uid
[12]; /* File member userid - decimal. */
289 char ar_gid
[12]; /* File member group id - decimal. */
290 char ar_mode
[12]; /* File member mode - octal. */
291 char ar_namlen
[4]; /* File member name length - decimal. */
292 char ar_name
[2]; /* Start of member name. */
296 /* Information we keep for an XCOFF symbol. */
300 /* The name of the symbol. */
302 /* The address of the symbol. */
304 /* The size of the symbol. */
308 /* Information to pass to xcoff_syminfo. */
310 struct xcoff_syminfo_data
312 /* Symbols for the next module. */
313 struct xcoff_syminfo_data
*next
;
314 /* The XCOFF symbols, sorted by address. */
315 struct xcoff_symbol
*symbols
;
316 /* The number of symbols. */
320 /* Information about an include file. */
325 const char *filename
;
326 /* Offset to first line number from the include file. */
328 /* Offset to last line number from the include file. */
332 /* A growable vector of include files information. */
334 struct xcoff_incl_vector
336 /* Memory. This is an array of struct xcoff_incl. */
337 struct backtrace_vector vec
;
338 /* Number of include files. */
342 /* A growable vector of functions information. */
348 /* The size of the function. */
353 const char *filename
;
354 /* Pointer to first lnno entry. */
356 /* Base address of containing section. */
358 /* Starting source line number. */
362 /* A growable vector of function information. This is used while
363 reading the function symbols. */
365 struct xcoff_func_vector
367 /* Memory. This is an array of struct xcoff_func. */
368 struct backtrace_vector vec
;
369 /* Number of valid mappings. */
373 /* The information we need to map a PC to a file and line. */
375 struct xcoff_fileline_data
377 /* The data for the next file we know about. */
378 struct xcoff_fileline_data
*next
;
379 /* Functions information. */
380 struct xcoff_func_vector func_vec
;
381 /* Include files information. */
382 struct xcoff_incl_vector incl_vec
;
383 /* Line numbers information. */
384 const unsigned char *linenos
;
387 /* Loader address. */
388 struct libbacktrace_base_address base_address
;
391 /* Information we gather for the DWARF sections we care about. */
395 /* Section file offset. */
399 /* Section contents, after read from file. */
400 const unsigned char *data
;
403 /* A dummy callback function used when we can't find any debug info. */
406 xcoff_nodebug (struct backtrace_state
*state ATTRIBUTE_UNUSED
,
407 uintptr_t pc ATTRIBUTE_UNUSED
,
408 backtrace_full_callback callback ATTRIBUTE_UNUSED
,
409 backtrace_error_callback error_callback
, void *data
)
411 error_callback (data
, "no debug info in XCOFF executable", -1);
415 /* A dummy callback function used when we can't find a symbol
419 xcoff_nosyms (struct backtrace_state
*state ATTRIBUTE_UNUSED
,
420 uintptr_t addr ATTRIBUTE_UNUSED
,
421 backtrace_syminfo_callback callback ATTRIBUTE_UNUSED
,
422 backtrace_error_callback error_callback
, void *data
)
424 error_callback (data
, "no symbol table in XCOFF executable", -1);
427 /* Compare struct xcoff_symbol for qsort. */
430 xcoff_symbol_compare (const void *v1
, const void *v2
)
432 const struct xcoff_symbol
*e1
= (const struct xcoff_symbol
*) v1
;
433 const struct xcoff_symbol
*e2
= (const struct xcoff_symbol
*) v2
;
435 if (e1
->address
< e2
->address
)
437 else if (e1
->address
> e2
->address
)
443 /* Compare an ADDR against an xcoff_symbol for bsearch. */
446 xcoff_symbol_search (const void *vkey
, const void *ventry
)
448 const uintptr_t *key
= (const uintptr_t *) vkey
;
449 const struct xcoff_symbol
*entry
= (const struct xcoff_symbol
*) ventry
;
453 if (addr
< entry
->address
)
455 else if ((entry
->size
== 0 && addr
> entry
->address
)
456 || (entry
->size
> 0 && addr
>= entry
->address
+ entry
->size
))
462 /* Add XDATA to the list in STATE. */
465 xcoff_add_syminfo_data (struct backtrace_state
*state
,
466 struct xcoff_syminfo_data
*xdata
)
468 if (!state
->threaded
)
470 struct xcoff_syminfo_data
**pp
;
472 for (pp
= (struct xcoff_syminfo_data
**) (void *) &state
->syminfo_data
;
482 struct xcoff_syminfo_data
**pp
;
484 pp
= (struct xcoff_syminfo_data
**) (void *) &state
->syminfo_data
;
488 struct xcoff_syminfo_data
*p
;
490 p
= backtrace_atomic_load_pointer (pp
);
498 if (__sync_bool_compare_and_swap (pp
, NULL
, xdata
))
504 /* Return the symbol name and value for an ADDR. */
507 xcoff_syminfo (struct backtrace_state
*state ATTRIBUTE_UNUSED
, uintptr_t addr
,
508 backtrace_syminfo_callback callback
,
509 backtrace_error_callback error_callback ATTRIBUTE_UNUSED
,
512 struct xcoff_syminfo_data
*edata
;
513 struct xcoff_symbol
*sym
= NULL
;
516 if (!state
->threaded
)
518 for (edata
= (struct xcoff_syminfo_data
*) state
->syminfo_data
;
522 sym
= ((struct xcoff_symbol
*)
523 bsearch (&addr
, edata
->symbols
, edata
->count
,
524 sizeof (struct xcoff_symbol
), xcoff_symbol_search
));
531 struct xcoff_syminfo_data
**pp
;
533 pp
= (struct xcoff_syminfo_data
**) (void *) &state
->syminfo_data
;
536 edata
= backtrace_atomic_load_pointer (pp
);
540 sym
= ((struct xcoff_symbol
*)
541 bsearch (&addr
, edata
->symbols
, edata
->count
,
542 sizeof (struct xcoff_symbol
), xcoff_symbol_search
));
551 callback (data
, addr
, NULL
, 0, 0);
555 /* AIX prepends a '.' to function entry points, remove it. */
556 if (name
&& *name
== '.')
558 callback (data
, addr
, name
, sym
->address
, sym
->size
);
562 /* Return the name of an XCOFF symbol. */
565 xcoff_symname (const b_xcoff_syment
*asym
,
566 const unsigned char *strtab
, size_t strtab_size
)
568 #if BACKTRACE_XCOFF_SIZE == 32
569 if (asym
->n_zeroes
!= 0)
571 /* Make a copy as we will release the symtab view. */
572 char name
[SYMNMLEN
+1];
573 strncpy (name
, asym
->n_name
, SYMNMLEN
);
574 name
[SYMNMLEN
] = '\0';
575 return strdup (name
);
578 if (asym
->n_sclass
& 0x80)
579 return NULL
; /* .debug */
580 if (asym
->n_offset_
>= strtab_size
)
582 return (const char *) strtab
+ asym
->n_offset_
;
585 /* Initialize the symbol table info for xcoff_syminfo. */
588 xcoff_initialize_syminfo (struct backtrace_state
*state
,
589 struct libbacktrace_base_address base_address
,
590 const b_xcoff_syment
*syms
, size_t nsyms
,
591 const unsigned char *strtab
, size_t strtab_size
,
592 backtrace_error_callback error_callback
, void *data
,
593 struct xcoff_syminfo_data
*sdata
)
595 size_t xcoff_symbol_count
;
596 size_t xcoff_symbol_size
;
597 struct xcoff_symbol
*xcoff_symbols
;
601 /* We only care about function symbols. Count them. */
602 xcoff_symbol_count
= 0;
603 for (i
= 0; i
< nsyms
; ++i
)
605 const b_xcoff_syment
*asym
= &syms
[i
];
606 if ((asym
->n_sclass
== C_EXT
|| asym
->n_sclass
== C_HIDEXT
607 || asym
->n_sclass
== C_WEAKEXT
)
608 && ISFCN (asym
->n_type
) && asym
->n_numaux
> 0 && asym
->n_scnum
> 0)
609 ++xcoff_symbol_count
;
614 xcoff_symbol_size
= xcoff_symbol_count
* sizeof (struct xcoff_symbol
);
615 xcoff_symbols
= ((struct xcoff_symbol
*)
616 backtrace_alloc (state
, xcoff_symbol_size
, error_callback
,
618 if (xcoff_symbols
== NULL
)
622 for (i
= 0; i
< nsyms
; ++i
)
624 const b_xcoff_syment
*asym
= &syms
[i
];
625 if ((asym
->n_sclass
== C_EXT
|| asym
->n_sclass
== C_HIDEXT
626 || asym
->n_sclass
== C_WEAKEXT
)
627 && ISFCN (asym
->n_type
) && asym
->n_numaux
> 0 && asym
->n_scnum
> 0)
629 const b_xcoff_auxent
*aux
= (const b_xcoff_auxent
*) (asym
+ 1);
630 xcoff_symbols
[j
].name
= xcoff_symname (asym
, strtab
, strtab_size
);
631 xcoff_symbols
[j
].address
=
632 libbacktrace_add_base (asym
->n_value
, base_address
);
633 /* x_fsize will be 0 if there is no debug information. */
634 xcoff_symbols
[j
].size
= aux
->x_fcn
.x_fsize
;
641 backtrace_qsort (xcoff_symbols
, xcoff_symbol_count
,
642 sizeof (struct xcoff_symbol
), xcoff_symbol_compare
);
645 sdata
->symbols
= xcoff_symbols
;
646 sdata
->count
= xcoff_symbol_count
;
651 /* Compare struct xcoff_func for qsort. */
654 xcoff_func_compare (const void *v1
, const void *v2
)
656 const struct xcoff_func
*fn1
= (const struct xcoff_func
*) v1
;
657 const struct xcoff_func
*fn2
= (const struct xcoff_func
*) v2
;
659 if (fn1
->pc
< fn2
->pc
)
661 else if (fn1
->pc
> fn2
->pc
)
667 /* Compare a PC against an xcoff_func for bsearch. */
670 xcoff_func_search (const void *vkey
, const void *ventry
)
672 const uintptr_t *key
= (const uintptr_t *) vkey
;
673 const struct xcoff_func
*entry
= (const struct xcoff_func
*) ventry
;
679 else if ((entry
->size
== 0 && pc
> entry
->pc
)
680 || (entry
->size
> 0 && pc
>= entry
->pc
+ entry
->size
))
686 /* Compare struct xcoff_incl for qsort. */
689 xcoff_incl_compare (const void *v1
, const void *v2
)
691 const struct xcoff_incl
*in1
= (const struct xcoff_incl
*) v1
;
692 const struct xcoff_incl
*in2
= (const struct xcoff_incl
*) v2
;
694 if (in1
->begin
< in2
->begin
)
696 else if (in1
->begin
> in2
->begin
)
702 /* Find a lnnoptr in an include file. */
705 xcoff_incl_search (const void *vkey
, const void *ventry
)
707 const uintptr_t *key
= (const uintptr_t *) vkey
;
708 const struct xcoff_incl
*entry
= (const struct xcoff_incl
*) ventry
;
712 if (lnno
< entry
->begin
)
714 else if (lnno
> entry
->end
)
720 /* Look for a PC in the function vector for one module. On success,
721 call CALLBACK and return whatever it returns. On error, call
722 ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found,
726 xcoff_lookup_pc (struct backtrace_state
*state ATTRIBUTE_UNUSED
,
727 struct xcoff_fileline_data
*fdata
, uintptr_t pc
,
728 backtrace_full_callback callback
,
729 backtrace_error_callback error_callback ATTRIBUTE_UNUSED
,
730 void *data
, int *found
)
732 const struct xcoff_incl
*incl
, *bincl
;
733 const struct xcoff_func
*fn
;
734 const b_xcoff_lineno
*lineno
;
735 const unsigned char *lineptr
;
736 const char *function
;
737 const char *filename
;
738 uintptr_t lnnoptr
, match
;
746 /* Find the function first. */
747 fn
= ((struct xcoff_func
*)
748 bsearch (&pc
, fdata
->func_vec
.vec
.base
, fdata
->func_vec
.count
,
749 sizeof (struct xcoff_func
), xcoff_func_search
));
756 filename
= fn
->filename
;
758 /* Find the line number next. */
760 /* Skip first entry that points to symtab. */
761 lnnoptr
= fn
->lnnoptr
+ LINESZ
;
764 lineptr
= fdata
->linenos
+ (lnnoptr
- fdata
->lnnoptr0
);
765 while (lineptr
+ LINESZ
<= fdata
->linenos
+ fdata
->linenos_size
)
767 lineno
= (const b_xcoff_lineno
*) lineptr
;
768 if (lineno
->l_lnno
== 0)
770 if (pc
<= libbacktrace_add_base (lineno
->l_addr
.l_paddr
,
771 fdata
->base_address
))
774 lnno
= lineno
->l_lnno
;
780 /* If part of a function other than the beginning comes from an
781 include file, the line numbers are absolute, rather than
782 relative to the beginning of the function. */
783 incl
= ((struct xcoff_incl
*)
784 bsearch (&match
, fdata
->incl_vec
.vec
.base
,
785 fdata
->incl_vec
.count
, sizeof (struct xcoff_incl
),
789 bincl
= ((struct xcoff_incl
*)
790 bsearch (&fn
->lnnoptr
, fdata
->incl_vec
.vec
.base
,
791 fdata
->incl_vec
.count
, sizeof (struct xcoff_incl
),
793 if (bincl
!= NULL
&& strcmp (incl
->filename
, bincl
->filename
) == 0)
795 lnno
+= fn
->lnno
- 1;
797 filename
= incl
->filename
;
801 lnno
+= fn
->lnno
- 1;
805 /* AIX prepends a '.' to function entry points, remove it. */
806 if (function
!= NULL
&& *function
== '.')
808 return callback (data
, pc
, filename
, lnno
, function
);
811 /* Return the file/line information for a PC using the XCOFF lineno
812 mapping we built earlier. */
815 xcoff_fileline (struct backtrace_state
*state
, uintptr_t pc
,
816 backtrace_full_callback callback
,
817 backtrace_error_callback error_callback
, void *data
)
820 struct xcoff_fileline_data
*fdata
;
824 if (!state
->threaded
)
826 for (fdata
= (struct xcoff_fileline_data
*) state
->fileline_data
;
830 ret
= xcoff_lookup_pc (state
, fdata
, pc
, callback
, error_callback
,
832 if (ret
!= 0 || found
)
838 struct xcoff_fileline_data
**pp
;
840 pp
= (struct xcoff_fileline_data
**) (void *) &state
->fileline_data
;
843 fdata
= backtrace_atomic_load_pointer (pp
);
847 ret
= xcoff_lookup_pc (state
, fdata
, pc
, callback
, error_callback
,
849 if (ret
!= 0 || found
)
856 /* FIXME: See if any libraries have been dlopen'ed. */
858 return callback (data
, pc
, NULL
, 0, NULL
);
861 /* Initialize the function vector info for xcoff_fileline. */
864 xcoff_initialize_fileline (struct backtrace_state
*state
,
865 struct libbacktrace_base_address base_address
,
866 const b_xcoff_scnhdr
*sects
,
867 const b_xcoff_syment
*syms
, size_t nsyms
,
868 const unsigned char *strtab
, size_t strtab_size
,
869 const unsigned char *linenos
, size_t linenos_size
,
871 backtrace_error_callback error_callback
, void *data
)
873 struct xcoff_fileline_data
*fdata
;
874 struct xcoff_func
*fn
;
875 const b_xcoff_syment
*fsym
;
876 const b_xcoff_auxent
*aux
;
877 const char *filename
;
879 struct xcoff_incl
*incl
;
880 uintptr_t begin
, end
;
881 uintptr_t lnno
, lnnoptr
;
885 fdata
= ((struct xcoff_fileline_data
*)
886 backtrace_alloc (state
, sizeof (struct xcoff_fileline_data
),
887 error_callback
, data
));
890 memset (fdata
, 0, sizeof *fdata
);
891 fdata
->base_address
= base_address
;
892 fdata
->linenos
= linenos
;
893 fdata
->linenos_size
= linenos_size
;
894 fdata
->lnnoptr0
= lnnoptr0
;
901 for (i
= 0; i
< nsyms
; ++i
)
903 const b_xcoff_syment
*asym
= &syms
[i
];
905 switch (asym
->n_sclass
)
908 begin
= asym
->n_value
;
915 incl
= ((struct xcoff_incl
*)
916 backtrace_vector_grow (state
, sizeof (struct xcoff_incl
),
917 error_callback
, data
,
918 &fdata
->incl_vec
.vec
));
921 incl
->filename
= xcoff_symname (asym
, strtab
, strtab_size
);
924 ++fdata
->incl_vec
.count
;
930 filename
= xcoff_symname (asym
, strtab
, strtab_size
);
931 if (filename
== NULL
)
934 /* If the file auxiliary entry is not used, the symbol name is
935 the name of the source file. If the file auxiliary entry is
936 used, then the symbol name should be .file, and the first
937 file auxiliary entry (by convention) contains the source
940 if (asym
->n_numaux
> 0 && strcmp (filename
, ".file") == 0)
942 aux
= (const b_xcoff_auxent
*) (asym
+ 1);
943 if (aux
->x_file
._x
.x_zeroes
!= 0)
945 /* Make a copy as we will release the symtab view. */
946 char name
[FILNMLEN
+1];
947 strncpy (name
, aux
->x_file
.x_fname
, FILNMLEN
);
948 name
[FILNMLEN
] = '\0';
949 filename
= strdup (name
);
951 else if (aux
->x_file
._x
.x_offset
< strtab_size
)
952 filename
= (const char *) strtab
+ aux
->x_file
._x
.x_offset
;
964 if (!ISFCN (asym
->n_type
) || asym
->n_numaux
== 0
965 || asym
->n_scnum
<= 0)
967 if (filename
== NULL
)
969 aux
= (const b_xcoff_auxent
*) (asym
+ 1);
970 lnnoptr
= aux
->x_fcn
.x_lnnoptr
;
971 if (lnnoptr
< lnnoptr0
972 || lnnoptr
+ LINESZ
> lnnoptr0
+ linenos_size
)
974 /* x_fsize will be 0 if there is no debug information. */
975 fsize
= aux
->x_fcn
.x_fsize
;
980 if (asym
->n_numaux
== 0)
984 name
= xcoff_symname (asym
, strtab
, strtab_size
);
985 if (name
== NULL
|| strcmp (name
, ".bf") != 0)
990 aux
= (const b_xcoff_auxent
*) (asym
+ 1);
991 #if BACKTRACE_XCOFF_SIZE == 32
992 lnno
= (uint32_t) aux
->x_block
.x_lnnohi
<< 16
993 | aux
->x_block
.x_lnno
;
995 lnno
= aux
->x_block
.x_lnno
;
997 fn
= ((struct xcoff_func
*)
998 backtrace_vector_grow (state
, sizeof (struct xcoff_func
),
999 error_callback
, data
,
1000 &fdata
->func_vec
.vec
));
1003 fn
->name
= xcoff_symname (fsym
, strtab
, strtab_size
);
1004 fn
->filename
= filename
;
1005 fn
->sect_base
= sects
[fsym
->n_scnum
- 1].s_paddr
;
1006 fn
->pc
= libbacktrace_add_base (fsym
->n_value
, base_address
);
1009 fn
->lnnoptr
= lnnoptr
;
1010 ++fdata
->func_vec
.count
;
1014 i
+= asym
->n_numaux
;
1017 if (!backtrace_vector_release (state
, &fdata
->func_vec
.vec
, error_callback
,
1020 backtrace_qsort (fdata
->func_vec
.vec
.base
, fdata
->func_vec
.count
,
1021 sizeof (struct xcoff_func
), xcoff_func_compare
);
1023 if (!backtrace_vector_release (state
, &fdata
->incl_vec
.vec
, error_callback
,
1026 backtrace_qsort (fdata
->incl_vec
.vec
.base
, fdata
->incl_vec
.count
,
1027 sizeof (struct xcoff_incl
), xcoff_incl_compare
);
1029 if (!state
->threaded
)
1031 struct xcoff_fileline_data
**pp
;
1033 for (pp
= (struct xcoff_fileline_data
**) (void *) &state
->fileline_data
;
1043 struct xcoff_fileline_data
**pp
;
1045 pp
= (struct xcoff_fileline_data
**) (void *) &state
->fileline_data
;
1049 struct xcoff_fileline_data
*p
;
1051 p
= backtrace_atomic_load_pointer (pp
);
1059 if (__sync_bool_compare_and_swap (pp
, NULL
, fdata
))
1070 /* Add the backtrace data for one XCOFF file. Returns 1 on success,
1071 0 on failure (in both cases descriptor is closed). */
1074 xcoff_add (struct backtrace_state
*state
, int descriptor
, off_t offset
,
1075 struct libbacktrace_base_address base_address
,
1076 backtrace_error_callback error_callback
,
1077 void *data
, fileline
*fileline_fn
, int *found_sym
, int exe
)
1079 struct backtrace_view fhdr_view
;
1080 struct backtrace_view sects_view
;
1081 struct backtrace_view linenos_view
;
1082 struct backtrace_view syms_view
;
1083 struct backtrace_view str_view
;
1084 struct backtrace_view dwarf_view
;
1085 b_xcoff_filhdr fhdr
;
1086 const b_xcoff_scnhdr
*sects
;
1087 const b_xcoff_scnhdr
*stext
;
1093 struct dwsect_info dwsect
[DEBUG_MAX
];
1097 int sects_view_valid
;
1098 int linenos_view_valid
;
1099 int syms_view_valid
;
1101 int dwarf_view_valid
;
1104 struct dwarf_sections dwarf_sections
;
1108 sects_view_valid
= 0;
1109 linenos_view_valid
= 0;
1110 syms_view_valid
= 0;
1112 dwarf_view_valid
= 0;
1116 /* Map the XCOFF file header. */
1117 if (!backtrace_get_view (state
, descriptor
, offset
, sizeof (b_xcoff_filhdr
),
1118 error_callback
, data
, &fhdr_view
))
1121 memcpy (&fhdr
, fhdr_view
.data
, sizeof fhdr
);
1122 magic_ok
= (fhdr
.f_magic
== XCOFF_MAGIC
);
1124 backtrace_release_view (state
, &fhdr_view
, error_callback
, data
);
1129 error_callback (data
, "executable file is not XCOFF", 0);
1133 /* Verify object is of expected type. */
1134 if ((exe
&& (fhdr
.f_flags
& F_SHROBJ
))
1135 || (!exe
&& !(fhdr
.f_flags
& F_SHROBJ
)))
1138 /* Read the section headers. */
1140 sects_size
= fhdr
.f_nscns
* sizeof (b_xcoff_scnhdr
);
1142 if (!backtrace_get_view (state
, descriptor
,
1143 offset
+ sizeof (fhdr
) + fhdr
.f_opthdr
,
1144 sects_size
, error_callback
, data
, §s_view
))
1146 sects_view_valid
= 1;
1147 sects
= (const b_xcoff_scnhdr
*) sects_view
.data
;
1149 /* FIXME: assumes only one .text section. */
1150 for (i
= 0; i
< fhdr
.f_nscns
; ++i
)
1151 if ((sects
[i
].s_flags
& 0xffff) == STYP_TEXT
)
1153 if (i
== fhdr
.f_nscns
)
1158 /* base_address represents the difference between the
1159 virtual memory address of the shared object or a loaded
1160 executable and the offset of that object in the file
1161 from which it was loaded.
1162 On AIX, virtual address is either fixed for executable
1163 or given by ldinfo. This address will include the XCOFF
1165 base_address
.m
= ((exe
? XCOFF_AIX_TEXTBASE
: base_address
.m
)
1169 lnnoptr
= stext
->s_lnnoptr
;
1170 nlnno
= stext
->s_nlnno
;
1172 #if BACKTRACE_XCOFF_SIZE == 32
1173 if (nlnno
== _OVERFLOW_MARKER
)
1176 /* Find the matching .ovrflo section. */
1177 for (i
= 0; i
< fhdr
.f_nscns
; ++i
)
1179 if (((sects
[i
].s_flags
& 0xffff) == STYP_OVRFLO
)
1180 && sects
[i
].s_nlnno
== sntext
)
1182 nlnno
= sects
[i
].s_vaddr
;
1189 /* Read the symbol table and the string table. */
1191 if (fhdr
.f_symptr
!= 0)
1193 struct xcoff_syminfo_data
*sdata
;
1195 /* Symbol table is followed by the string table. The string table
1196 starts with its length (on 4 bytes).
1197 Map the symbol table and the length of the string table. */
1198 syms_size
= fhdr
.f_nsyms
* sizeof (b_xcoff_syment
);
1200 if (!backtrace_get_view (state
, descriptor
, offset
+ fhdr
.f_symptr
,
1201 syms_size
+ 4, error_callback
, data
,
1204 syms_view_valid
= 1;
1207 (const unsigned char *) syms_view
.data
+ syms_size
,
1210 str_off
= fhdr
.f_symptr
+ syms_size
;
1214 /* Map string table (including the length word). */
1216 if (!backtrace_get_view (state
, descriptor
, offset
+ str_off
,
1217 str_size
, error_callback
, data
, &str_view
))
1222 sdata
= ((struct xcoff_syminfo_data
*)
1223 backtrace_alloc (state
, sizeof *sdata
, error_callback
, data
));
1227 if (!xcoff_initialize_syminfo (state
, base_address
,
1228 syms_view
.data
, fhdr
.f_nsyms
,
1229 str_view
.data
, str_size
,
1230 error_callback
, data
, sdata
))
1232 backtrace_free (state
, sdata
, sizeof *sdata
, error_callback
, data
);
1238 xcoff_add_syminfo_data (state
, sdata
);
1241 /* Read all the DWARF sections in a single view, since they are
1242 probably adjacent in the file. We never release this view. */
1246 memset (dwsect
, 0, sizeof dwsect
);
1247 for (i
= 0; i
< fhdr
.f_nscns
; ++i
)
1252 if ((sects
[i
].s_flags
& 0xffff) != STYP_DWARF
1253 || sects
[i
].s_size
== 0)
1255 /* Map DWARF section to array index. */
1256 switch (sects
[i
].s_flags
& 0xffff0000)
1258 case SSUBTYP_DWINFO
:
1261 case SSUBTYP_DWLINE
:
1264 case SSUBTYP_DWABREV
:
1267 case SSUBTYP_DWRNGES
:
1276 if (min_offset
== 0 || (off_t
) sects
[i
].s_scnptr
< min_offset
)
1277 min_offset
= sects
[i
].s_scnptr
;
1278 end
= sects
[i
].s_scnptr
+ sects
[i
].s_size
;
1279 if (end
> max_offset
)
1281 dwsect
[idx
].offset
= sects
[i
].s_scnptr
;
1282 dwsect
[idx
].size
= sects
[i
].s_size
;
1284 if (min_offset
!= 0 && max_offset
!= 0)
1286 if (!backtrace_get_view (state
, descriptor
, offset
+ min_offset
,
1287 max_offset
- min_offset
,
1288 error_callback
, data
, &dwarf_view
))
1290 dwarf_view_valid
= 1;
1292 for (i
= 0; i
< (int) DEBUG_MAX
; ++i
)
1294 if (dwsect
[i
].offset
== 0)
1295 dwsect
[i
].data
= NULL
;
1297 dwsect
[i
].data
= ((const unsigned char *) dwarf_view
.data
1298 + (dwsect
[i
].offset
- min_offset
));
1301 memset (&dwarf_sections
, 0, sizeof dwarf_sections
);
1303 dwarf_sections
.data
[DEBUG_INFO
] = dwsect
[DEBUG_INFO
].data
;
1304 dwarf_sections
.size
[DEBUG_INFO
] = dwsect
[DEBUG_INFO
].size
;
1305 dwarf_sections
.data
[DEBUG_LINE
] = dwsect
[DEBUG_LINE
].data
;
1306 dwarf_sections
.size
[DEBUG_LINE
] = dwsect
[DEBUG_LINE
].size
;
1307 dwarf_sections
.data
[DEBUG_ABBREV
] = dwsect
[DEBUG_ABBREV
].data
;
1308 dwarf_sections
.size
[DEBUG_ABBREV
] = dwsect
[DEBUG_ABBREV
].size
;
1309 dwarf_sections
.data
[DEBUG_RANGES
] = dwsect
[DEBUG_RANGES
].data
;
1310 dwarf_sections
.size
[DEBUG_RANGES
] = dwsect
[DEBUG_RANGES
].size
;
1311 dwarf_sections
.data
[DEBUG_STR
] = dwsect
[DEBUG_STR
].data
;
1312 dwarf_sections
.size
[DEBUG_STR
] = dwsect
[DEBUG_STR
].size
;
1314 if (!backtrace_dwarf_add (state
, base_address
, &dwarf_sections
,
1317 error_callback
, data
, fileline_fn
,
1318 NULL
/* returned fileline_entry */))
1322 /* Read the XCOFF line number entries if DWARF sections not found. */
1324 if (!dwarf_view_valid
&& fhdr
.f_symptr
!= 0 && lnnoptr
!= 0)
1326 size_t linenos_size
= (size_t) nlnno
* LINESZ
;
1328 /* We never release this view. */
1329 if (!backtrace_get_view (state
, descriptor
, offset
+ lnnoptr
,
1331 error_callback
, data
, &linenos_view
))
1333 linenos_view_valid
= 1;
1335 if (xcoff_initialize_fileline (state
, base_address
, sects
,
1336 syms_view
.data
, fhdr
.f_nsyms
,
1337 str_view
.data
, str_size
,
1338 linenos_view
.data
, linenos_size
,
1339 lnnoptr
, error_callback
, data
))
1340 *fileline_fn
= xcoff_fileline
;
1343 backtrace_release_view (state
, §s_view
, error_callback
, data
);
1344 sects_view_valid
= 0;
1345 if (syms_view_valid
)
1346 backtrace_release_view (state
, &syms_view
, error_callback
, data
);
1347 syms_view_valid
= 0;
1349 /* We've read all we need from the executable. */
1350 if (!backtrace_close (descriptor
, error_callback
, data
))
1357 if (sects_view_valid
)
1358 backtrace_release_view (state
, §s_view
, error_callback
, data
);
1360 backtrace_release_view (state
, &str_view
, error_callback
, data
);
1361 if (syms_view_valid
)
1362 backtrace_release_view (state
, &syms_view
, error_callback
, data
);
1363 if (linenos_view_valid
)
1364 backtrace_release_view (state
, &linenos_view
, error_callback
, data
);
1365 if (dwarf_view_valid
)
1366 backtrace_release_view (state
, &dwarf_view
, error_callback
, data
);
1367 if (descriptor
!= -1 && offset
== 0)
1368 backtrace_close (descriptor
, error_callback
, data
);
1372 #ifdef HAVE_LOADQUERY
1374 /* Read an integer value in human-readable format from an AIX
1375 big archive fixed-length or member header. */
1378 xcoff_parse_decimal (const char *buf
, size_t size
, off_t
*off
)
1383 if (size
>= sizeof str
)
1385 memcpy (str
, buf
, size
);
1387 *off
= strtol (str
, &end
, 10);
1388 if (*end
!= '\0' && *end
!= ' ')
1394 /* Add the backtrace data for a member of an AIX big archive.
1395 Returns 1 on success, 0 on failure. */
1398 xcoff_armem_add (struct backtrace_state
*state
, int descriptor
,
1399 struct libbacktrace_base_address base_address
,
1400 const char *member
, backtrace_error_callback error_callback
,
1401 void *data
, fileline
*fileline_fn
, int *found_sym
)
1403 struct backtrace_view view
;
1405 const b_ar_hdr
*ar_hdr
;
1412 /* Map archive fixed-length header. */
1414 if (!backtrace_get_view (state
, descriptor
, 0, sizeof (b_ar_fl_hdr
),
1415 error_callback
, data
, &view
))
1418 memcpy (&fl_hdr
, view
.data
, sizeof (b_ar_fl_hdr
));
1420 backtrace_release_view (state
, &view
, error_callback
, data
);
1422 if (memcmp (fl_hdr
.fl_magic
, AIAMAGBIG
, 8) != 0)
1425 memlen
= strlen (member
);
1427 /* Read offset of first archive member. */
1428 if (!xcoff_parse_decimal (fl_hdr
.fl_fstmoff
, sizeof fl_hdr
.fl_fstmoff
, &off
))
1432 /* Map archive member header and member name. */
1434 if (!backtrace_get_view (state
, descriptor
, off
,
1435 sizeof (b_ar_hdr
) + memlen
,
1436 error_callback
, data
, &view
))
1439 ar_hdr
= (const b_ar_hdr
*) view
.data
;
1441 /* Read archive member name length. */
1442 if (!xcoff_parse_decimal (ar_hdr
->ar_namlen
, sizeof ar_hdr
->ar_namlen
,
1445 backtrace_release_view (state
, &view
, error_callback
, data
);
1448 if (len
== memlen
&& !memcmp (ar_hdr
->ar_name
, member
, memlen
))
1450 off
= (off
+ sizeof (b_ar_hdr
) + memlen
+ 1) & ~1;
1452 /* The archive can contain several members with the same name
1453 (e.g. 32-bit and 64-bit), so continue if not ok. */
1455 if (xcoff_add (state
, descriptor
, off
, base_address
, error_callback
,
1456 data
, fileline_fn
, found_sym
, 0))
1458 backtrace_release_view (state
, &view
, error_callback
, data
);
1463 /* Read offset of next archive member. */
1464 if (!xcoff_parse_decimal (ar_hdr
->ar_nxtmem
, sizeof ar_hdr
->ar_nxtmem
,
1467 backtrace_release_view (state
, &view
, error_callback
, data
);
1470 backtrace_release_view (state
, &view
, error_callback
, data
);
1474 /* No matching member found. */
1475 backtrace_close (descriptor
, error_callback
, data
);
1479 /* Add the backtrace data for dynamically loaded libraries. */
1482 xcoff_add_shared_libs (struct backtrace_state
*state
,
1483 backtrace_error_callback error_callback
,
1484 void *data
, fileline
*fileline_fn
, int *found_sym
)
1486 const struct ld_info
*ldinfo
;
1488 unsigned int buflen
;
1495 /* Retrieve the list of loaded libraries. */
1501 buf
= realloc (buf
, buflen
);
1507 ret
= loadquery (L_GETINFO
, buf
, buflen
);
1512 while (ret
== -1 && errno
== ENOMEM
);
1519 ldinfo
= (const struct ld_info
*) buf
;
1520 while ((const char *) ldinfo
< (const char *) buf
+ buflen
)
1522 struct libbacktrace_base_address base_address
;
1524 if (*ldinfo
->ldinfo_filename
!= '/')
1527 descriptor
= backtrace_open (ldinfo
->ldinfo_filename
, error_callback
,
1528 data
, &does_not_exist
);
1532 /* Check if it is an archive (member name not empty). */
1534 member
= ldinfo
->ldinfo_filename
+ strlen (ldinfo
->ldinfo_filename
) + 1;
1535 memset (&base_address
, 0, sizeof base_address
);
1536 base_address
.m
= (uintptr_t) ldinfo
->ldinfo_textorg
;
1539 xcoff_armem_add (state
, descriptor
, base_address
, member
,
1540 error_callback
, data
, fileline_fn
, &lib_found_sym
);
1544 xcoff_add (state
, descriptor
, 0, base_address
, error_callback
, data
,
1545 fileline_fn
, &lib_found_sym
, 0);
1551 if (ldinfo
->ldinfo_next
== 0)
1553 ldinfo
= (const struct ld_info
*) ((const char *) ldinfo
1554 + ldinfo
->ldinfo_next
);
1559 #endif /* HAVE_LOADQUERY */
1561 /* Initialize the backtrace data we need from an XCOFF executable.
1562 Returns 1 on success, 0 on failure. */
1565 backtrace_initialize (struct backtrace_state
*state
,
1566 const char *filename ATTRIBUTE_UNUSED
, int descriptor
,
1567 backtrace_error_callback error_callback
,
1568 void *data
, fileline
*fileline_fn
)
1570 struct libbacktrace_base_address zero_base_address
;
1573 fileline xcoff_fileline_fn
= xcoff_nodebug
;
1575 memset (&zero_base_address
, 0, sizeof zero_base_address
);
1576 ret
= xcoff_add (state
, descriptor
, 0, zero_base_address
,
1577 error_callback
, data
, &xcoff_fileline_fn
, &found_sym
, 1);
1581 #ifdef HAVE_LOADQUERY
1582 xcoff_add_shared_libs (state
, error_callback
, data
, &xcoff_fileline_fn
,
1586 if (!state
->threaded
)
1589 state
->syminfo_fn
= xcoff_syminfo
;
1590 else if (state
->syminfo_fn
== NULL
)
1591 state
->syminfo_fn
= xcoff_nosyms
;
1596 backtrace_atomic_store_pointer (&state
->syminfo_fn
, xcoff_syminfo
);
1598 (void) __sync_bool_compare_and_swap (&state
->syminfo_fn
, NULL
,
1602 if (!state
->threaded
)
1604 if (state
->fileline_fn
== NULL
|| state
->fileline_fn
== xcoff_nodebug
)
1605 *fileline_fn
= xcoff_fileline_fn
;
1609 fileline current_fn
;
1611 current_fn
= backtrace_atomic_load_pointer (&state
->fileline_fn
);
1612 if (current_fn
== NULL
|| current_fn
== xcoff_nodebug
)
1613 *fileline_fn
= xcoff_fileline_fn
;