1 /* xcoff.c -- Get debug data from an XCOFF file for backtraces.
2 Copyright (C) 2012-2020 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. */
141 #if BACKTRACE_XCOFF_SIZE == 32
145 char _name
[SYMNMLEN
];
151 #define n_name _u._name
152 #define n_zeroes _u._s._zeroes
153 #define n_offset_ _u._s._offset
160 } __attribute__ ((packed
)) b_xcoff_syment
;
162 #else /* BACKTRACE_XCOFF_SIZE != 32 */
171 } __attribute__ ((packed
)) b_xcoff_syment
;
173 #endif /* BACKTRACE_XCOFF_SIZE != 32 */
177 #define C_EXT 2 /* External symbol. */
178 #define C_FCN 101 /* Beginning or end of function. */
179 #define C_FILE 103 /* Source file name. */
180 #define C_HIDEXT 107 /* Unnamed external symbol. */
181 #define C_BINCL 108 /* Beginning of include file. */
182 #define C_EINCL 109 /* End of include file. */
183 #define C_WEAKEXT 111 /* Weak external symbol. */
185 #define ISFCN(x) ((x) & 0x0020)
187 /* XCOFF AUX entry. */
193 #if BACKTRACE_XCOFF_SIZE == 32
205 char x_fname
[FILNMLEN
];
209 char pad
[FILNMLEN
-8];
213 #if BACKTRACE_XCOFF_SIZE == 32
228 uint8_t pad
[AUXESZ
-1];
231 } __attribute__ ((packed
)) b_xcoff_auxent
;
233 /* XCOFF line number entry. */
235 #if BACKTRACE_XCOFF_SIZE == 32
247 #else /* BACKTRACE_XCOFF_SIZE != 32 */
259 #endif /* BACKTRACE_XCOFF_SIZE != 32 */
261 #if BACKTRACE_XCOFF_SIZE == 32
262 #define XCOFF_AIX_TEXTBASE 0x10000000u
264 #define XCOFF_AIX_TEXTBASE 0x100000000ul
267 /* AIX big archive fixed-length header. */
269 #define AIAMAGBIG "<bigaf>\n"
272 char fl_magic
[8]; /* Archive magic string. */
273 char fl_memoff
[20]; /* Offset to member table. */
274 char fl_gstoff
[20]; /* Offset to global symbol table. */
275 char fl_gst64off
[20]; /* Offset to global symbol table for 64-bit objects. */
276 char fl_fstmoff
[20]; /* Offset to first archive member. */
277 char fl_freeoff
[20]; /* Offset to first member on free list. */
280 /* AIX big archive file member header. */
283 char ar_size
[20]; /* File member size - decimal. */
284 char ar_nxtmem
[20]; /* Next member offset - decimal. */
285 char ar_prvmem
[20]; /* Previous member offset - decimal. */
286 char ar_date
[12]; /* File member date - decimal. */
287 char ar_uid
[12]; /* File member userid - decimal. */
288 char ar_gid
[12]; /* File member group id - decimal. */
289 char ar_mode
[12]; /* File member mode - octal. */
290 char ar_namlen
[4]; /* File member name length - decimal. */
291 char ar_name
[2]; /* Start of member name. */
295 /* Information we keep for an XCOFF symbol. */
299 /* The name of the symbol. */
301 /* The address of the symbol. */
303 /* The size of the symbol. */
307 /* Information to pass to xcoff_syminfo. */
309 struct xcoff_syminfo_data
311 /* Symbols for the next module. */
312 struct xcoff_syminfo_data
*next
;
313 /* The XCOFF symbols, sorted by address. */
314 struct xcoff_symbol
*symbols
;
315 /* The number of symbols. */
319 /* Information about an include file. */
324 const char *filename
;
325 /* Offset to first line number from the include file. */
327 /* Offset to last line number from the include file. */
331 /* A growable vector of include files information. */
333 struct xcoff_incl_vector
335 /* Memory. This is an array of struct xcoff_incl. */
336 struct backtrace_vector vec
;
337 /* Number of include files. */
341 /* A growable vector of functions information. */
347 /* The size of the function. */
352 const char *filename
;
353 /* Pointer to first lnno entry. */
355 /* Base address of containing section. */
357 /* Starting source line number. */
361 /* A growable vector of function information. This is used while
362 reading the function symbols. */
364 struct xcoff_func_vector
366 /* Memory. This is an array of struct xcoff_func. */
367 struct backtrace_vector vec
;
368 /* Number of valid mappings. */
372 /* The information we need to map a PC to a file and line. */
374 struct xcoff_fileline_data
376 /* The data for the next file we know about. */
377 struct xcoff_fileline_data
*next
;
378 /* Functions information. */
379 struct xcoff_func_vector func_vec
;
380 /* Include files information. */
381 struct xcoff_incl_vector incl_vec
;
382 /* Line numbers information. */
383 const unsigned char *linenos
;
386 /* Loader address. */
387 uintptr_t base_address
;
390 /* Information we gather for the DWARF sections we care about. */
394 /* Section file offset. */
398 /* Section contents, after read from file. */
399 const unsigned char *data
;
402 /* A dummy callback function used when we can't find any debug info. */
405 xcoff_nodebug (struct backtrace_state
*state ATTRIBUTE_UNUSED
,
406 uintptr_t pc ATTRIBUTE_UNUSED
,
407 backtrace_full_callback callback ATTRIBUTE_UNUSED
,
408 backtrace_error_callback error_callback
, void *data
)
410 error_callback (data
, "no debug info in XCOFF executable", -1);
414 /* A dummy callback function used when we can't find a symbol
418 xcoff_nosyms (struct backtrace_state
*state ATTRIBUTE_UNUSED
,
419 uintptr_t addr ATTRIBUTE_UNUSED
,
420 backtrace_syminfo_callback callback ATTRIBUTE_UNUSED
,
421 backtrace_error_callback error_callback
, void *data
)
423 error_callback (data
, "no symbol table in XCOFF executable", -1);
426 /* Compare struct xcoff_symbol for qsort. */
429 xcoff_symbol_compare (const void *v1
, const void *v2
)
431 const struct xcoff_symbol
*e1
= (const struct xcoff_symbol
*) v1
;
432 const struct xcoff_symbol
*e2
= (const struct xcoff_symbol
*) v2
;
434 if (e1
->address
< e2
->address
)
436 else if (e1
->address
> e2
->address
)
442 /* Compare an ADDR against an xcoff_symbol for bsearch. */
445 xcoff_symbol_search (const void *vkey
, const void *ventry
)
447 const uintptr_t *key
= (const uintptr_t *) vkey
;
448 const struct xcoff_symbol
*entry
= (const struct xcoff_symbol
*) ventry
;
452 if (addr
< entry
->address
)
454 else if ((entry
->size
== 0 && addr
> entry
->address
)
455 || (entry
->size
> 0 && addr
>= entry
->address
+ entry
->size
))
461 /* Add XDATA to the list in STATE. */
464 xcoff_add_syminfo_data (struct backtrace_state
*state
,
465 struct xcoff_syminfo_data
*xdata
)
467 if (!state
->threaded
)
469 struct xcoff_syminfo_data
**pp
;
471 for (pp
= (struct xcoff_syminfo_data
**) (void *) &state
->syminfo_data
;
481 struct xcoff_syminfo_data
**pp
;
483 pp
= (struct xcoff_syminfo_data
**) (void *) &state
->syminfo_data
;
487 struct xcoff_syminfo_data
*p
;
489 p
= backtrace_atomic_load_pointer (pp
);
497 if (__sync_bool_compare_and_swap (pp
, NULL
, xdata
))
503 /* Return the symbol name and value for an ADDR. */
506 xcoff_syminfo (struct backtrace_state
*state ATTRIBUTE_UNUSED
, uintptr_t addr
,
507 backtrace_syminfo_callback callback
,
508 backtrace_error_callback error_callback ATTRIBUTE_UNUSED
,
511 struct xcoff_syminfo_data
*edata
;
512 struct xcoff_symbol
*sym
= NULL
;
515 if (!state
->threaded
)
517 for (edata
= (struct xcoff_syminfo_data
*) state
->syminfo_data
;
521 sym
= ((struct xcoff_symbol
*)
522 bsearch (&addr
, edata
->symbols
, edata
->count
,
523 sizeof (struct xcoff_symbol
), xcoff_symbol_search
));
530 struct xcoff_syminfo_data
**pp
;
532 pp
= (struct xcoff_syminfo_data
**) (void *) &state
->syminfo_data
;
535 edata
= backtrace_atomic_load_pointer (pp
);
539 sym
= ((struct xcoff_symbol
*)
540 bsearch (&addr
, edata
->symbols
, edata
->count
,
541 sizeof (struct xcoff_symbol
), xcoff_symbol_search
));
550 callback (data
, addr
, NULL
, 0, 0);
554 /* AIX prepends a '.' to function entry points, remove it. */
555 if (name
&& *name
== '.')
557 callback (data
, addr
, name
, sym
->address
, sym
->size
);
561 /* Return the name of an XCOFF symbol. */
564 xcoff_symname (const b_xcoff_syment
*asym
,
565 const unsigned char *strtab
, size_t strtab_size
)
567 #if BACKTRACE_XCOFF_SIZE == 32
568 if (asym
->n_zeroes
!= 0)
570 /* Make a copy as we will release the symtab view. */
571 char name
[SYMNMLEN
+1];
572 strncpy (name
, asym
->n_name
, SYMNMLEN
);
573 name
[SYMNMLEN
] = '\0';
574 return strdup (name
);
577 if (asym
->n_sclass
& 0x80)
578 return NULL
; /* .debug */
579 if (asym
->n_offset_
>= strtab_size
)
581 return (const char *) strtab
+ asym
->n_offset_
;
584 /* Initialize the symbol table info for xcoff_syminfo. */
587 xcoff_initialize_syminfo (struct backtrace_state
*state
,
588 uintptr_t base_address
,
589 const b_xcoff_scnhdr
*sects
,
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
= base_address
+ asym
->n_value
632 - sects
[asym
->n_scnum
- 1].s_paddr
;
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
<= fdata
->base_address
+ lineno
->l_addr
.l_paddr
- fn
->sect_base
)
773 lnno
= lineno
->l_lnno
;
779 /* If part of a function other than the beginning comes from an
780 include file, the line numbers are absolute, rather than
781 relative to the beginning of the function. */
782 incl
= ((struct xcoff_incl
*)
783 bsearch (&match
, fdata
->incl_vec
.vec
.base
,
784 fdata
->incl_vec
.count
, sizeof (struct xcoff_incl
),
788 bincl
= ((struct xcoff_incl
*)
789 bsearch (&fn
->lnnoptr
, fdata
->incl_vec
.vec
.base
,
790 fdata
->incl_vec
.count
, sizeof (struct xcoff_incl
),
792 if (bincl
!= NULL
&& strcmp (incl
->filename
, bincl
->filename
) == 0)
794 lnno
+= fn
->lnno
- 1;
796 filename
= incl
->filename
;
800 lnno
+= fn
->lnno
- 1;
804 /* AIX prepends a '.' to function entry points, remove it. */
805 if (function
!= NULL
&& *function
== '.')
807 return callback (data
, pc
, filename
, lnno
, function
);
810 /* Return the file/line information for a PC using the XCOFF lineno
811 mapping we built earlier. */
814 xcoff_fileline (struct backtrace_state
*state
, uintptr_t pc
,
815 backtrace_full_callback callback
,
816 backtrace_error_callback error_callback
, void *data
)
819 struct xcoff_fileline_data
*fdata
;
823 if (!state
->threaded
)
825 for (fdata
= (struct xcoff_fileline_data
*) state
->fileline_data
;
829 ret
= xcoff_lookup_pc (state
, fdata
, pc
, callback
, error_callback
,
831 if (ret
!= 0 || found
)
837 struct xcoff_fileline_data
**pp
;
839 pp
= (struct xcoff_fileline_data
**) (void *) &state
->fileline_data
;
842 fdata
= backtrace_atomic_load_pointer (pp
);
846 ret
= xcoff_lookup_pc (state
, fdata
, pc
, callback
, error_callback
,
848 if (ret
!= 0 || found
)
855 /* FIXME: See if any libraries have been dlopen'ed. */
857 return callback (data
, pc
, NULL
, 0, NULL
);
860 /* Initialize the function vector info for xcoff_fileline. */
863 xcoff_initialize_fileline (struct backtrace_state
*state
,
864 uintptr_t base_address
,
865 const b_xcoff_scnhdr
*sects
,
866 const b_xcoff_syment
*syms
, size_t nsyms
,
867 const unsigned char *strtab
, size_t strtab_size
,
868 const unsigned char *linenos
, size_t linenos_size
,
870 backtrace_error_callback error_callback
, void *data
)
872 struct xcoff_fileline_data
*fdata
;
873 struct xcoff_func
*fn
;
874 const b_xcoff_syment
*fsym
;
875 const b_xcoff_auxent
*aux
;
876 const char *filename
;
878 struct xcoff_incl
*incl
;
879 uintptr_t begin
, end
;
880 uintptr_t lnno
, lnnoptr
;
884 fdata
= ((struct xcoff_fileline_data
*)
885 backtrace_alloc (state
, sizeof (struct xcoff_fileline_data
),
886 error_callback
, data
));
889 memset (fdata
, 0, sizeof *fdata
);
890 fdata
->base_address
= base_address
;
891 fdata
->linenos
= linenos
;
892 fdata
->linenos_size
= linenos_size
;
893 fdata
->lnnoptr0
= lnnoptr0
;
900 for (i
= 0; i
< nsyms
; ++i
)
902 const b_xcoff_syment
*asym
= &syms
[i
];
904 switch (asym
->n_sclass
)
907 begin
= asym
->n_value
;
914 incl
= ((struct xcoff_incl
*)
915 backtrace_vector_grow (state
, sizeof (struct xcoff_incl
),
916 error_callback
, data
,
917 &fdata
->incl_vec
.vec
));
920 incl
->filename
= xcoff_symname (asym
, strtab
, strtab_size
);
923 ++fdata
->incl_vec
.count
;
929 filename
= xcoff_symname (asym
, strtab
, strtab_size
);
930 if (filename
== NULL
)
933 /* If the file auxiliary entry is not used, the symbol name is
934 the name of the source file. If the file auxiliary entry is
935 used, then the symbol name should be .file, and the first
936 file auxiliary entry (by convention) contains the source
939 if (asym
->n_numaux
> 0 && strcmp (filename
, ".file") == 0)
941 aux
= (const b_xcoff_auxent
*) (asym
+ 1);
942 if (aux
->x_file
._x
.x_zeroes
!= 0)
944 /* Make a copy as we will release the symtab view. */
945 char name
[FILNMLEN
+1];
946 strncpy (name
, aux
->x_file
.x_fname
, FILNMLEN
);
947 name
[FILNMLEN
] = '\0';
948 filename
= strdup (name
);
950 else if (aux
->x_file
._x
.x_offset
< strtab_size
)
951 filename
= (const char *) strtab
+ aux
->x_file
._x
.x_offset
;
963 if (!ISFCN (asym
->n_type
) || asym
->n_numaux
== 0
964 || asym
->n_scnum
<= 0)
966 if (filename
== NULL
)
968 aux
= (const b_xcoff_auxent
*) (asym
+ 1);
969 lnnoptr
= aux
->x_fcn
.x_lnnoptr
;
970 if (lnnoptr
< lnnoptr0
971 || lnnoptr
+ LINESZ
> lnnoptr0
+ linenos_size
)
973 /* x_fsize will be 0 if there is no debug information. */
974 fsize
= aux
->x_fcn
.x_fsize
;
979 if (asym
->n_numaux
== 0)
983 name
= xcoff_symname (asym
, strtab
, strtab_size
);
984 if (name
== NULL
|| strcmp (name
, ".bf") != 0)
989 aux
= (const b_xcoff_auxent
*) (asym
+ 1);
990 #if BACKTRACE_XCOFF_SIZE == 32
991 lnno
= (uint32_t) aux
->x_block
.x_lnnohi
<< 16
992 | aux
->x_block
.x_lnno
;
994 lnno
= aux
->x_block
.x_lnno
;
996 fn
= ((struct xcoff_func
*)
997 backtrace_vector_grow (state
, sizeof (struct xcoff_func
),
998 error_callback
, data
,
999 &fdata
->func_vec
.vec
));
1002 fn
->name
= xcoff_symname (fsym
, strtab
, strtab_size
);
1003 fn
->filename
= filename
;
1004 fn
->sect_base
= sects
[fsym
->n_scnum
- 1].s_paddr
;
1005 fn
->pc
= base_address
+ fsym
->n_value
- fn
->sect_base
;
1008 fn
->lnnoptr
= lnnoptr
;
1009 ++fdata
->func_vec
.count
;
1013 i
+= asym
->n_numaux
;
1016 if (!backtrace_vector_release (state
, &fdata
->func_vec
.vec
, error_callback
,
1019 backtrace_qsort (fdata
->func_vec
.vec
.base
, fdata
->func_vec
.count
,
1020 sizeof (struct xcoff_func
), xcoff_func_compare
);
1022 if (!backtrace_vector_release (state
, &fdata
->incl_vec
.vec
, error_callback
,
1025 backtrace_qsort (fdata
->incl_vec
.vec
.base
, fdata
->incl_vec
.count
,
1026 sizeof (struct xcoff_incl
), xcoff_incl_compare
);
1028 if (!state
->threaded
)
1030 struct xcoff_fileline_data
**pp
;
1032 for (pp
= (struct xcoff_fileline_data
**) (void *) &state
->fileline_data
;
1042 struct xcoff_fileline_data
**pp
;
1044 pp
= (struct xcoff_fileline_data
**) (void *) &state
->fileline_data
;
1048 struct xcoff_fileline_data
*p
;
1050 p
= backtrace_atomic_load_pointer (pp
);
1058 if (__sync_bool_compare_and_swap (pp
, NULL
, fdata
))
1069 /* Add the backtrace data for one XCOFF file. Returns 1 on success,
1070 0 on failure (in both cases descriptor is closed). */
1073 xcoff_add (struct backtrace_state
*state
, int descriptor
, off_t offset
,
1074 uintptr_t base_address
, backtrace_error_callback error_callback
,
1075 void *data
, fileline
*fileline_fn
, int *found_sym
, int exe
)
1077 struct backtrace_view fhdr_view
;
1078 struct backtrace_view sects_view
;
1079 struct backtrace_view linenos_view
;
1080 struct backtrace_view syms_view
;
1081 struct backtrace_view str_view
;
1082 struct backtrace_view dwarf_view
;
1083 b_xcoff_filhdr fhdr
;
1084 const b_xcoff_scnhdr
*sects
;
1085 const b_xcoff_scnhdr
*stext
;
1091 struct dwsect_info dwsect
[DEBUG_MAX
];
1095 int sects_view_valid
;
1096 int linenos_view_valid
;
1097 int syms_view_valid
;
1099 int dwarf_view_valid
;
1102 struct dwarf_sections dwarf_sections
;
1106 sects_view_valid
= 0;
1107 linenos_view_valid
= 0;
1108 syms_view_valid
= 0;
1110 dwarf_view_valid
= 0;
1114 /* Map the XCOFF file header. */
1115 if (!backtrace_get_view (state
, descriptor
, offset
, sizeof (b_xcoff_filhdr
),
1116 error_callback
, data
, &fhdr_view
))
1119 memcpy (&fhdr
, fhdr_view
.data
, sizeof fhdr
);
1120 magic_ok
= (fhdr
.f_magic
== XCOFF_MAGIC
);
1122 backtrace_release_view (state
, &fhdr_view
, error_callback
, data
);
1127 error_callback (data
, "executable file is not XCOFF", 0);
1131 /* Verify object is of expected type. */
1132 if ((exe
&& (fhdr
.f_flags
& F_SHROBJ
))
1133 || (!exe
&& !(fhdr
.f_flags
& F_SHROBJ
)))
1136 /* Read the section headers. */
1138 sects_size
= fhdr
.f_nscns
* sizeof (b_xcoff_scnhdr
);
1140 if (!backtrace_get_view (state
, descriptor
,
1141 offset
+ sizeof (fhdr
) + fhdr
.f_opthdr
,
1142 sects_size
, error_callback
, data
, §s_view
))
1144 sects_view_valid
= 1;
1145 sects
= (const b_xcoff_scnhdr
*) sects_view
.data
;
1147 /* FIXME: assumes only one .text section. */
1148 for (i
= 0; i
< fhdr
.f_nscns
; ++i
)
1149 if ((sects
[i
].s_flags
& 0xffff) == STYP_TEXT
)
1151 if (i
== fhdr
.f_nscns
)
1156 /* AIX ldinfo_textorg includes the XCOFF headers. */
1157 base_address
= (exe
? XCOFF_AIX_TEXTBASE
: base_address
) + stext
->s_scnptr
;
1159 lnnoptr
= stext
->s_lnnoptr
;
1160 nlnno
= stext
->s_nlnno
;
1162 #if BACKTRACE_XCOFF_SIZE == 32
1163 if (nlnno
== _OVERFLOW_MARKER
)
1166 /* Find the matching .ovrflo section. */
1167 for (i
= 0; i
< fhdr
.f_nscns
; ++i
)
1169 if (((sects
[i
].s_flags
& 0xffff) == STYP_OVRFLO
)
1170 && sects
[i
].s_nlnno
== sntext
)
1172 nlnno
= sects
[i
].s_vaddr
;
1179 /* Read the symbol table and the string table. */
1181 if (fhdr
.f_symptr
!= 0)
1183 struct xcoff_syminfo_data
*sdata
;
1185 /* Symbol table is followed by the string table. The string table
1186 starts with its length (on 4 bytes).
1187 Map the symbol table and the length of the string table. */
1188 syms_size
= fhdr
.f_nsyms
* sizeof (b_xcoff_syment
);
1190 if (!backtrace_get_view (state
, descriptor
, offset
+ fhdr
.f_symptr
,
1191 syms_size
+ 4, error_callback
, data
,
1194 syms_view_valid
= 1;
1196 memcpy (&str_size
, syms_view
.data
+ syms_size
, 4);
1198 str_off
= fhdr
.f_symptr
+ syms_size
;
1202 /* Map string table (including the length word). */
1204 if (!backtrace_get_view (state
, descriptor
, offset
+ str_off
,
1205 str_size
, error_callback
, data
, &str_view
))
1210 sdata
= ((struct xcoff_syminfo_data
*)
1211 backtrace_alloc (state
, sizeof *sdata
, error_callback
, data
));
1215 if (!xcoff_initialize_syminfo (state
, base_address
, sects
,
1216 syms_view
.data
, fhdr
.f_nsyms
,
1217 str_view
.data
, str_size
,
1218 error_callback
, data
, sdata
))
1220 backtrace_free (state
, sdata
, sizeof *sdata
, error_callback
, data
);
1226 xcoff_add_syminfo_data (state
, sdata
);
1229 /* Read all the DWARF sections in a single view, since they are
1230 probably adjacent in the file. We never release this view. */
1234 memset (dwsect
, 0, sizeof dwsect
);
1235 for (i
= 0; i
< fhdr
.f_nscns
; ++i
)
1240 if ((sects
[i
].s_flags
& 0xffff) != STYP_DWARF
1241 || sects
[i
].s_size
== 0)
1243 /* Map DWARF section to array index. */
1244 switch (sects
[i
].s_flags
& 0xffff0000)
1246 case SSUBTYP_DWINFO
:
1249 case SSUBTYP_DWLINE
:
1252 case SSUBTYP_DWABREV
:
1255 case SSUBTYP_DWARNGE
:
1264 if (min_offset
== 0 || (off_t
) sects
[i
].s_scnptr
< min_offset
)
1265 min_offset
= sects
[i
].s_scnptr
;
1266 end
= sects
[i
].s_scnptr
+ sects
[i
].s_size
;
1267 if (end
> max_offset
)
1269 dwsect
[idx
].offset
= sects
[i
].s_scnptr
;
1270 dwsect
[idx
].size
= sects
[i
].s_size
;
1272 if (min_offset
!= 0 && max_offset
!= 0)
1274 if (!backtrace_get_view (state
, descriptor
, offset
+ min_offset
,
1275 max_offset
- min_offset
,
1276 error_callback
, data
, &dwarf_view
))
1278 dwarf_view_valid
= 1;
1280 for (i
= 0; i
< (int) DEBUG_MAX
; ++i
)
1282 if (dwsect
[i
].offset
== 0)
1283 dwsect
[i
].data
= NULL
;
1285 dwsect
[i
].data
= ((const unsigned char *) dwarf_view
.data
1286 + (dwsect
[i
].offset
- min_offset
));
1289 memset (&dwarf_sections
, 0, sizeof dwarf_sections
);
1291 dwarf_sections
.data
[DEBUG_INFO
] = dwsect
[DEBUG_INFO
].data
;
1292 dwarf_sections
.size
[DEBUG_INFO
] = dwsect
[DEBUG_INFO
].size
;
1293 #if BACKTRACE_XCOFF_SIZE == 32
1294 /* XXX workaround for broken lineoff */
1295 dwarf_sections
.data
[DEBUG_LINE
] = dwsect
[DEBUG_LINE
].data
- 4;
1297 /* XXX workaround for broken lineoff */
1298 dwarf_sections
.data
[DEBUG_LINE
] = dwsect
[DEBUG_LINE
].data
- 12;
1300 dwarf_sections
.size
[DEBUG_LINE
] = dwsect
[DEBUG_LINE
].size
;
1301 dwarf_sections
.data
[DEBUG_ABBREV
] = dwsect
[DEBUG_ABBREV
].data
;
1302 dwarf_sections
.size
[DEBUG_ABBREV
] = dwsect
[DEBUG_ABBREV
].size
;
1303 dwarf_sections
.data
[DEBUG_RANGES
] = dwsect
[DEBUG_RANGES
].data
;
1304 dwarf_sections
.size
[DEBUG_RANGES
] = dwsect
[DEBUG_RANGES
].size
;
1305 dwarf_sections
.data
[DEBUG_STR
] = dwsect
[DEBUG_STR
].data
;
1306 dwarf_sections
.size
[DEBUG_STR
] = dwsect
[DEBUG_STR
].size
;
1308 if (!backtrace_dwarf_add (state
, 0, &dwarf_sections
,
1311 error_callback
, data
, fileline_fn
,
1312 NULL
/* returned fileline_entry */))
1316 /* Read the XCOFF line number entries if DWARF sections not found. */
1318 if (!dwarf_view_valid
&& fhdr
.f_symptr
!= 0 && lnnoptr
!= 0)
1320 size_t linenos_size
= (size_t) nlnno
* LINESZ
;
1322 /* We never release this view. */
1323 if (!backtrace_get_view (state
, descriptor
, offset
+ lnnoptr
,
1325 error_callback
, data
, &linenos_view
))
1327 linenos_view_valid
= 1;
1329 if (xcoff_initialize_fileline (state
, base_address
, sects
,
1330 syms_view
.data
, fhdr
.f_nsyms
,
1331 str_view
.data
, str_size
,
1332 linenos_view
.data
, linenos_size
,
1333 lnnoptr
, error_callback
, data
))
1334 *fileline_fn
= xcoff_fileline
;
1337 backtrace_release_view (state
, §s_view
, error_callback
, data
);
1338 sects_view_valid
= 0;
1339 if (syms_view_valid
)
1340 backtrace_release_view (state
, &syms_view
, error_callback
, data
);
1341 syms_view_valid
= 0;
1343 /* We've read all we need from the executable. */
1344 if (!backtrace_close (descriptor
, error_callback
, data
))
1351 if (sects_view_valid
)
1352 backtrace_release_view (state
, §s_view
, error_callback
, data
);
1354 backtrace_release_view (state
, &str_view
, error_callback
, data
);
1355 if (syms_view_valid
)
1356 backtrace_release_view (state
, &syms_view
, error_callback
, data
);
1357 if (linenos_view_valid
)
1358 backtrace_release_view (state
, &linenos_view
, error_callback
, data
);
1359 if (dwarf_view_valid
)
1360 backtrace_release_view (state
, &dwarf_view
, error_callback
, data
);
1361 if (descriptor
!= -1 && offset
== 0)
1362 backtrace_close (descriptor
, error_callback
, data
);
1366 #ifdef HAVE_LOADQUERY
1368 /* Read an integer value in human-readable format from an AIX
1369 big archive fixed-length or member header. */
1372 xcoff_parse_decimal (const char *buf
, size_t size
, off_t
*off
)
1377 if (size
>= sizeof str
)
1379 memcpy (str
, buf
, size
);
1381 *off
= strtol (str
, &end
, 10);
1382 if (*end
!= '\0' && *end
!= ' ')
1388 /* Add the backtrace data for a member of an AIX big archive.
1389 Returns 1 on success, 0 on failure. */
1392 xcoff_armem_add (struct backtrace_state
*state
, int descriptor
,
1393 uintptr_t base_address
, const char *member
,
1394 backtrace_error_callback error_callback
, void *data
,
1395 fileline
*fileline_fn
, int *found_sym
)
1397 struct backtrace_view view
;
1399 const b_ar_hdr
*ar_hdr
;
1406 /* Map archive fixed-length header. */
1408 if (!backtrace_get_view (state
, descriptor
, 0, sizeof (b_ar_fl_hdr
),
1409 error_callback
, data
, &view
))
1412 memcpy (&fl_hdr
, view
.data
, sizeof (b_ar_fl_hdr
));
1414 backtrace_release_view (state
, &view
, error_callback
, data
);
1416 if (memcmp (fl_hdr
.fl_magic
, AIAMAGBIG
, 8) != 0)
1419 memlen
= strlen (member
);
1421 /* Read offset of first archive member. */
1422 if (!xcoff_parse_decimal (fl_hdr
.fl_fstmoff
, sizeof fl_hdr
.fl_fstmoff
, &off
))
1426 /* Map archive member header and member name. */
1428 if (!backtrace_get_view (state
, descriptor
, off
,
1429 sizeof (b_ar_hdr
) + memlen
,
1430 error_callback
, data
, &view
))
1433 ar_hdr
= (const b_ar_hdr
*) view
.data
;
1435 /* Read archive member name length. */
1436 if (!xcoff_parse_decimal (ar_hdr
->ar_namlen
, sizeof ar_hdr
->ar_namlen
,
1439 backtrace_release_view (state
, &view
, error_callback
, data
);
1442 if (len
== memlen
&& !memcmp (ar_hdr
->ar_name
, member
, memlen
))
1444 off
= (off
+ sizeof (b_ar_hdr
) + memlen
+ 1) & ~1;
1446 /* The archive can contain several members with the same name
1447 (e.g. 32-bit and 64-bit), so continue if not ok. */
1449 if (xcoff_add (state
, descriptor
, off
, base_address
, error_callback
,
1450 data
, fileline_fn
, found_sym
, 0))
1452 backtrace_release_view (state
, &view
, error_callback
, data
);
1457 /* Read offset of next archive member. */
1458 if (!xcoff_parse_decimal (ar_hdr
->ar_nxtmem
, sizeof ar_hdr
->ar_nxtmem
,
1461 backtrace_release_view (state
, &view
, error_callback
, data
);
1464 backtrace_release_view (state
, &view
, error_callback
, data
);
1468 /* No matching member found. */
1469 backtrace_close (descriptor
, error_callback
, data
);
1473 /* Add the backtrace data for dynamically loaded libraries. */
1476 xcoff_add_shared_libs (struct backtrace_state
*state
,
1477 backtrace_error_callback error_callback
,
1478 void *data
, fileline
*fileline_fn
, int *found_sym
)
1480 const struct ld_info
*ldinfo
;
1482 unsigned int buflen
;
1489 /* Retrieve the list of loaded libraries. */
1495 buf
= realloc (buf
, buflen
);
1501 ret
= loadquery (L_GETINFO
, buf
, buflen
);
1506 while (ret
== -1 && errno
== ENOMEM
);
1513 ldinfo
= (const struct ld_info
*) buf
;
1514 while ((const char *) ldinfo
< (const char *) buf
+ buflen
)
1516 if (*ldinfo
->ldinfo_filename
!= '/')
1519 descriptor
= backtrace_open (ldinfo
->ldinfo_filename
, error_callback
,
1520 data
, &does_not_exist
);
1524 /* Check if it is an archive (member name not empty). */
1526 member
= ldinfo
->ldinfo_filename
+ strlen (ldinfo
->ldinfo_filename
) + 1;
1529 xcoff_armem_add (state
, descriptor
,
1530 (uintptr_t) ldinfo
->ldinfo_textorg
, member
,
1531 error_callback
, data
, fileline_fn
, &lib_found_sym
);
1535 xcoff_add (state
, descriptor
, 0, (uintptr_t) ldinfo
->ldinfo_textorg
,
1536 error_callback
, data
, fileline_fn
, &lib_found_sym
, 0);
1542 if (ldinfo
->ldinfo_next
== 0)
1544 ldinfo
= (const struct ld_info
*) ((const char *) ldinfo
1545 + ldinfo
->ldinfo_next
);
1550 #endif /* HAVE_LOADQUERY */
1552 /* Initialize the backtrace data we need from an XCOFF executable.
1553 Returns 1 on success, 0 on failure. */
1556 backtrace_initialize (struct backtrace_state
*state
,
1557 const char *filename ATTRIBUTE_UNUSED
, int descriptor
,
1558 backtrace_error_callback error_callback
,
1559 void *data
, fileline
*fileline_fn
)
1563 fileline xcoff_fileline_fn
= xcoff_nodebug
;
1565 ret
= xcoff_add (state
, descriptor
, 0, 0, error_callback
, data
,
1566 &xcoff_fileline_fn
, &found_sym
, 1);
1570 #ifdef HAVE_LOADQUERY
1571 xcoff_add_shared_libs (state
, error_callback
, data
, &xcoff_fileline_fn
,
1575 if (!state
->threaded
)
1578 state
->syminfo_fn
= xcoff_syminfo
;
1579 else if (state
->syminfo_fn
== NULL
)
1580 state
->syminfo_fn
= xcoff_nosyms
;
1585 backtrace_atomic_store_pointer (&state
->syminfo_fn
, xcoff_syminfo
);
1587 (void) __sync_bool_compare_and_swap (&state
->syminfo_fn
, NULL
,
1591 if (!state
->threaded
)
1593 if (state
->fileline_fn
== NULL
|| state
->fileline_fn
== xcoff_nodebug
)
1594 *fileline_fn
= xcoff_fileline_fn
;
1598 fileline current_fn
;
1600 current_fn
= backtrace_atomic_load_pointer (&state
->fileline_fn
);
1601 if (current_fn
== NULL
|| current_fn
== xcoff_nodebug
)
1602 *fileline_fn
= xcoff_fileline_fn
;