12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607 |
- /* xcoff.c -- Get debug data from an XCOFF file for backtraces.
- Copyright (C) 2012-2021 Free Software Foundation, Inc.
- Adapted from elf.c.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
- (1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- (2) Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- (3) The name of the author may not be used to
- endorse or promote products derived from this software without
- specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE. */
- #include "config.h"
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #ifdef HAVE_LOADQUERY
- #include <sys/ldr.h>
- #endif
- #include "backtrace.h"
- #include "internal.h"
- /* The configure script must tell us whether we are 32-bit or 64-bit
- XCOFF. We could make this code test and support either possibility,
- but there is no point. This code only works for the currently
- running executable, which means that we know the XCOFF mode at
- configure time. */
- #if BACKTRACE_XCOFF_SIZE != 32 && BACKTRACE_XCOFF_SIZE != 64
- #error "Unknown BACKTRACE_XCOFF_SIZE"
- #endif
- /* XCOFF file header. */
- #if BACKTRACE_XCOFF_SIZE == 32
- typedef struct {
- uint16_t f_magic;
- uint16_t f_nscns;
- uint32_t f_timdat;
- uint32_t f_symptr;
- uint32_t f_nsyms;
- uint16_t f_opthdr;
- uint16_t f_flags;
- } b_xcoff_filhdr;
- #define XCOFF_MAGIC 0737
- #else /* BACKTRACE_XCOFF_SIZE != 32 */
- typedef struct {
- uint16_t f_magic;
- uint16_t f_nscns;
- uint32_t f_timdat;
- uint64_t f_symptr;
- uint16_t f_opthdr;
- uint16_t f_flags;
- uint32_t f_nsyms;
- } b_xcoff_filhdr;
- #define XCOFF_MAGIC 0767
- #endif /* BACKTRACE_XCOFF_SIZE != 32 */
- #define F_SHROBJ 0x2000 /* File is a shared object. */
- /* XCOFF section header. */
- #if BACKTRACE_XCOFF_SIZE == 32
- typedef struct {
- char s_name[8];
- uint32_t s_paddr;
- uint32_t s_vaddr;
- uint32_t s_size;
- uint32_t s_scnptr;
- uint32_t s_relptr;
- uint32_t s_lnnoptr;
- uint16_t s_nreloc;
- uint16_t s_nlnno;
- uint32_t s_flags;
- } b_xcoff_scnhdr;
- #define _OVERFLOW_MARKER 65535
- #else /* BACKTRACE_XCOFF_SIZE != 32 */
- typedef struct {
- char name[8];
- uint64_t s_paddr;
- uint64_t s_vaddr;
- uint64_t s_size;
- uint64_t s_scnptr;
- uint64_t s_relptr;
- uint64_t s_lnnoptr;
- uint32_t s_nreloc;
- uint32_t s_nlnno;
- uint32_t s_flags;
- } b_xcoff_scnhdr;
- #endif /* BACKTRACE_XCOFF_SIZE != 32 */
- #define STYP_DWARF 0x10 /* DWARF debugging section. */
- #define STYP_TEXT 0x20 /* Executable text (code) section. */
- #define STYP_OVRFLO 0x8000 /* Line-number field overflow section. */
- #define SSUBTYP_DWINFO 0x10000 /* DWARF info section. */
- #define SSUBTYP_DWLINE 0x20000 /* DWARF line-number section. */
- #define SSUBTYP_DWARNGE 0x50000 /* DWARF aranges section. */
- #define SSUBTYP_DWABREV 0x60000 /* DWARF abbreviation section. */
- #define SSUBTYP_DWSTR 0x70000 /* DWARF strings section. */
- #define SSUBTYP_DWRNGES 0x80000 /* DWARF ranges section. */
- /* XCOFF symbol. */
- #define SYMNMLEN 8
- #if BACKTRACE_XCOFF_SIZE == 32
- typedef struct {
- union {
- char _name[SYMNMLEN];
- struct {
- uint32_t _zeroes;
- uint32_t _offset;
- } _s;
- } _u;
- #define n_name _u._name
- #define n_zeroes _u._s._zeroes
- #define n_offset_ _u._s._offset
- uint32_t n_value;
- int16_t n_scnum;
- uint16_t n_type;
- uint8_t n_sclass;
- uint8_t n_numaux;
- } __attribute__ ((packed)) b_xcoff_syment;
- #else /* BACKTRACE_XCOFF_SIZE != 32 */
- typedef struct {
- uint64_t n_value;
- uint32_t n_offset_;
- int16_t n_scnum;
- uint16_t n_type;
- uint8_t n_sclass;
- uint8_t n_numaux;
- } __attribute__ ((packed)) b_xcoff_syment;
- #endif /* BACKTRACE_XCOFF_SIZE != 32 */
- #define SYMESZ 18
- #define C_EXT 2 /* External symbol. */
- #define C_FCN 101 /* Beginning or end of function. */
- #define C_FILE 103 /* Source file name. */
- #define C_HIDEXT 107 /* Unnamed external symbol. */
- #define C_BINCL 108 /* Beginning of include file. */
- #define C_EINCL 109 /* End of include file. */
- #define C_WEAKEXT 111 /* Weak external symbol. */
- #define ISFCN(x) ((x) & 0x0020)
- /* XCOFF AUX entry. */
- #define AUXESZ 18
- #define FILNMLEN 14
- typedef union {
- #if BACKTRACE_XCOFF_SIZE == 32
- struct {
- uint16_t pad;
- uint16_t x_lnnohi;
- uint16_t x_lnno;
- } x_block;
- #else
- struct {
- uint32_t x_lnno;
- } x_block;
- #endif
- union {
- char x_fname[FILNMLEN];
- struct {
- uint32_t x_zeroes;
- uint32_t x_offset;
- char pad[FILNMLEN-8];
- uint8_t x_ftype;
- } _x;
- } x_file;
- #if BACKTRACE_XCOFF_SIZE == 32
- struct {
- uint32_t x_exptr;
- uint32_t x_fsize;
- uint32_t x_lnnoptr;
- uint32_t x_endndx;
- } x_fcn;
- #else
- struct {
- uint64_t x_lnnoptr;
- uint32_t x_fsize;
- uint32_t x_endndx;
- } x_fcn;
- #endif
- struct {
- uint8_t pad[AUXESZ-1];
- uint8_t x_auxtype;
- } x_auxtype;
- } __attribute__ ((packed)) b_xcoff_auxent;
- /* XCOFF line number entry. */
- #if BACKTRACE_XCOFF_SIZE == 32
- typedef struct {
- union {
- uint32_t l_symndx;
- uint32_t l_paddr;
- } l_addr;
- uint16_t l_lnno;
- } b_xcoff_lineno;
- #define LINESZ 6
- #else /* BACKTRACE_XCOFF_SIZE != 32 */
- typedef struct {
- union {
- uint32_t l_symndx;
- uint64_t l_paddr;
- } l_addr;
- uint32_t l_lnno;
- } b_xcoff_lineno;
- #define LINESZ 12
- #endif /* BACKTRACE_XCOFF_SIZE != 32 */
- #if BACKTRACE_XCOFF_SIZE == 32
- #define XCOFF_AIX_TEXTBASE 0x10000000u
- #else
- #define XCOFF_AIX_TEXTBASE 0x100000000ul
- #endif
- /* AIX big archive fixed-length header. */
- #define AIAMAGBIG "<bigaf>\n"
- typedef struct {
- char fl_magic[8]; /* Archive magic string. */
- char fl_memoff[20]; /* Offset to member table. */
- char fl_gstoff[20]; /* Offset to global symbol table. */
- char fl_gst64off[20]; /* Offset to global symbol table for 64-bit objects. */
- char fl_fstmoff[20]; /* Offset to first archive member. */
- char fl_freeoff[20]; /* Offset to first member on free list. */
- } b_ar_fl_hdr;
- /* AIX big archive file member header. */
- typedef struct {
- char ar_size[20]; /* File member size - decimal. */
- char ar_nxtmem[20]; /* Next member offset - decimal. */
- char ar_prvmem[20]; /* Previous member offset - decimal. */
- char ar_date[12]; /* File member date - decimal. */
- char ar_uid[12]; /* File member userid - decimal. */
- char ar_gid[12]; /* File member group id - decimal. */
- char ar_mode[12]; /* File member mode - octal. */
- char ar_namlen[4]; /* File member name length - decimal. */
- char ar_name[2]; /* Start of member name. */
- } b_ar_hdr;
- /* Information we keep for an XCOFF symbol. */
- struct xcoff_symbol
- {
- /* The name of the symbol. */
- const char *name;
- /* The address of the symbol. */
- uintptr_t address;
- /* The size of the symbol. */
- size_t size;
- };
- /* Information to pass to xcoff_syminfo. */
- struct xcoff_syminfo_data
- {
- /* Symbols for the next module. */
- struct xcoff_syminfo_data *next;
- /* The XCOFF symbols, sorted by address. */
- struct xcoff_symbol *symbols;
- /* The number of symbols. */
- size_t count;
- };
- /* Information about an include file. */
- struct xcoff_incl
- {
- /* File name. */
- const char *filename;
- /* Offset to first line number from the include file. */
- uintptr_t begin;
- /* Offset to last line number from the include file. */
- uintptr_t end;
- };
- /* A growable vector of include files information. */
- struct xcoff_incl_vector
- {
- /* Memory. This is an array of struct xcoff_incl. */
- struct backtrace_vector vec;
- /* Number of include files. */
- size_t count;
- };
- /* A growable vector of functions information. */
- struct xcoff_func
- {
- /* PC. */
- uintptr_t pc;
- /* The size of the function. */
- size_t size;
- /* Function name. */
- const char *name;
- /* File name. */
- const char *filename;
- /* Pointer to first lnno entry. */
- uintptr_t lnnoptr;
- /* Base address of containing section. */
- uintptr_t sect_base;
- /* Starting source line number. */
- int lnno;
- };
- /* A growable vector of function information. This is used while
- reading the function symbols. */
- struct xcoff_func_vector
- {
- /* Memory. This is an array of struct xcoff_func. */
- struct backtrace_vector vec;
- /* Number of valid mappings. */
- size_t count;
- };
- /* The information we need to map a PC to a file and line. */
- struct xcoff_fileline_data
- {
- /* The data for the next file we know about. */
- struct xcoff_fileline_data *next;
- /* Functions information. */
- struct xcoff_func_vector func_vec;
- /* Include files information. */
- struct xcoff_incl_vector incl_vec;
- /* Line numbers information. */
- const unsigned char *linenos;
- size_t linenos_size;
- uint64_t lnnoptr0;
- /* Loader address. */
- uintptr_t base_address;
- };
- /* Information we gather for the DWARF sections we care about. */
- struct dwsect_info
- {
- /* Section file offset. */
- off_t offset;
- /* Section size. */
- size_t size;
- /* Section contents, after read from file. */
- const unsigned char *data;
- };
- /* A dummy callback function used when we can't find any debug info. */
- static int
- xcoff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
- uintptr_t pc ATTRIBUTE_UNUSED,
- backtrace_full_callback callback ATTRIBUTE_UNUSED,
- backtrace_error_callback error_callback, void *data)
- {
- error_callback (data, "no debug info in XCOFF executable", -1);
- return 0;
- }
- /* A dummy callback function used when we can't find a symbol
- table. */
- static void
- xcoff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
- uintptr_t addr ATTRIBUTE_UNUSED,
- backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
- backtrace_error_callback error_callback, void *data)
- {
- error_callback (data, "no symbol table in XCOFF executable", -1);
- }
- /* Compare struct xcoff_symbol for qsort. */
- static int
- xcoff_symbol_compare (const void *v1, const void *v2)
- {
- const struct xcoff_symbol *e1 = (const struct xcoff_symbol *) v1;
- const struct xcoff_symbol *e2 = (const struct xcoff_symbol *) v2;
- if (e1->address < e2->address)
- return -1;
- else if (e1->address > e2->address)
- return 1;
- else
- return 0;
- }
- /* Compare an ADDR against an xcoff_symbol for bsearch. */
- static int
- xcoff_symbol_search (const void *vkey, const void *ventry)
- {
- const uintptr_t *key = (const uintptr_t *) vkey;
- const struct xcoff_symbol *entry = (const struct xcoff_symbol *) ventry;
- uintptr_t addr;
- addr = *key;
- if (addr < entry->address)
- return -1;
- else if ((entry->size == 0 && addr > entry->address)
- || (entry->size > 0 && addr >= entry->address + entry->size))
- return 1;
- else
- return 0;
- }
- /* Add XDATA to the list in STATE. */
- static void
- xcoff_add_syminfo_data (struct backtrace_state *state,
- struct xcoff_syminfo_data *xdata)
- {
- if (!state->threaded)
- {
- struct xcoff_syminfo_data **pp;
- for (pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
- *pp != NULL;
- pp = &(*pp)->next)
- ;
- *pp = xdata;
- }
- else
- {
- while (1)
- {
- struct xcoff_syminfo_data **pp;
- pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
- while (1)
- {
- struct xcoff_syminfo_data *p;
- p = backtrace_atomic_load_pointer (pp);
- if (p == NULL)
- break;
- pp = &p->next;
- }
- if (__sync_bool_compare_and_swap (pp, NULL, xdata))
- break;
- }
- }
- }
- /* Return the symbol name and value for an ADDR. */
- static void
- xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr,
- backtrace_syminfo_callback callback,
- backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
- void *data)
- {
- struct xcoff_syminfo_data *edata;
- struct xcoff_symbol *sym = NULL;
- const char *name;
- if (!state->threaded)
- {
- for (edata = (struct xcoff_syminfo_data *) state->syminfo_data;
- edata != NULL;
- edata = edata->next)
- {
- sym = ((struct xcoff_symbol *)
- bsearch (&addr, edata->symbols, edata->count,
- sizeof (struct xcoff_symbol), xcoff_symbol_search));
- if (sym != NULL)
- break;
- }
- }
- else
- {
- struct xcoff_syminfo_data **pp;
- pp = (struct xcoff_syminfo_data **) (void *) &state->syminfo_data;
- while (1)
- {
- edata = backtrace_atomic_load_pointer (pp);
- if (edata == NULL)
- break;
- sym = ((struct xcoff_symbol *)
- bsearch (&addr, edata->symbols, edata->count,
- sizeof (struct xcoff_symbol), xcoff_symbol_search));
- if (sym != NULL)
- break;
- pp = &edata->next;
- }
- }
- if (sym == NULL)
- callback (data, addr, NULL, 0, 0);
- else
- {
- name = sym->name;
- /* AIX prepends a '.' to function entry points, remove it. */
- if (name && *name == '.')
- ++name;
- callback (data, addr, name, sym->address, sym->size);
- }
- }
- /* Return the name of an XCOFF symbol. */
- static const char *
- xcoff_symname (const b_xcoff_syment *asym,
- const unsigned char *strtab, size_t strtab_size)
- {
- #if BACKTRACE_XCOFF_SIZE == 32
- if (asym->n_zeroes != 0)
- {
- /* Make a copy as we will release the symtab view. */
- char name[SYMNMLEN+1];
- strncpy (name, asym->n_name, SYMNMLEN);
- name[SYMNMLEN] = '\0';
- return strdup (name);
- }
- #endif
- if (asym->n_sclass & 0x80)
- return NULL; /* .debug */
- if (asym->n_offset_ >= strtab_size)
- return NULL;
- return (const char *) strtab + asym->n_offset_;
- }
- /* Initialize the symbol table info for xcoff_syminfo. */
- static int
- xcoff_initialize_syminfo (struct backtrace_state *state,
- uintptr_t base_address,
- const b_xcoff_syment *syms, size_t nsyms,
- const unsigned char *strtab, size_t strtab_size,
- backtrace_error_callback error_callback, void *data,
- struct xcoff_syminfo_data *sdata)
- {
- size_t xcoff_symbol_count;
- size_t xcoff_symbol_size;
- struct xcoff_symbol *xcoff_symbols;
- size_t i;
- unsigned int j;
- /* We only care about function symbols. Count them. */
- xcoff_symbol_count = 0;
- for (i = 0; i < nsyms; ++i)
- {
- const b_xcoff_syment *asym = &syms[i];
- if ((asym->n_sclass == C_EXT || asym->n_sclass == C_HIDEXT
- || asym->n_sclass == C_WEAKEXT)
- && ISFCN (asym->n_type) && asym->n_numaux > 0 && asym->n_scnum > 0)
- ++xcoff_symbol_count;
- i += asym->n_numaux;
- }
- xcoff_symbol_size = xcoff_symbol_count * sizeof (struct xcoff_symbol);
- xcoff_symbols = ((struct xcoff_symbol *)
- backtrace_alloc (state, xcoff_symbol_size, error_callback,
- data));
- if (xcoff_symbols == NULL)
- return 0;
- j = 0;
- for (i = 0; i < nsyms; ++i)
- {
- const b_xcoff_syment *asym = &syms[i];
- if ((asym->n_sclass == C_EXT || asym->n_sclass == C_HIDEXT
- || asym->n_sclass == C_WEAKEXT)
- && ISFCN (asym->n_type) && asym->n_numaux > 0 && asym->n_scnum > 0)
- {
- const b_xcoff_auxent *aux = (const b_xcoff_auxent *) (asym + 1);
- xcoff_symbols[j].name = xcoff_symname (asym, strtab, strtab_size);
- xcoff_symbols[j].address = base_address + asym->n_value;
- /* x_fsize will be 0 if there is no debug information. */
- xcoff_symbols[j].size = aux->x_fcn.x_fsize;
- ++j;
- }
- i += asym->n_numaux;
- }
- backtrace_qsort (xcoff_symbols, xcoff_symbol_count,
- sizeof (struct xcoff_symbol), xcoff_symbol_compare);
- sdata->next = NULL;
- sdata->symbols = xcoff_symbols;
- sdata->count = xcoff_symbol_count;
- return 1;
- }
- /* Compare struct xcoff_func for qsort. */
- static int
- xcoff_func_compare (const void *v1, const void *v2)
- {
- const struct xcoff_func *fn1 = (const struct xcoff_func *) v1;
- const struct xcoff_func *fn2 = (const struct xcoff_func *) v2;
- if (fn1->pc < fn2->pc)
- return -1;
- else if (fn1->pc > fn2->pc)
- return 1;
- else
- return 0;
- }
- /* Compare a PC against an xcoff_func for bsearch. */
- static int
- xcoff_func_search (const void *vkey, const void *ventry)
- {
- const uintptr_t *key = (const uintptr_t *) vkey;
- const struct xcoff_func *entry = (const struct xcoff_func *) ventry;
- uintptr_t pc;
- pc = *key;
- if (pc < entry->pc)
- return -1;
- else if ((entry->size == 0 && pc > entry->pc)
- || (entry->size > 0 && pc >= entry->pc + entry->size))
- return 1;
- else
- return 0;
- }
- /* Compare struct xcoff_incl for qsort. */
- static int
- xcoff_incl_compare (const void *v1, const void *v2)
- {
- const struct xcoff_incl *in1 = (const struct xcoff_incl *) v1;
- const struct xcoff_incl *in2 = (const struct xcoff_incl *) v2;
- if (in1->begin < in2->begin)
- return -1;
- else if (in1->begin > in2->begin)
- return 1;
- else
- return 0;
- }
- /* Find a lnnoptr in an include file. */
- static int
- xcoff_incl_search (const void *vkey, const void *ventry)
- {
- const uintptr_t *key = (const uintptr_t *) vkey;
- const struct xcoff_incl *entry = (const struct xcoff_incl *) ventry;
- uintptr_t lnno;
- lnno = *key;
- if (lnno < entry->begin)
- return -1;
- else if (lnno > entry->end)
- return 1;
- else
- return 0;
- }
- /* Look for a PC in the function vector for one module. On success,
- call CALLBACK and return whatever it returns. On error, call
- ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found,
- 0 if not. */
- static int
- xcoff_lookup_pc (struct backtrace_state *state ATTRIBUTE_UNUSED,
- struct xcoff_fileline_data *fdata, uintptr_t pc,
- backtrace_full_callback callback,
- backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
- void *data, int *found)
- {
- const struct xcoff_incl *incl, *bincl;
- const struct xcoff_func *fn;
- const b_xcoff_lineno *lineno;
- const unsigned char *lineptr;
- const char *function;
- const char *filename;
- uintptr_t lnnoptr, match;
- uint32_t lnno = 0;
- *found = 1;
- if ((pc & 3) != 0)
- ++pc;
- /* Find the function first. */
- fn = ((struct xcoff_func *)
- bsearch (&pc, fdata->func_vec.vec.base, fdata->func_vec.count,
- sizeof (struct xcoff_func), xcoff_func_search));
- if (fn == NULL)
- {
- *found = 0;
- return 0;
- }
- filename = fn->filename;
- /* Find the line number next. */
- /* Skip first entry that points to symtab. */
- lnnoptr = fn->lnnoptr + LINESZ;
- match = lnnoptr;
- lineptr = fdata->linenos + (lnnoptr - fdata->lnnoptr0);
- while (lineptr + LINESZ <= fdata->linenos + fdata->linenos_size)
- {
- lineno = (const b_xcoff_lineno *) lineptr;
- if (lineno->l_lnno == 0)
- break;
- if (pc <= fdata->base_address + lineno->l_addr.l_paddr)
- break;
- match = lnnoptr;
- lnno = lineno->l_lnno;
- lnnoptr += LINESZ;
- lineptr += LINESZ;
- }
- /* If part of a function other than the beginning comes from an
- include file, the line numbers are absolute, rather than
- relative to the beginning of the function. */
- incl = ((struct xcoff_incl *)
- bsearch (&match, fdata->incl_vec.vec.base,
- fdata->incl_vec.count, sizeof (struct xcoff_incl),
- xcoff_incl_search));
- if (incl != NULL)
- {
- bincl = ((struct xcoff_incl *)
- bsearch (&fn->lnnoptr, fdata->incl_vec.vec.base,
- fdata->incl_vec.count, sizeof (struct xcoff_incl),
- xcoff_incl_search));
- if (bincl != NULL && strcmp (incl->filename, bincl->filename) == 0)
- {
- lnno += fn->lnno - 1;
- }
- filename = incl->filename;
- }
- else
- {
- lnno += fn->lnno - 1;
- }
- function = fn->name;
- /* AIX prepends a '.' to function entry points, remove it. */
- if (function != NULL && *function == '.')
- ++function;
- return callback (data, pc, filename, lnno, function);
- }
- /* Return the file/line information for a PC using the XCOFF lineno
- mapping we built earlier. */
- static int
- xcoff_fileline (struct backtrace_state *state, uintptr_t pc,
- backtrace_full_callback callback,
- backtrace_error_callback error_callback, void *data)
- {
- struct xcoff_fileline_data *fdata;
- int found;
- int ret;
- if (!state->threaded)
- {
- for (fdata = (struct xcoff_fileline_data *) state->fileline_data;
- fdata != NULL;
- fdata = fdata->next)
- {
- ret = xcoff_lookup_pc (state, fdata, pc, callback, error_callback,
- data, &found);
- if (ret != 0 || found)
- return ret;
- }
- }
- else
- {
- struct xcoff_fileline_data **pp;
- pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
- while (1)
- {
- fdata = backtrace_atomic_load_pointer (pp);
- if (fdata == NULL)
- break;
- ret = xcoff_lookup_pc (state, fdata, pc, callback, error_callback,
- data, &found);
- if (ret != 0 || found)
- return ret;
- pp = &fdata->next;
- }
- }
- /* FIXME: See if any libraries have been dlopen'ed. */
- return callback (data, pc, NULL, 0, NULL);
- }
- /* Initialize the function vector info for xcoff_fileline. */
- static int
- xcoff_initialize_fileline (struct backtrace_state *state,
- uintptr_t base_address,
- const b_xcoff_scnhdr *sects,
- const b_xcoff_syment *syms, size_t nsyms,
- const unsigned char *strtab, size_t strtab_size,
- const unsigned char *linenos, size_t linenos_size,
- uint64_t lnnoptr0,
- backtrace_error_callback error_callback, void *data)
- {
- struct xcoff_fileline_data *fdata;
- struct xcoff_func *fn;
- const b_xcoff_syment *fsym;
- const b_xcoff_auxent *aux;
- const char *filename;
- const char *name;
- struct xcoff_incl *incl;
- uintptr_t begin, end;
- uintptr_t lnno, lnnoptr;
- uint32_t fsize;
- size_t i;
- fdata = ((struct xcoff_fileline_data *)
- backtrace_alloc (state, sizeof (struct xcoff_fileline_data),
- error_callback, data));
- if (fdata == NULL)
- return 0;
- memset (fdata, 0, sizeof *fdata);
- fdata->base_address = base_address;
- fdata->linenos = linenos;
- fdata->linenos_size = linenos_size;
- fdata->lnnoptr0 = lnnoptr0;
- begin = 0;
- filename = NULL;
- fsym = NULL;
- lnnoptr = 0;
- fsize = 0;
- for (i = 0; i < nsyms; ++i)
- {
- const b_xcoff_syment *asym = &syms[i];
- switch (asym->n_sclass)
- {
- case C_BINCL:
- begin = asym->n_value;
- break;
- case C_EINCL:
- if (begin == 0)
- break;
- end = asym->n_value;
- incl = ((struct xcoff_incl *)
- backtrace_vector_grow (state, sizeof (struct xcoff_incl),
- error_callback, data,
- &fdata->incl_vec.vec));
- if (incl != NULL)
- {
- incl->filename = xcoff_symname (asym, strtab, strtab_size);
- incl->begin = begin;
- incl->end = end;
- ++fdata->incl_vec.count;
- }
- begin = 0;
- break;
- case C_FILE:
- filename = xcoff_symname (asym, strtab, strtab_size);
- if (filename == NULL)
- break;
- /* If the file auxiliary entry is not used, the symbol name is
- the name of the source file. If the file auxiliary entry is
- used, then the symbol name should be .file, and the first
- file auxiliary entry (by convention) contains the source
- file name. */
- if (asym->n_numaux > 0 && strcmp (filename, ".file") == 0)
- {
- aux = (const b_xcoff_auxent *) (asym + 1);
- if (aux->x_file._x.x_zeroes != 0)
- {
- /* Make a copy as we will release the symtab view. */
- char name[FILNMLEN+1];
- strncpy (name, aux->x_file.x_fname, FILNMLEN);
- name[FILNMLEN] = '\0';
- filename = strdup (name);
- }
- else if (aux->x_file._x.x_offset < strtab_size)
- filename = (const char *) strtab + aux->x_file._x.x_offset;
- else
- filename = NULL;
- }
- break;
- case C_EXT:
- case C_HIDEXT:
- case C_WEAKEXT:
- fsym = NULL;
- lnnoptr = 0;
- fsize = 0;
- if (!ISFCN (asym->n_type) || asym->n_numaux == 0
- || asym->n_scnum <= 0)
- break;
- if (filename == NULL)
- break;
- aux = (const b_xcoff_auxent *) (asym + 1);
- lnnoptr = aux->x_fcn.x_lnnoptr;
- if (lnnoptr < lnnoptr0
- || lnnoptr + LINESZ > lnnoptr0 + linenos_size)
- break;
- /* x_fsize will be 0 if there is no debug information. */
- fsize = aux->x_fcn.x_fsize;
- fsym = asym;
- break;
- case C_FCN:
- if (asym->n_numaux == 0)
- break;
- if (fsym == NULL)
- break;
- name = xcoff_symname (asym, strtab, strtab_size);
- if (name == NULL || strcmp (name, ".bf") != 0)
- {
- fsym = NULL;
- break;
- }
- aux = (const b_xcoff_auxent *) (asym + 1);
- #if BACKTRACE_XCOFF_SIZE == 32
- lnno = (uint32_t) aux->x_block.x_lnnohi << 16
- | aux->x_block.x_lnno;
- #else
- lnno = aux->x_block.x_lnno;
- #endif
- fn = ((struct xcoff_func *)
- backtrace_vector_grow (state, sizeof (struct xcoff_func),
- error_callback, data,
- &fdata->func_vec.vec));
- if (fn == NULL)
- break;
- fn->name = xcoff_symname (fsym, strtab, strtab_size);
- fn->filename = filename;
- fn->sect_base = sects[fsym->n_scnum - 1].s_paddr;
- fn->pc = base_address + fsym->n_value;
- fn->size = fsize;
- fn->lnno = lnno;
- fn->lnnoptr = lnnoptr;
- ++fdata->func_vec.count;
- break;
- }
- i += asym->n_numaux;
- }
- if (!backtrace_vector_release (state, &fdata->func_vec.vec, error_callback,
- data))
- goto fail;
- backtrace_qsort (fdata->func_vec.vec.base, fdata->func_vec.count,
- sizeof (struct xcoff_func), xcoff_func_compare);
- if (!backtrace_vector_release (state, &fdata->incl_vec.vec, error_callback,
- data))
- goto fail;
- backtrace_qsort (fdata->incl_vec.vec.base, fdata->incl_vec.count,
- sizeof (struct xcoff_incl), xcoff_incl_compare);
- if (!state->threaded)
- {
- struct xcoff_fileline_data **pp;
- for (pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
- *pp != NULL;
- pp = &(*pp)->next)
- ;
- *pp = fdata;
- }
- else
- {
- while (1)
- {
- struct xcoff_fileline_data **pp;
- pp = (struct xcoff_fileline_data **) (void *) &state->fileline_data;
- while (1)
- {
- struct xcoff_fileline_data *p;
- p = backtrace_atomic_load_pointer (pp);
- if (p == NULL)
- break;
- pp = &p->next;
- }
- if (__sync_bool_compare_and_swap (pp, NULL, fdata))
- break;
- }
- }
- return 1;
- fail:
- return 0;
- }
- /* Add the backtrace data for one XCOFF file. Returns 1 on success,
- 0 on failure (in both cases descriptor is closed). */
- static int
- xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
- uintptr_t base_address, backtrace_error_callback error_callback,
- void *data, fileline *fileline_fn, int *found_sym, int exe)
- {
- struct backtrace_view fhdr_view;
- struct backtrace_view sects_view;
- struct backtrace_view linenos_view;
- struct backtrace_view syms_view;
- struct backtrace_view str_view;
- struct backtrace_view dwarf_view;
- b_xcoff_filhdr fhdr;
- const b_xcoff_scnhdr *sects;
- const b_xcoff_scnhdr *stext;
- uint64_t lnnoptr;
- uint32_t nlnno;
- off_t str_off;
- off_t min_offset;
- off_t max_offset;
- struct dwsect_info dwsect[DEBUG_MAX];
- size_t sects_size;
- size_t syms_size;
- int32_t str_size;
- int sects_view_valid;
- int linenos_view_valid;
- int syms_view_valid;
- int str_view_valid;
- int dwarf_view_valid;
- int magic_ok;
- int i;
- struct dwarf_sections dwarf_sections;
- *found_sym = 0;
- sects_view_valid = 0;
- linenos_view_valid = 0;
- syms_view_valid = 0;
- str_view_valid = 0;
- dwarf_view_valid = 0;
- str_size = 0;
- /* Map the XCOFF file header. */
- if (!backtrace_get_view (state, descriptor, offset, sizeof (b_xcoff_filhdr),
- error_callback, data, &fhdr_view))
- goto fail;
- memcpy (&fhdr, fhdr_view.data, sizeof fhdr);
- magic_ok = (fhdr.f_magic == XCOFF_MAGIC);
- backtrace_release_view (state, &fhdr_view, error_callback, data);
- if (!magic_ok)
- {
- if (exe)
- error_callback (data, "executable file is not XCOFF", 0);
- goto fail;
- }
- /* Verify object is of expected type. */
- if ((exe && (fhdr.f_flags & F_SHROBJ))
- || (!exe && !(fhdr.f_flags & F_SHROBJ)))
- goto fail;
- /* Read the section headers. */
- sects_size = fhdr.f_nscns * sizeof (b_xcoff_scnhdr);
- if (!backtrace_get_view (state, descriptor,
- offset + sizeof (fhdr) + fhdr.f_opthdr,
- sects_size, error_callback, data, §s_view))
- goto fail;
- sects_view_valid = 1;
- sects = (const b_xcoff_scnhdr *) sects_view.data;
- /* FIXME: assumes only one .text section. */
- for (i = 0; i < fhdr.f_nscns; ++i)
- if ((sects[i].s_flags & 0xffff) == STYP_TEXT)
- break;
- if (i == fhdr.f_nscns)
- goto fail;
- stext = §s[i];
- /* base_address represents the difference between the
- virtual memory address of the shared object or a loaded
- executable and the offset of that object in the file
- from which it was loaded.
- On AIX, virtual address is either fixed for executable
- or given by ldinfo. This address will include the XCOFF
- headers. */
- base_address = ((exe ? XCOFF_AIX_TEXTBASE : base_address)
- + stext->s_scnptr
- - stext->s_paddr);
- lnnoptr = stext->s_lnnoptr;
- nlnno = stext->s_nlnno;
- #if BACKTRACE_XCOFF_SIZE == 32
- if (nlnno == _OVERFLOW_MARKER)
- {
- int sntext = i + 1;
- /* Find the matching .ovrflo section. */
- for (i = 0; i < fhdr.f_nscns; ++i)
- {
- if (((sects[i].s_flags & 0xffff) == STYP_OVRFLO)
- && sects[i].s_nlnno == sntext)
- {
- nlnno = sects[i].s_vaddr;
- break;
- }
- }
- }
- #endif
- /* Read the symbol table and the string table. */
- if (fhdr.f_symptr != 0)
- {
- struct xcoff_syminfo_data *sdata;
- /* Symbol table is followed by the string table. The string table
- starts with its length (on 4 bytes).
- Map the symbol table and the length of the string table. */
- syms_size = fhdr.f_nsyms * sizeof (b_xcoff_syment);
- if (!backtrace_get_view (state, descriptor, offset + fhdr.f_symptr,
- syms_size + 4, error_callback, data,
- &syms_view))
- goto fail;
- syms_view_valid = 1;
- memcpy (&str_size, syms_view.data + syms_size, 4);
- str_off = fhdr.f_symptr + syms_size;
- if (str_size > 4)
- {
- /* Map string table (including the length word). */
- if (!backtrace_get_view (state, descriptor, offset + str_off,
- str_size, error_callback, data, &str_view))
- goto fail;
- str_view_valid = 1;
- }
- sdata = ((struct xcoff_syminfo_data *)
- backtrace_alloc (state, sizeof *sdata, error_callback, data));
- if (sdata == NULL)
- goto fail;
- if (!xcoff_initialize_syminfo (state, base_address,
- syms_view.data, fhdr.f_nsyms,
- str_view.data, str_size,
- error_callback, data, sdata))
- {
- backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
- goto fail;
- }
- *found_sym = 1;
- xcoff_add_syminfo_data (state, sdata);
- }
- /* Read all the DWARF sections in a single view, since they are
- probably adjacent in the file. We never release this view. */
- min_offset = 0;
- max_offset = 0;
- memset (dwsect, 0, sizeof dwsect);
- for (i = 0; i < fhdr.f_nscns; ++i)
- {
- off_t end;
- int idx;
- if ((sects[i].s_flags & 0xffff) != STYP_DWARF
- || sects[i].s_size == 0)
- continue;
- /* Map DWARF section to array index. */
- switch (sects[i].s_flags & 0xffff0000)
- {
- case SSUBTYP_DWINFO:
- idx = DEBUG_INFO;
- break;
- case SSUBTYP_DWLINE:
- idx = DEBUG_LINE;
- break;
- case SSUBTYP_DWABREV:
- idx = DEBUG_ABBREV;
- break;
- case SSUBTYP_DWRNGES:
- idx = DEBUG_RANGES;
- break;
- case SSUBTYP_DWSTR:
- idx = DEBUG_STR;
- break;
- default:
- continue;
- }
- if (min_offset == 0 || (off_t) sects[i].s_scnptr < min_offset)
- min_offset = sects[i].s_scnptr;
- end = sects[i].s_scnptr + sects[i].s_size;
- if (end > max_offset)
- max_offset = end;
- dwsect[idx].offset = sects[i].s_scnptr;
- dwsect[idx].size = sects[i].s_size;
- }
- if (min_offset != 0 && max_offset != 0)
- {
- if (!backtrace_get_view (state, descriptor, offset + min_offset,
- max_offset - min_offset,
- error_callback, data, &dwarf_view))
- goto fail;
- dwarf_view_valid = 1;
- for (i = 0; i < (int) DEBUG_MAX; ++i)
- {
- if (dwsect[i].offset == 0)
- dwsect[i].data = NULL;
- else
- dwsect[i].data = ((const unsigned char *) dwarf_view.data
- + (dwsect[i].offset - min_offset));
- }
- memset (&dwarf_sections, 0, sizeof dwarf_sections);
- dwarf_sections.data[DEBUG_INFO] = dwsect[DEBUG_INFO].data;
- dwarf_sections.size[DEBUG_INFO] = dwsect[DEBUG_INFO].size;
- dwarf_sections.data[DEBUG_LINE] = dwsect[DEBUG_LINE].data;
- dwarf_sections.size[DEBUG_LINE] = dwsect[DEBUG_LINE].size;
- dwarf_sections.data[DEBUG_ABBREV] = dwsect[DEBUG_ABBREV].data;
- dwarf_sections.size[DEBUG_ABBREV] = dwsect[DEBUG_ABBREV].size;
- dwarf_sections.data[DEBUG_RANGES] = dwsect[DEBUG_RANGES].data;
- dwarf_sections.size[DEBUG_RANGES] = dwsect[DEBUG_RANGES].size;
- dwarf_sections.data[DEBUG_STR] = dwsect[DEBUG_STR].data;
- dwarf_sections.size[DEBUG_STR] = dwsect[DEBUG_STR].size;
- if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,
- 1, /* big endian */
- NULL, /* altlink */
- error_callback, data, fileline_fn,
- NULL /* returned fileline_entry */))
- goto fail;
- }
- /* Read the XCOFF line number entries if DWARF sections not found. */
- if (!dwarf_view_valid && fhdr.f_symptr != 0 && lnnoptr != 0)
- {
- size_t linenos_size = (size_t) nlnno * LINESZ;
- /* We never release this view. */
- if (!backtrace_get_view (state, descriptor, offset + lnnoptr,
- linenos_size,
- error_callback, data, &linenos_view))
- goto fail;
- linenos_view_valid = 1;
- if (xcoff_initialize_fileline (state, base_address, sects,
- syms_view.data, fhdr.f_nsyms,
- str_view.data, str_size,
- linenos_view.data, linenos_size,
- lnnoptr, error_callback, data))
- *fileline_fn = xcoff_fileline;
- }
- backtrace_release_view (state, §s_view, error_callback, data);
- sects_view_valid = 0;
- if (syms_view_valid)
- backtrace_release_view (state, &syms_view, error_callback, data);
- syms_view_valid = 0;
- /* We've read all we need from the executable. */
- if (!backtrace_close (descriptor, error_callback, data))
- goto fail;
- descriptor = -1;
- return 1;
- fail:
- if (sects_view_valid)
- backtrace_release_view (state, §s_view, error_callback, data);
- if (str_view_valid)
- backtrace_release_view (state, &str_view, error_callback, data);
- if (syms_view_valid)
- backtrace_release_view (state, &syms_view, error_callback, data);
- if (linenos_view_valid)
- backtrace_release_view (state, &linenos_view, error_callback, data);
- if (dwarf_view_valid)
- backtrace_release_view (state, &dwarf_view, error_callback, data);
- if (descriptor != -1 && offset == 0)
- backtrace_close (descriptor, error_callback, data);
- return 0;
- }
- #ifdef HAVE_LOADQUERY
- /* Read an integer value in human-readable format from an AIX
- big archive fixed-length or member header. */
- static int
- xcoff_parse_decimal (const char *buf, size_t size, off_t *off)
- {
- char str[32];
- char *end;
- if (size >= sizeof str)
- return 0;
- memcpy (str, buf, size);
- str[size] = '\0';
- *off = strtol (str, &end, 10);
- if (*end != '\0' && *end != ' ')
- return 0;
- return 1;
- }
- /* Add the backtrace data for a member of an AIX big archive.
- Returns 1 on success, 0 on failure. */
- static int
- xcoff_armem_add (struct backtrace_state *state, int descriptor,
- uintptr_t base_address, const char *member,
- backtrace_error_callback error_callback, void *data,
- fileline *fileline_fn, int *found_sym)
- {
- struct backtrace_view view;
- b_ar_fl_hdr fl_hdr;
- const b_ar_hdr *ar_hdr;
- off_t off;
- off_t len;
- int memlen;
- *found_sym = 0;
- /* Map archive fixed-length header. */
- if (!backtrace_get_view (state, descriptor, 0, sizeof (b_ar_fl_hdr),
- error_callback, data, &view))
- goto fail;
- memcpy (&fl_hdr, view.data, sizeof (b_ar_fl_hdr));
- backtrace_release_view (state, &view, error_callback, data);
- if (memcmp (fl_hdr.fl_magic, AIAMAGBIG, 8) != 0)
- goto fail;
- memlen = strlen (member);
- /* Read offset of first archive member. */
- if (!xcoff_parse_decimal (fl_hdr.fl_fstmoff, sizeof fl_hdr.fl_fstmoff, &off))
- goto fail;
- while (off != 0)
- {
- /* Map archive member header and member name. */
- if (!backtrace_get_view (state, descriptor, off,
- sizeof (b_ar_hdr) + memlen,
- error_callback, data, &view))
- break;
- ar_hdr = (const b_ar_hdr *) view.data;
- /* Read archive member name length. */
- if (!xcoff_parse_decimal (ar_hdr->ar_namlen, sizeof ar_hdr->ar_namlen,
- &len))
- {
- backtrace_release_view (state, &view, error_callback, data);
- break;
- }
- if (len == memlen && !memcmp (ar_hdr->ar_name, member, memlen))
- {
- off = (off + sizeof (b_ar_hdr) + memlen + 1) & ~1;
- /* The archive can contain several members with the same name
- (e.g. 32-bit and 64-bit), so continue if not ok. */
- if (xcoff_add (state, descriptor, off, base_address, error_callback,
- data, fileline_fn, found_sym, 0))
- {
- backtrace_release_view (state, &view, error_callback, data);
- return 1;
- }
- }
- /* Read offset of next archive member. */
- if (!xcoff_parse_decimal (ar_hdr->ar_nxtmem, sizeof ar_hdr->ar_nxtmem,
- &off))
- {
- backtrace_release_view (state, &view, error_callback, data);
- break;
- }
- backtrace_release_view (state, &view, error_callback, data);
- }
- fail:
- /* No matching member found. */
- backtrace_close (descriptor, error_callback, data);
- return 0;
- }
- /* Add the backtrace data for dynamically loaded libraries. */
- static void
- xcoff_add_shared_libs (struct backtrace_state *state,
- backtrace_error_callback error_callback,
- void *data, fileline *fileline_fn, int *found_sym)
- {
- const struct ld_info *ldinfo;
- void *buf;
- unsigned int buflen;
- const char *member;
- int descriptor;
- int does_not_exist;
- int lib_found_sym;
- int ret;
- /* Retrieve the list of loaded libraries. */
- buf = NULL;
- buflen = 512;
- do
- {
- buf = realloc (buf, buflen);
- if (buf == NULL)
- {
- ret = -1;
- break;
- }
- ret = loadquery (L_GETINFO, buf, buflen);
- if (ret == 0)
- break;
- buflen *= 2;
- }
- while (ret == -1 && errno == ENOMEM);
- if (ret != 0)
- {
- free (buf);
- return;
- }
- ldinfo = (const struct ld_info *) buf;
- while ((const char *) ldinfo < (const char *) buf + buflen)
- {
- if (*ldinfo->ldinfo_filename != '/')
- goto next;
- descriptor = backtrace_open (ldinfo->ldinfo_filename, error_callback,
- data, &does_not_exist);
- if (descriptor < 0)
- goto next;
- /* Check if it is an archive (member name not empty). */
- member = ldinfo->ldinfo_filename + strlen (ldinfo->ldinfo_filename) + 1;
- if (*member)
- {
- xcoff_armem_add (state, descriptor,
- (uintptr_t) ldinfo->ldinfo_textorg, member,
- error_callback, data, fileline_fn, &lib_found_sym);
- }
- else
- {
- xcoff_add (state, descriptor, 0, (uintptr_t) ldinfo->ldinfo_textorg,
- error_callback, data, fileline_fn, &lib_found_sym, 0);
- }
- if (lib_found_sym)
- *found_sym = 1;
- next:
- if (ldinfo->ldinfo_next == 0)
- break;
- ldinfo = (const struct ld_info *) ((const char *) ldinfo
- + ldinfo->ldinfo_next);
- }
- free (buf);
- }
- #endif /* HAVE_LOADQUERY */
- /* Initialize the backtrace data we need from an XCOFF executable.
- Returns 1 on success, 0 on failure. */
- int
- backtrace_initialize (struct backtrace_state *state,
- const char *filename ATTRIBUTE_UNUSED, int descriptor,
- backtrace_error_callback error_callback,
- void *data, fileline *fileline_fn)
- {
- int ret;
- int found_sym;
- fileline xcoff_fileline_fn = xcoff_nodebug;
- ret = xcoff_add (state, descriptor, 0, 0, error_callback, data,
- &xcoff_fileline_fn, &found_sym, 1);
- if (!ret)
- return 0;
- #ifdef HAVE_LOADQUERY
- xcoff_add_shared_libs (state, error_callback, data, &xcoff_fileline_fn,
- &found_sym);
- #endif
- if (!state->threaded)
- {
- if (found_sym)
- state->syminfo_fn = xcoff_syminfo;
- else if (state->syminfo_fn == NULL)
- state->syminfo_fn = xcoff_nosyms;
- }
- else
- {
- if (found_sym)
- backtrace_atomic_store_pointer (&state->syminfo_fn, xcoff_syminfo);
- else
- (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
- xcoff_nosyms);
- }
- if (!state->threaded)
- {
- if (state->fileline_fn == NULL || state->fileline_fn == xcoff_nodebug)
- *fileline_fn = xcoff_fileline_fn;
- }
- else
- {
- fileline current_fn;
- current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
- if (current_fn == NULL || current_fn == xcoff_nodebug)
- *fileline_fn = xcoff_fileline_fn;
- }
- return 1;
- }
|