12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409 |
- /* dwarf.c -- Get file/line information from DWARF for backtraces.
- Copyright (C) 2012-2024 Free Software Foundation, Inc.
- Written by Ian Lance Taylor, Google.
- 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>
- #include "filenames.h"
- #include "backtrace.h"
- #include "internal.h"
- /* DWARF constants. */
- enum dwarf_tag {
- DW_TAG_entry_point = 0x3,
- DW_TAG_compile_unit = 0x11,
- DW_TAG_inlined_subroutine = 0x1d,
- DW_TAG_subprogram = 0x2e,
- DW_TAG_skeleton_unit = 0x4a,
- };
- enum dwarf_form {
- DW_FORM_addr = 0x01,
- DW_FORM_block2 = 0x03,
- DW_FORM_block4 = 0x04,
- DW_FORM_data2 = 0x05,
- DW_FORM_data4 = 0x06,
- DW_FORM_data8 = 0x07,
- DW_FORM_string = 0x08,
- DW_FORM_block = 0x09,
- DW_FORM_block1 = 0x0a,
- DW_FORM_data1 = 0x0b,
- DW_FORM_flag = 0x0c,
- DW_FORM_sdata = 0x0d,
- DW_FORM_strp = 0x0e,
- DW_FORM_udata = 0x0f,
- DW_FORM_ref_addr = 0x10,
- DW_FORM_ref1 = 0x11,
- DW_FORM_ref2 = 0x12,
- DW_FORM_ref4 = 0x13,
- DW_FORM_ref8 = 0x14,
- DW_FORM_ref_udata = 0x15,
- DW_FORM_indirect = 0x16,
- DW_FORM_sec_offset = 0x17,
- DW_FORM_exprloc = 0x18,
- DW_FORM_flag_present = 0x19,
- DW_FORM_ref_sig8 = 0x20,
- DW_FORM_strx = 0x1a,
- DW_FORM_addrx = 0x1b,
- DW_FORM_ref_sup4 = 0x1c,
- DW_FORM_strp_sup = 0x1d,
- DW_FORM_data16 = 0x1e,
- DW_FORM_line_strp = 0x1f,
- DW_FORM_implicit_const = 0x21,
- DW_FORM_loclistx = 0x22,
- DW_FORM_rnglistx = 0x23,
- DW_FORM_ref_sup8 = 0x24,
- DW_FORM_strx1 = 0x25,
- DW_FORM_strx2 = 0x26,
- DW_FORM_strx3 = 0x27,
- DW_FORM_strx4 = 0x28,
- DW_FORM_addrx1 = 0x29,
- DW_FORM_addrx2 = 0x2a,
- DW_FORM_addrx3 = 0x2b,
- DW_FORM_addrx4 = 0x2c,
- DW_FORM_GNU_addr_index = 0x1f01,
- DW_FORM_GNU_str_index = 0x1f02,
- DW_FORM_GNU_ref_alt = 0x1f20,
- DW_FORM_GNU_strp_alt = 0x1f21
- };
- enum dwarf_attribute {
- DW_AT_sibling = 0x01,
- DW_AT_location = 0x02,
- DW_AT_name = 0x03,
- DW_AT_ordering = 0x09,
- DW_AT_subscr_data = 0x0a,
- DW_AT_byte_size = 0x0b,
- DW_AT_bit_offset = 0x0c,
- DW_AT_bit_size = 0x0d,
- DW_AT_element_list = 0x0f,
- DW_AT_stmt_list = 0x10,
- DW_AT_low_pc = 0x11,
- DW_AT_high_pc = 0x12,
- DW_AT_language = 0x13,
- DW_AT_member = 0x14,
- DW_AT_discr = 0x15,
- DW_AT_discr_value = 0x16,
- DW_AT_visibility = 0x17,
- DW_AT_import = 0x18,
- DW_AT_string_length = 0x19,
- DW_AT_common_reference = 0x1a,
- DW_AT_comp_dir = 0x1b,
- DW_AT_const_value = 0x1c,
- DW_AT_containing_type = 0x1d,
- DW_AT_default_value = 0x1e,
- DW_AT_inline = 0x20,
- DW_AT_is_optional = 0x21,
- DW_AT_lower_bound = 0x22,
- DW_AT_producer = 0x25,
- DW_AT_prototyped = 0x27,
- DW_AT_return_addr = 0x2a,
- DW_AT_start_scope = 0x2c,
- DW_AT_bit_stride = 0x2e,
- DW_AT_upper_bound = 0x2f,
- DW_AT_abstract_origin = 0x31,
- DW_AT_accessibility = 0x32,
- DW_AT_address_class = 0x33,
- DW_AT_artificial = 0x34,
- DW_AT_base_types = 0x35,
- DW_AT_calling_convention = 0x36,
- DW_AT_count = 0x37,
- DW_AT_data_member_location = 0x38,
- DW_AT_decl_column = 0x39,
- DW_AT_decl_file = 0x3a,
- DW_AT_decl_line = 0x3b,
- DW_AT_declaration = 0x3c,
- DW_AT_discr_list = 0x3d,
- DW_AT_encoding = 0x3e,
- DW_AT_external = 0x3f,
- DW_AT_frame_base = 0x40,
- DW_AT_friend = 0x41,
- DW_AT_identifier_case = 0x42,
- DW_AT_macro_info = 0x43,
- DW_AT_namelist_items = 0x44,
- DW_AT_priority = 0x45,
- DW_AT_segment = 0x46,
- DW_AT_specification = 0x47,
- DW_AT_static_link = 0x48,
- DW_AT_type = 0x49,
- DW_AT_use_location = 0x4a,
- DW_AT_variable_parameter = 0x4b,
- DW_AT_virtuality = 0x4c,
- DW_AT_vtable_elem_location = 0x4d,
- DW_AT_allocated = 0x4e,
- DW_AT_associated = 0x4f,
- DW_AT_data_location = 0x50,
- DW_AT_byte_stride = 0x51,
- DW_AT_entry_pc = 0x52,
- DW_AT_use_UTF8 = 0x53,
- DW_AT_extension = 0x54,
- DW_AT_ranges = 0x55,
- DW_AT_trampoline = 0x56,
- DW_AT_call_column = 0x57,
- DW_AT_call_file = 0x58,
- DW_AT_call_line = 0x59,
- DW_AT_description = 0x5a,
- DW_AT_binary_scale = 0x5b,
- DW_AT_decimal_scale = 0x5c,
- DW_AT_small = 0x5d,
- DW_AT_decimal_sign = 0x5e,
- DW_AT_digit_count = 0x5f,
- DW_AT_picture_string = 0x60,
- DW_AT_mutable = 0x61,
- DW_AT_threads_scaled = 0x62,
- DW_AT_explicit = 0x63,
- DW_AT_object_pointer = 0x64,
- DW_AT_endianity = 0x65,
- DW_AT_elemental = 0x66,
- DW_AT_pure = 0x67,
- DW_AT_recursive = 0x68,
- DW_AT_signature = 0x69,
- DW_AT_main_subprogram = 0x6a,
- DW_AT_data_bit_offset = 0x6b,
- DW_AT_const_expr = 0x6c,
- DW_AT_enum_class = 0x6d,
- DW_AT_linkage_name = 0x6e,
- DW_AT_string_length_bit_size = 0x6f,
- DW_AT_string_length_byte_size = 0x70,
- DW_AT_rank = 0x71,
- DW_AT_str_offsets_base = 0x72,
- DW_AT_addr_base = 0x73,
- DW_AT_rnglists_base = 0x74,
- DW_AT_dwo_name = 0x76,
- DW_AT_reference = 0x77,
- DW_AT_rvalue_reference = 0x78,
- DW_AT_macros = 0x79,
- DW_AT_call_all_calls = 0x7a,
- DW_AT_call_all_source_calls = 0x7b,
- DW_AT_call_all_tail_calls = 0x7c,
- DW_AT_call_return_pc = 0x7d,
- DW_AT_call_value = 0x7e,
- DW_AT_call_origin = 0x7f,
- DW_AT_call_parameter = 0x80,
- DW_AT_call_pc = 0x81,
- DW_AT_call_tail_call = 0x82,
- DW_AT_call_target = 0x83,
- DW_AT_call_target_clobbered = 0x84,
- DW_AT_call_data_location = 0x85,
- DW_AT_call_data_value = 0x86,
- DW_AT_noreturn = 0x87,
- DW_AT_alignment = 0x88,
- DW_AT_export_symbols = 0x89,
- DW_AT_deleted = 0x8a,
- DW_AT_defaulted = 0x8b,
- DW_AT_loclists_base = 0x8c,
- DW_AT_lo_user = 0x2000,
- DW_AT_hi_user = 0x3fff,
- DW_AT_MIPS_fde = 0x2001,
- DW_AT_MIPS_loop_begin = 0x2002,
- DW_AT_MIPS_tail_loop_begin = 0x2003,
- DW_AT_MIPS_epilog_begin = 0x2004,
- DW_AT_MIPS_loop_unroll_factor = 0x2005,
- DW_AT_MIPS_software_pipeline_depth = 0x2006,
- DW_AT_MIPS_linkage_name = 0x2007,
- DW_AT_MIPS_stride = 0x2008,
- DW_AT_MIPS_abstract_name = 0x2009,
- DW_AT_MIPS_clone_origin = 0x200a,
- DW_AT_MIPS_has_inlines = 0x200b,
- DW_AT_HP_block_index = 0x2000,
- DW_AT_HP_unmodifiable = 0x2001,
- DW_AT_HP_prologue = 0x2005,
- DW_AT_HP_epilogue = 0x2008,
- DW_AT_HP_actuals_stmt_list = 0x2010,
- DW_AT_HP_proc_per_section = 0x2011,
- DW_AT_HP_raw_data_ptr = 0x2012,
- DW_AT_HP_pass_by_reference = 0x2013,
- DW_AT_HP_opt_level = 0x2014,
- DW_AT_HP_prof_version_id = 0x2015,
- DW_AT_HP_opt_flags = 0x2016,
- DW_AT_HP_cold_region_low_pc = 0x2017,
- DW_AT_HP_cold_region_high_pc = 0x2018,
- DW_AT_HP_all_variables_modifiable = 0x2019,
- DW_AT_HP_linkage_name = 0x201a,
- DW_AT_HP_prof_flags = 0x201b,
- DW_AT_HP_unit_name = 0x201f,
- DW_AT_HP_unit_size = 0x2020,
- DW_AT_HP_widened_byte_size = 0x2021,
- DW_AT_HP_definition_points = 0x2022,
- DW_AT_HP_default_location = 0x2023,
- DW_AT_HP_is_result_param = 0x2029,
- DW_AT_sf_names = 0x2101,
- DW_AT_src_info = 0x2102,
- DW_AT_mac_info = 0x2103,
- DW_AT_src_coords = 0x2104,
- DW_AT_body_begin = 0x2105,
- DW_AT_body_end = 0x2106,
- DW_AT_GNU_vector = 0x2107,
- DW_AT_GNU_guarded_by = 0x2108,
- DW_AT_GNU_pt_guarded_by = 0x2109,
- DW_AT_GNU_guarded = 0x210a,
- DW_AT_GNU_pt_guarded = 0x210b,
- DW_AT_GNU_locks_excluded = 0x210c,
- DW_AT_GNU_exclusive_locks_required = 0x210d,
- DW_AT_GNU_shared_locks_required = 0x210e,
- DW_AT_GNU_odr_signature = 0x210f,
- DW_AT_GNU_template_name = 0x2110,
- DW_AT_GNU_call_site_value = 0x2111,
- DW_AT_GNU_call_site_data_value = 0x2112,
- DW_AT_GNU_call_site_target = 0x2113,
- DW_AT_GNU_call_site_target_clobbered = 0x2114,
- DW_AT_GNU_tail_call = 0x2115,
- DW_AT_GNU_all_tail_call_sites = 0x2116,
- DW_AT_GNU_all_call_sites = 0x2117,
- DW_AT_GNU_all_source_call_sites = 0x2118,
- DW_AT_GNU_macros = 0x2119,
- DW_AT_GNU_deleted = 0x211a,
- DW_AT_GNU_dwo_name = 0x2130,
- DW_AT_GNU_dwo_id = 0x2131,
- DW_AT_GNU_ranges_base = 0x2132,
- DW_AT_GNU_addr_base = 0x2133,
- DW_AT_GNU_pubnames = 0x2134,
- DW_AT_GNU_pubtypes = 0x2135,
- DW_AT_GNU_discriminator = 0x2136,
- DW_AT_GNU_locviews = 0x2137,
- DW_AT_GNU_entry_view = 0x2138,
- DW_AT_VMS_rtnbeg_pd_address = 0x2201,
- DW_AT_use_GNAT_descriptive_type = 0x2301,
- DW_AT_GNAT_descriptive_type = 0x2302,
- DW_AT_GNU_numerator = 0x2303,
- DW_AT_GNU_denominator = 0x2304,
- DW_AT_GNU_bias = 0x2305,
- DW_AT_upc_threads_scaled = 0x3210,
- DW_AT_PGI_lbase = 0x3a00,
- DW_AT_PGI_soffset = 0x3a01,
- DW_AT_PGI_lstride = 0x3a02,
- DW_AT_APPLE_optimized = 0x3fe1,
- DW_AT_APPLE_flags = 0x3fe2,
- DW_AT_APPLE_isa = 0x3fe3,
- DW_AT_APPLE_block = 0x3fe4,
- DW_AT_APPLE_major_runtime_vers = 0x3fe5,
- DW_AT_APPLE_runtime_class = 0x3fe6,
- DW_AT_APPLE_omit_frame_ptr = 0x3fe7,
- DW_AT_APPLE_property_name = 0x3fe8,
- DW_AT_APPLE_property_getter = 0x3fe9,
- DW_AT_APPLE_property_setter = 0x3fea,
- DW_AT_APPLE_property_attribute = 0x3feb,
- DW_AT_APPLE_objc_complete_type = 0x3fec,
- DW_AT_APPLE_property = 0x3fed
- };
- enum dwarf_line_number_op {
- DW_LNS_extended_op = 0x0,
- DW_LNS_copy = 0x1,
- DW_LNS_advance_pc = 0x2,
- DW_LNS_advance_line = 0x3,
- DW_LNS_set_file = 0x4,
- DW_LNS_set_column = 0x5,
- DW_LNS_negate_stmt = 0x6,
- DW_LNS_set_basic_block = 0x7,
- DW_LNS_const_add_pc = 0x8,
- DW_LNS_fixed_advance_pc = 0x9,
- DW_LNS_set_prologue_end = 0xa,
- DW_LNS_set_epilogue_begin = 0xb,
- DW_LNS_set_isa = 0xc,
- };
- enum dwarf_extended_line_number_op {
- DW_LNE_end_sequence = 0x1,
- DW_LNE_set_address = 0x2,
- DW_LNE_define_file = 0x3,
- DW_LNE_set_discriminator = 0x4,
- };
- enum dwarf_line_number_content_type {
- DW_LNCT_path = 0x1,
- DW_LNCT_directory_index = 0x2,
- DW_LNCT_timestamp = 0x3,
- DW_LNCT_size = 0x4,
- DW_LNCT_MD5 = 0x5,
- DW_LNCT_lo_user = 0x2000,
- DW_LNCT_hi_user = 0x3fff
- };
- enum dwarf_range_list_entry {
- DW_RLE_end_of_list = 0x00,
- DW_RLE_base_addressx = 0x01,
- DW_RLE_startx_endx = 0x02,
- DW_RLE_startx_length = 0x03,
- DW_RLE_offset_pair = 0x04,
- DW_RLE_base_address = 0x05,
- DW_RLE_start_end = 0x06,
- DW_RLE_start_length = 0x07
- };
- enum dwarf_unit_type {
- DW_UT_compile = 0x01,
- DW_UT_type = 0x02,
- DW_UT_partial = 0x03,
- DW_UT_skeleton = 0x04,
- DW_UT_split_compile = 0x05,
- DW_UT_split_type = 0x06,
- DW_UT_lo_user = 0x80,
- DW_UT_hi_user = 0xff
- };
- #if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN
- /* If strnlen is not declared, provide our own version. */
- static size_t
- xstrnlen (const char *s, size_t maxlen)
- {
- size_t i;
- for (i = 0; i < maxlen; ++i)
- if (s[i] == '\0')
- break;
- return i;
- }
- #define strnlen xstrnlen
- #endif
- /* A buffer to read DWARF info. */
- struct dwarf_buf
- {
- /* Buffer name for error messages. */
- const char *name;
- /* Start of the buffer. */
- const unsigned char *start;
- /* Next byte to read. */
- const unsigned char *buf;
- /* The number of bytes remaining. */
- size_t left;
- /* Whether the data is big-endian. */
- int is_bigendian;
- /* Error callback routine. */
- backtrace_error_callback error_callback;
- /* Data for error_callback. */
- void *data;
- /* Non-zero if we've reported an underflow error. */
- int reported_underflow;
- };
- /* A single attribute in a DWARF abbreviation. */
- struct attr
- {
- /* The attribute name. */
- enum dwarf_attribute name;
- /* The attribute form. */
- enum dwarf_form form;
- /* The attribute value, for DW_FORM_implicit_const. */
- int64_t val;
- };
- /* A single DWARF abbreviation. */
- struct abbrev
- {
- /* The abbrev code--the number used to refer to the abbrev. */
- uint64_t code;
- /* The entry tag. */
- enum dwarf_tag tag;
- /* Non-zero if this abbrev has child entries. */
- int has_children;
- /* The number of attributes. */
- size_t num_attrs;
- /* The attributes. */
- struct attr *attrs;
- };
- /* The DWARF abbreviations for a compilation unit. This structure
- only exists while reading the compilation unit. Most DWARF readers
- seem to a hash table to map abbrev ID's to abbrev entries.
- However, we primarily care about GCC, and GCC simply issues ID's in
- numerical order starting at 1. So we simply keep a sorted vector,
- and try to just look up the code. */
- struct abbrevs
- {
- /* The number of abbrevs in the vector. */
- size_t num_abbrevs;
- /* The abbrevs, sorted by the code field. */
- struct abbrev *abbrevs;
- };
- /* The different kinds of attribute values. */
- enum attr_val_encoding
- {
- /* No attribute value. */
- ATTR_VAL_NONE,
- /* An address. */
- ATTR_VAL_ADDRESS,
- /* An index into the .debug_addr section, whose value is relative to
- the DW_AT_addr_base attribute of the compilation unit. */
- ATTR_VAL_ADDRESS_INDEX,
- /* A unsigned integer. */
- ATTR_VAL_UINT,
- /* A sigd integer. */
- ATTR_VAL_SINT,
- /* A string. */
- ATTR_VAL_STRING,
- /* An index into the .debug_str_offsets section. */
- ATTR_VAL_STRING_INDEX,
- /* An offset to other data in the containing unit. */
- ATTR_VAL_REF_UNIT,
- /* An offset to other data within the .debug_info section. */
- ATTR_VAL_REF_INFO,
- /* An offset to other data within the alt .debug_info section. */
- ATTR_VAL_REF_ALT_INFO,
- /* An offset to data in some other section. */
- ATTR_VAL_REF_SECTION,
- /* A type signature. */
- ATTR_VAL_REF_TYPE,
- /* An index into the .debug_rnglists section. */
- ATTR_VAL_RNGLISTS_INDEX,
- /* A block of data (not represented). */
- ATTR_VAL_BLOCK,
- /* An expression (not represented). */
- ATTR_VAL_EXPR,
- };
- /* An attribute value. */
- struct attr_val
- {
- /* How the value is stored in the field u. */
- enum attr_val_encoding encoding;
- union
- {
- /* ATTR_VAL_ADDRESS*, ATTR_VAL_UINT, ATTR_VAL_REF*. */
- uint64_t uint;
- /* ATTR_VAL_SINT. */
- int64_t sint;
- /* ATTR_VAL_STRING. */
- const char *string;
- /* ATTR_VAL_BLOCK not stored. */
- } u;
- };
- /* The line number program header. */
- struct line_header
- {
- /* The version of the line number information. */
- int version;
- /* Address size. */
- int addrsize;
- /* The minimum instruction length. */
- unsigned int min_insn_len;
- /* The maximum number of ops per instruction. */
- unsigned int max_ops_per_insn;
- /* The line base for special opcodes. */
- int line_base;
- /* The line range for special opcodes. */
- unsigned int line_range;
- /* The opcode base--the first special opcode. */
- unsigned int opcode_base;
- /* Opcode lengths, indexed by opcode - 1. */
- const unsigned char *opcode_lengths;
- /* The number of directory entries. */
- size_t dirs_count;
- /* The directory entries. */
- const char **dirs;
- /* The number of filenames. */
- size_t filenames_count;
- /* The filenames. */
- const char **filenames;
- };
- /* A format description from a line header. */
- struct line_header_format
- {
- int lnct; /* LNCT code. */
- enum dwarf_form form; /* Form of entry data. */
- };
- /* Map a single PC value to a file/line. We will keep a vector of
- these sorted by PC value. Each file/line will be correct from the
- PC up to the PC of the next entry if there is one. We allocate one
- extra entry at the end so that we can use bsearch. */
- struct line
- {
- /* PC. */
- uintptr_t pc;
- /* File name. Many entries in the array are expected to point to
- the same file name. */
- const char *filename;
- /* Line number. */
- int lineno;
- /* Index of the object in the original array read from the DWARF
- section, before it has been sorted. The index makes it possible
- to use Quicksort and maintain stability. */
- int idx;
- };
- /* A growable vector of line number information. This is used while
- reading the line numbers. */
- struct line_vector
- {
- /* Memory. This is an array of struct line. */
- struct backtrace_vector vec;
- /* Number of valid mappings. */
- size_t count;
- };
- /* A function described in the debug info. */
- struct function
- {
- /* The name of the function. */
- const char *name;
- /* If this is an inlined function, the filename of the call
- site. */
- const char *caller_filename;
- /* If this is an inlined function, the line number of the call
- site. */
- int caller_lineno;
- /* Map PC ranges to inlined functions. */
- struct function_addrs *function_addrs;
- size_t function_addrs_count;
- };
- /* An address range for a function. This maps a PC value to a
- specific function. */
- struct function_addrs
- {
- /* Range is LOW <= PC < HIGH. */
- uintptr_t low;
- uintptr_t high;
- /* Function for this address range. */
- struct function *function;
- };
- /* A growable vector of function address ranges. */
- struct function_vector
- {
- /* Memory. This is an array of struct function_addrs. */
- struct backtrace_vector vec;
- /* Number of address ranges present. */
- size_t count;
- };
- /* A DWARF compilation unit. This only holds the information we need
- to map a PC to a file and line. */
- struct unit
- {
- /* The first entry for this compilation unit. */
- const unsigned char *unit_data;
- /* The length of the data for this compilation unit. */
- size_t unit_data_len;
- /* The offset of UNIT_DATA from the start of the information for
- this compilation unit. */
- size_t unit_data_offset;
- /* Offset of the start of the compilation unit from the start of the
- .debug_info section. */
- size_t low_offset;
- /* Offset of the end of the compilation unit from the start of the
- .debug_info section. */
- size_t high_offset;
- /* DWARF version. */
- int version;
- /* Whether unit is DWARF64. */
- int is_dwarf64;
- /* Address size. */
- int addrsize;
- /* Offset into line number information. */
- off_t lineoff;
- /* Offset of compilation unit in .debug_str_offsets. */
- uint64_t str_offsets_base;
- /* Offset of compilation unit in .debug_addr. */
- uint64_t addr_base;
- /* Offset of compilation unit in .debug_rnglists. */
- uint64_t rnglists_base;
- /* Primary source file. */
- const char *filename;
- /* Compilation command working directory. */
- const char *comp_dir;
- /* Absolute file name, only set if needed. */
- const char *abs_filename;
- /* The abbreviations for this unit. */
- struct abbrevs abbrevs;
- /* The fields above this point are read in during initialization and
- may be accessed freely. The fields below this point are read in
- as needed, and therefore require care, as different threads may
- try to initialize them simultaneously. */
- /* PC to line number mapping. This is NULL if the values have not
- been read. This is (struct line *) -1 if there was an error
- reading the values. */
- struct line *lines;
- /* Number of entries in lines. */
- size_t lines_count;
- /* PC ranges to function. */
- struct function_addrs *function_addrs;
- size_t function_addrs_count;
- };
- /* An address range for a compilation unit. This maps a PC value to a
- specific compilation unit. Note that we invert the representation
- in DWARF: instead of listing the units and attaching a list of
- ranges, we list the ranges and have each one point to the unit.
- This lets us do a binary search to find the unit. */
- struct unit_addrs
- {
- /* Range is LOW <= PC < HIGH. */
- uintptr_t low;
- uintptr_t high;
- /* Compilation unit for this address range. */
- struct unit *u;
- };
- /* A growable vector of compilation unit address ranges. */
- struct unit_addrs_vector
- {
- /* Memory. This is an array of struct unit_addrs. */
- struct backtrace_vector vec;
- /* Number of address ranges present. */
- size_t count;
- };
- /* A growable vector of compilation unit pointer. */
- struct unit_vector
- {
- struct backtrace_vector vec;
- size_t count;
- };
- /* The information we need to map a PC to a file and line. */
- struct dwarf_data
- {
- /* The data for the next file we know about. */
- struct dwarf_data *next;
- /* The data for .gnu_debugaltlink. */
- struct dwarf_data *altlink;
- /* The base address mapping for this file. */
- struct libbacktrace_base_address base_address;
- /* A sorted list of address ranges. */
- struct unit_addrs *addrs;
- /* Number of address ranges in list. */
- size_t addrs_count;
- /* A sorted list of units. */
- struct unit **units;
- /* Number of units in the list. */
- size_t units_count;
- /* The unparsed DWARF debug data. */
- struct dwarf_sections dwarf_sections;
- /* Whether the data is big-endian or not. */
- int is_bigendian;
- /* A vector used for function addresses. We keep this here so that
- we can grow the vector as we read more functions. */
- struct function_vector fvec;
- };
- /* Report an error for a DWARF buffer. */
- static void
- dwarf_buf_error (struct dwarf_buf *buf, const char *msg, int errnum)
- {
- char b[200];
- snprintf (b, sizeof b, "%s in %s at %d",
- msg, buf->name, (int) (buf->buf - buf->start));
- buf->error_callback (buf->data, b, errnum);
- }
- /* Require at least COUNT bytes in BUF. Return 1 if all is well, 0 on
- error. */
- static int
- require (struct dwarf_buf *buf, size_t count)
- {
- if (buf->left >= count)
- return 1;
- if (!buf->reported_underflow)
- {
- dwarf_buf_error (buf, "DWARF underflow", 0);
- buf->reported_underflow = 1;
- }
- return 0;
- }
- /* Advance COUNT bytes in BUF. Return 1 if all is well, 0 on
- error. */
- static int
- advance (struct dwarf_buf *buf, size_t count)
- {
- if (!require (buf, count))
- return 0;
- buf->buf += count;
- buf->left -= count;
- return 1;
- }
- /* Read one zero-terminated string from BUF and advance past the string. */
- static const char *
- read_string (struct dwarf_buf *buf)
- {
- const char *p = (const char *)buf->buf;
- size_t len = strnlen (p, buf->left);
- /* - If len == left, we ran out of buffer before finding the zero terminator.
- Generate an error by advancing len + 1.
- - If len < left, advance by len + 1 to skip past the zero terminator. */
- size_t count = len + 1;
- if (!advance (buf, count))
- return NULL;
- return p;
- }
- /* Read one byte from BUF and advance 1 byte. */
- static unsigned char
- read_byte (struct dwarf_buf *buf)
- {
- const unsigned char *p = buf->buf;
- if (!advance (buf, 1))
- return 0;
- return p[0];
- }
- /* Read a signed char from BUF and advance 1 byte. */
- static signed char
- read_sbyte (struct dwarf_buf *buf)
- {
- const unsigned char *p = buf->buf;
- if (!advance (buf, 1))
- return 0;
- return (*p ^ 0x80) - 0x80;
- }
- /* Read a uint16 from BUF and advance 2 bytes. */
- static uint16_t
- read_uint16 (struct dwarf_buf *buf)
- {
- const unsigned char *p = buf->buf;
- if (!advance (buf, 2))
- return 0;
- if (buf->is_bigendian)
- return ((uint16_t) p[0] << 8) | (uint16_t) p[1];
- else
- return ((uint16_t) p[1] << 8) | (uint16_t) p[0];
- }
- /* Read a 24 bit value from BUF and advance 3 bytes. */
- static uint32_t
- read_uint24 (struct dwarf_buf *buf)
- {
- const unsigned char *p = buf->buf;
- if (!advance (buf, 3))
- return 0;
- if (buf->is_bigendian)
- return (((uint32_t) p[0] << 16) | ((uint32_t) p[1] << 8)
- | (uint32_t) p[2]);
- else
- return (((uint32_t) p[2] << 16) | ((uint32_t) p[1] << 8)
- | (uint32_t) p[0]);
- }
- /* Read a uint32 from BUF and advance 4 bytes. */
- static uint32_t
- read_uint32 (struct dwarf_buf *buf)
- {
- const unsigned char *p = buf->buf;
- if (!advance (buf, 4))
- return 0;
- if (buf->is_bigendian)
- return (((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16)
- | ((uint32_t) p[2] << 8) | (uint32_t) p[3]);
- else
- return (((uint32_t) p[3] << 24) | ((uint32_t) p[2] << 16)
- | ((uint32_t) p[1] << 8) | (uint32_t) p[0]);
- }
- /* Read a uint64 from BUF and advance 8 bytes. */
- static uint64_t
- read_uint64 (struct dwarf_buf *buf)
- {
- const unsigned char *p = buf->buf;
- if (!advance (buf, 8))
- return 0;
- if (buf->is_bigendian)
- return (((uint64_t) p[0] << 56) | ((uint64_t) p[1] << 48)
- | ((uint64_t) p[2] << 40) | ((uint64_t) p[3] << 32)
- | ((uint64_t) p[4] << 24) | ((uint64_t) p[5] << 16)
- | ((uint64_t) p[6] << 8) | (uint64_t) p[7]);
- else
- return (((uint64_t) p[7] << 56) | ((uint64_t) p[6] << 48)
- | ((uint64_t) p[5] << 40) | ((uint64_t) p[4] << 32)
- | ((uint64_t) p[3] << 24) | ((uint64_t) p[2] << 16)
- | ((uint64_t) p[1] << 8) | (uint64_t) p[0]);
- }
- /* Read an offset from BUF and advance the appropriate number of
- bytes. */
- static uint64_t
- read_offset (struct dwarf_buf *buf, int is_dwarf64)
- {
- if (is_dwarf64)
- return read_uint64 (buf);
- else
- return read_uint32 (buf);
- }
- /* Read an address from BUF and advance the appropriate number of
- bytes. */
- static uint64_t
- read_address (struct dwarf_buf *buf, int addrsize)
- {
- switch (addrsize)
- {
- case 1:
- return read_byte (buf);
- case 2:
- return read_uint16 (buf);
- case 4:
- return read_uint32 (buf);
- case 8:
- return read_uint64 (buf);
- default:
- dwarf_buf_error (buf, "unrecognized address size", 0);
- return 0;
- }
- }
- /* Return whether a value is the highest possible address, given the
- address size. */
- static int
- is_highest_address (uint64_t address, int addrsize)
- {
- switch (addrsize)
- {
- case 1:
- return address == (unsigned char) -1;
- case 2:
- return address == (uint16_t) -1;
- case 4:
- return address == (uint32_t) -1;
- case 8:
- return address == (uint64_t) -1;
- default:
- return 0;
- }
- }
- /* Read an unsigned LEB128 number. */
- static uint64_t
- read_uleb128 (struct dwarf_buf *buf)
- {
- uint64_t ret;
- unsigned int shift;
- int overflow;
- unsigned char b;
- ret = 0;
- shift = 0;
- overflow = 0;
- do
- {
- const unsigned char *p;
- p = buf->buf;
- if (!advance (buf, 1))
- return 0;
- b = *p;
- if (shift < 64)
- ret |= ((uint64_t) (b & 0x7f)) << shift;
- else if (!overflow)
- {
- dwarf_buf_error (buf, "LEB128 overflows uint64_t", 0);
- overflow = 1;
- }
- shift += 7;
- }
- while ((b & 0x80) != 0);
- return ret;
- }
- /* Read a signed LEB128 number. */
- static int64_t
- read_sleb128 (struct dwarf_buf *buf)
- {
- uint64_t val;
- unsigned int shift;
- int overflow;
- unsigned char b;
- val = 0;
- shift = 0;
- overflow = 0;
- do
- {
- const unsigned char *p;
- p = buf->buf;
- if (!advance (buf, 1))
- return 0;
- b = *p;
- if (shift < 64)
- val |= ((uint64_t) (b & 0x7f)) << shift;
- else if (!overflow)
- {
- dwarf_buf_error (buf, "signed LEB128 overflows uint64_t", 0);
- overflow = 1;
- }
- shift += 7;
- }
- while ((b & 0x80) != 0);
- if ((b & 0x40) != 0 && shift < 64)
- val |= ((uint64_t) -1) << shift;
- return (int64_t) val;
- }
- /* Return the length of an LEB128 number. */
- static size_t
- leb128_len (const unsigned char *p)
- {
- size_t ret;
- ret = 1;
- while ((*p & 0x80) != 0)
- {
- ++p;
- ++ret;
- }
- return ret;
- }
- /* Read initial_length from BUF and advance the appropriate number of bytes. */
- static uint64_t
- read_initial_length (struct dwarf_buf *buf, int *is_dwarf64)
- {
- uint64_t len;
- len = read_uint32 (buf);
- if (len == 0xffffffff)
- {
- len = read_uint64 (buf);
- *is_dwarf64 = 1;
- }
- else
- *is_dwarf64 = 0;
- return len;
- }
- /* Free an abbreviations structure. */
- static void
- free_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs,
- backtrace_error_callback error_callback, void *data)
- {
- size_t i;
- for (i = 0; i < abbrevs->num_abbrevs; ++i)
- backtrace_free (state, abbrevs->abbrevs[i].attrs,
- abbrevs->abbrevs[i].num_attrs * sizeof (struct attr),
- error_callback, data);
- backtrace_free (state, abbrevs->abbrevs,
- abbrevs->num_abbrevs * sizeof (struct abbrev),
- error_callback, data);
- abbrevs->num_abbrevs = 0;
- abbrevs->abbrevs = NULL;
- }
- /* Read an attribute value. Returns 1 on success, 0 on failure. If
- the value can be represented as a uint64_t, sets *VAL and sets
- *IS_VALID to 1. We don't try to store the value of other attribute
- forms, because we don't care about them. */
- static int
- read_attribute (enum dwarf_form form, uint64_t implicit_val,
- struct dwarf_buf *buf, int is_dwarf64, int version,
- int addrsize, const struct dwarf_sections *dwarf_sections,
- struct dwarf_data *altlink, struct attr_val *val)
- {
- /* Avoid warnings about val.u.FIELD may be used uninitialized if
- this function is inlined. The warnings aren't valid but can
- occur because the different fields are set and used
- conditionally. */
- memset (val, 0, sizeof *val);
- switch (form)
- {
- case DW_FORM_addr:
- val->encoding = ATTR_VAL_ADDRESS;
- val->u.uint = read_address (buf, addrsize);
- return 1;
- case DW_FORM_block2:
- val->encoding = ATTR_VAL_BLOCK;
- return advance (buf, read_uint16 (buf));
- case DW_FORM_block4:
- val->encoding = ATTR_VAL_BLOCK;
- return advance (buf, read_uint32 (buf));
- case DW_FORM_data2:
- val->encoding = ATTR_VAL_UINT;
- val->u.uint = read_uint16 (buf);
- return 1;
- case DW_FORM_data4:
- val->encoding = ATTR_VAL_UINT;
- val->u.uint = read_uint32 (buf);
- return 1;
- case DW_FORM_data8:
- val->encoding = ATTR_VAL_UINT;
- val->u.uint = read_uint64 (buf);
- return 1;
- case DW_FORM_data16:
- val->encoding = ATTR_VAL_BLOCK;
- return advance (buf, 16);
- case DW_FORM_string:
- val->encoding = ATTR_VAL_STRING;
- val->u.string = read_string (buf);
- return val->u.string == NULL ? 0 : 1;
- case DW_FORM_block:
- val->encoding = ATTR_VAL_BLOCK;
- return advance (buf, read_uleb128 (buf));
- case DW_FORM_block1:
- val->encoding = ATTR_VAL_BLOCK;
- return advance (buf, read_byte (buf));
- case DW_FORM_data1:
- val->encoding = ATTR_VAL_UINT;
- val->u.uint = read_byte (buf);
- return 1;
- case DW_FORM_flag:
- val->encoding = ATTR_VAL_UINT;
- val->u.uint = read_byte (buf);
- return 1;
- case DW_FORM_sdata:
- val->encoding = ATTR_VAL_SINT;
- val->u.sint = read_sleb128 (buf);
- return 1;
- case DW_FORM_strp:
- {
- uint64_t offset;
- offset = read_offset (buf, is_dwarf64);
- if (offset >= dwarf_sections->size[DEBUG_STR])
- {
- dwarf_buf_error (buf, "DW_FORM_strp out of range", 0);
- return 0;
- }
- val->encoding = ATTR_VAL_STRING;
- val->u.string =
- (const char *) dwarf_sections->data[DEBUG_STR] + offset;
- return 1;
- }
- case DW_FORM_line_strp:
- {
- uint64_t offset;
- offset = read_offset (buf, is_dwarf64);
- if (offset >= dwarf_sections->size[DEBUG_LINE_STR])
- {
- dwarf_buf_error (buf, "DW_FORM_line_strp out of range", 0);
- return 0;
- }
- val->encoding = ATTR_VAL_STRING;
- val->u.string =
- (const char *) dwarf_sections->data[DEBUG_LINE_STR] + offset;
- return 1;
- }
- case DW_FORM_udata:
- val->encoding = ATTR_VAL_UINT;
- val->u.uint = read_uleb128 (buf);
- return 1;
- case DW_FORM_ref_addr:
- val->encoding = ATTR_VAL_REF_INFO;
- if (version == 2)
- val->u.uint = read_address (buf, addrsize);
- else
- val->u.uint = read_offset (buf, is_dwarf64);
- return 1;
- case DW_FORM_ref1:
- val->encoding = ATTR_VAL_REF_UNIT;
- val->u.uint = read_byte (buf);
- return 1;
- case DW_FORM_ref2:
- val->encoding = ATTR_VAL_REF_UNIT;
- val->u.uint = read_uint16 (buf);
- return 1;
- case DW_FORM_ref4:
- val->encoding = ATTR_VAL_REF_UNIT;
- val->u.uint = read_uint32 (buf);
- return 1;
- case DW_FORM_ref8:
- val->encoding = ATTR_VAL_REF_UNIT;
- val->u.uint = read_uint64 (buf);
- return 1;
- case DW_FORM_ref_udata:
- val->encoding = ATTR_VAL_REF_UNIT;
- val->u.uint = read_uleb128 (buf);
- return 1;
- case DW_FORM_indirect:
- {
- uint64_t form;
- form = read_uleb128 (buf);
- if (form == DW_FORM_implicit_const)
- {
- dwarf_buf_error (buf,
- "DW_FORM_indirect to DW_FORM_implicit_const",
- 0);
- return 0;
- }
- return read_attribute ((enum dwarf_form) form, 0, buf, is_dwarf64,
- version, addrsize, dwarf_sections, altlink,
- val);
- }
- case DW_FORM_sec_offset:
- val->encoding = ATTR_VAL_REF_SECTION;
- val->u.uint = read_offset (buf, is_dwarf64);
- return 1;
- case DW_FORM_exprloc:
- val->encoding = ATTR_VAL_EXPR;
- return advance (buf, read_uleb128 (buf));
- case DW_FORM_flag_present:
- val->encoding = ATTR_VAL_UINT;
- val->u.uint = 1;
- return 1;
- case DW_FORM_ref_sig8:
- val->encoding = ATTR_VAL_REF_TYPE;
- val->u.uint = read_uint64 (buf);
- return 1;
- case DW_FORM_strx: case DW_FORM_strx1: case DW_FORM_strx2:
- case DW_FORM_strx3: case DW_FORM_strx4:
- {
- uint64_t offset;
- switch (form)
- {
- case DW_FORM_strx:
- offset = read_uleb128 (buf);
- break;
- case DW_FORM_strx1:
- offset = read_byte (buf);
- break;
- case DW_FORM_strx2:
- offset = read_uint16 (buf);
- break;
- case DW_FORM_strx3:
- offset = read_uint24 (buf);
- break;
- case DW_FORM_strx4:
- offset = read_uint32 (buf);
- break;
- default:
- /* This case can't happen. */
- return 0;
- }
- val->encoding = ATTR_VAL_STRING_INDEX;
- val->u.uint = offset;
- return 1;
- }
- case DW_FORM_addrx: case DW_FORM_addrx1: case DW_FORM_addrx2:
- case DW_FORM_addrx3: case DW_FORM_addrx4:
- {
- uint64_t offset;
- switch (form)
- {
- case DW_FORM_addrx:
- offset = read_uleb128 (buf);
- break;
- case DW_FORM_addrx1:
- offset = read_byte (buf);
- break;
- case DW_FORM_addrx2:
- offset = read_uint16 (buf);
- break;
- case DW_FORM_addrx3:
- offset = read_uint24 (buf);
- break;
- case DW_FORM_addrx4:
- offset = read_uint32 (buf);
- break;
- default:
- /* This case can't happen. */
- return 0;
- }
- val->encoding = ATTR_VAL_ADDRESS_INDEX;
- val->u.uint = offset;
- return 1;
- }
- case DW_FORM_ref_sup4:
- val->encoding = ATTR_VAL_REF_SECTION;
- val->u.uint = read_uint32 (buf);
- return 1;
- case DW_FORM_ref_sup8:
- val->encoding = ATTR_VAL_REF_SECTION;
- val->u.uint = read_uint64 (buf);
- return 1;
- case DW_FORM_implicit_const:
- val->encoding = ATTR_VAL_UINT;
- val->u.uint = implicit_val;
- return 1;
- case DW_FORM_loclistx:
- /* We don't distinguish this from DW_FORM_sec_offset. It
- * shouldn't matter since we don't care about loclists. */
- val->encoding = ATTR_VAL_REF_SECTION;
- val->u.uint = read_uleb128 (buf);
- return 1;
- case DW_FORM_rnglistx:
- val->encoding = ATTR_VAL_RNGLISTS_INDEX;
- val->u.uint = read_uleb128 (buf);
- return 1;
- case DW_FORM_GNU_addr_index:
- val->encoding = ATTR_VAL_REF_SECTION;
- val->u.uint = read_uleb128 (buf);
- return 1;
- case DW_FORM_GNU_str_index:
- val->encoding = ATTR_VAL_REF_SECTION;
- val->u.uint = read_uleb128 (buf);
- return 1;
- case DW_FORM_GNU_ref_alt:
- val->u.uint = read_offset (buf, is_dwarf64);
- if (altlink == NULL)
- {
- val->encoding = ATTR_VAL_NONE;
- return 1;
- }
- val->encoding = ATTR_VAL_REF_ALT_INFO;
- return 1;
- case DW_FORM_strp_sup: case DW_FORM_GNU_strp_alt:
- {
- uint64_t offset;
- offset = read_offset (buf, is_dwarf64);
- if (altlink == NULL)
- {
- val->encoding = ATTR_VAL_NONE;
- return 1;
- }
- if (offset >= altlink->dwarf_sections.size[DEBUG_STR])
- {
- dwarf_buf_error (buf, "DW_FORM_strp_sup out of range", 0);
- return 0;
- }
- val->encoding = ATTR_VAL_STRING;
- val->u.string =
- (const char *) altlink->dwarf_sections.data[DEBUG_STR] + offset;
- return 1;
- }
- default:
- dwarf_buf_error (buf, "unrecognized DWARF form", -1);
- return 0;
- }
- }
- /* If we can determine the value of a string attribute, set *STRING to
- point to the string. Return 1 on success, 0 on error. If we don't
- know the value, we consider that a success, and we don't change
- *STRING. An error is only reported for some sort of out of range
- offset. */
- static int
- resolve_string (const struct dwarf_sections *dwarf_sections, int is_dwarf64,
- int is_bigendian, uint64_t str_offsets_base,
- const struct attr_val *val,
- backtrace_error_callback error_callback, void *data,
- const char **string)
- {
- switch (val->encoding)
- {
- case ATTR_VAL_STRING:
- *string = val->u.string;
- return 1;
- case ATTR_VAL_STRING_INDEX:
- {
- uint64_t offset;
- struct dwarf_buf offset_buf;
- offset = val->u.uint * (is_dwarf64 ? 8 : 4) + str_offsets_base;
- if (offset + (is_dwarf64 ? 8 : 4)
- > dwarf_sections->size[DEBUG_STR_OFFSETS])
- {
- error_callback (data, "DW_FORM_strx value out of range", 0);
- return 0;
- }
- offset_buf.name = ".debug_str_offsets";
- offset_buf.start = dwarf_sections->data[DEBUG_STR_OFFSETS];
- offset_buf.buf = dwarf_sections->data[DEBUG_STR_OFFSETS] + offset;
- offset_buf.left = dwarf_sections->size[DEBUG_STR_OFFSETS] - offset;
- offset_buf.is_bigendian = is_bigendian;
- offset_buf.error_callback = error_callback;
- offset_buf.data = data;
- offset_buf.reported_underflow = 0;
- offset = read_offset (&offset_buf, is_dwarf64);
- if (offset >= dwarf_sections->size[DEBUG_STR])
- {
- dwarf_buf_error (&offset_buf,
- "DW_FORM_strx offset out of range",
- 0);
- return 0;
- }
- *string = (const char *) dwarf_sections->data[DEBUG_STR] + offset;
- return 1;
- }
- default:
- return 1;
- }
- }
- /* Set *ADDRESS to the real address for a ATTR_VAL_ADDRESS_INDEX.
- Return 1 on success, 0 on error. */
- static int
- resolve_addr_index (const struct dwarf_sections *dwarf_sections,
- uint64_t addr_base, int addrsize, int is_bigendian,
- uint64_t addr_index,
- backtrace_error_callback error_callback, void *data,
- uintptr_t *address)
- {
- uint64_t offset;
- struct dwarf_buf addr_buf;
- offset = addr_index * addrsize + addr_base;
- if (offset + addrsize > dwarf_sections->size[DEBUG_ADDR])
- {
- error_callback (data, "DW_FORM_addrx value out of range", 0);
- return 0;
- }
- addr_buf.name = ".debug_addr";
- addr_buf.start = dwarf_sections->data[DEBUG_ADDR];
- addr_buf.buf = dwarf_sections->data[DEBUG_ADDR] + offset;
- addr_buf.left = dwarf_sections->size[DEBUG_ADDR] - offset;
- addr_buf.is_bigendian = is_bigendian;
- addr_buf.error_callback = error_callback;
- addr_buf.data = data;
- addr_buf.reported_underflow = 0;
- *address = (uintptr_t) read_address (&addr_buf, addrsize);
- return 1;
- }
- /* Compare a unit offset against a unit for bsearch. */
- static int
- units_search (const void *vkey, const void *ventry)
- {
- const size_t *key = (const size_t *) vkey;
- const struct unit *entry = *((const struct unit *const *) ventry);
- size_t offset;
- offset = *key;
- if (offset < entry->low_offset)
- return -1;
- else if (offset >= entry->high_offset)
- return 1;
- else
- return 0;
- }
- /* Find a unit in PU containing OFFSET. */
- static struct unit *
- find_unit (struct unit **pu, size_t units_count, size_t offset)
- {
- struct unit **u;
- u = bsearch (&offset, pu, units_count, sizeof (struct unit *), units_search);
- return u == NULL ? NULL : *u;
- }
- /* Compare function_addrs for qsort. When ranges are nested, make the
- smallest one sort last. */
- static int
- function_addrs_compare (const void *v1, const void *v2)
- {
- const struct function_addrs *a1 = (const struct function_addrs *) v1;
- const struct function_addrs *a2 = (const struct function_addrs *) v2;
- if (a1->low < a2->low)
- return -1;
- if (a1->low > a2->low)
- return 1;
- if (a1->high < a2->high)
- return 1;
- if (a1->high > a2->high)
- return -1;
- return strcmp (a1->function->name, a2->function->name);
- }
- /* Compare a PC against a function_addrs for bsearch. We always
- allocate an entra entry at the end of the vector, so that this
- routine can safely look at the next entry. Note that if there are
- multiple ranges containing PC, which one will be returned is
- unpredictable. We compensate for that in dwarf_fileline. */
- static int
- function_addrs_search (const void *vkey, const void *ventry)
- {
- const uintptr_t *key = (const uintptr_t *) vkey;
- const struct function_addrs *entry = (const struct function_addrs *) ventry;
- uintptr_t pc;
- pc = *key;
- if (pc < entry->low)
- return -1;
- else if (pc > (entry + 1)->low)
- return 1;
- else
- return 0;
- }
- /* Add a new compilation unit address range to a vector. This is
- called via add_ranges. Returns 1 on success, 0 on failure. */
- static int
- add_unit_addr (struct backtrace_state *state, void *rdata,
- uintptr_t lowpc, uintptr_t highpc,
- backtrace_error_callback error_callback, void *data,
- void *pvec)
- {
- struct unit *u = (struct unit *) rdata;
- struct unit_addrs_vector *vec = (struct unit_addrs_vector *) pvec;
- struct unit_addrs *p;
- /* Try to merge with the last entry. */
- if (vec->count > 0)
- {
- p = (struct unit_addrs *) vec->vec.base + (vec->count - 1);
- if ((lowpc == p->high || lowpc == p->high + 1)
- && u == p->u)
- {
- if (highpc > p->high)
- p->high = highpc;
- return 1;
- }
- }
- p = ((struct unit_addrs *)
- backtrace_vector_grow (state, sizeof (struct unit_addrs),
- error_callback, data, &vec->vec));
- if (p == NULL)
- return 0;
- p->low = lowpc;
- p->high = highpc;
- p->u = u;
- ++vec->count;
- return 1;
- }
- /* Compare unit_addrs for qsort. When ranges are nested, make the
- smallest one sort last. */
- static int
- unit_addrs_compare (const void *v1, const void *v2)
- {
- const struct unit_addrs *a1 = (const struct unit_addrs *) v1;
- const struct unit_addrs *a2 = (const struct unit_addrs *) v2;
- if (a1->low < a2->low)
- return -1;
- if (a1->low > a2->low)
- return 1;
- if (a1->high < a2->high)
- return 1;
- if (a1->high > a2->high)
- return -1;
- if (a1->u->lineoff < a2->u->lineoff)
- return -1;
- if (a1->u->lineoff > a2->u->lineoff)
- return 1;
- return 0;
- }
- /* Compare a PC against a unit_addrs for bsearch. We always allocate
- an entry entry at the end of the vector, so that this routine can
- safely look at the next entry. Note that if there are multiple
- ranges containing PC, which one will be returned is unpredictable.
- We compensate for that in dwarf_fileline. */
- static int
- unit_addrs_search (const void *vkey, const void *ventry)
- {
- const uintptr_t *key = (const uintptr_t *) vkey;
- const struct unit_addrs *entry = (const struct unit_addrs *) ventry;
- uintptr_t pc;
- pc = *key;
- if (pc < entry->low)
- return -1;
- else if (pc > (entry + 1)->low)
- return 1;
- else
- return 0;
- }
- /* Sort the line vector by PC. We want a stable sort here to maintain
- the order of lines for the same PC values. Since the sequence is
- being sorted in place, their addresses cannot be relied on to
- maintain stability. That is the purpose of the index member. */
- static int
- line_compare (const void *v1, const void *v2)
- {
- const struct line *ln1 = (const struct line *) v1;
- const struct line *ln2 = (const struct line *) v2;
- if (ln1->pc < ln2->pc)
- return -1;
- else if (ln1->pc > ln2->pc)
- return 1;
- else if (ln1->idx < ln2->idx)
- return -1;
- else if (ln1->idx > ln2->idx)
- return 1;
- else
- return 0;
- }
- /* Find a PC in a line vector. We always allocate an extra entry at
- the end of the lines vector, so that this routine can safely look
- at the next entry. Note that when there are multiple mappings for
- the same PC value, this will return the last one. */
- static int
- line_search (const void *vkey, const void *ventry)
- {
- const uintptr_t *key = (const uintptr_t *) vkey;
- const struct line *entry = (const struct line *) ventry;
- uintptr_t pc;
- pc = *key;
- if (pc < entry->pc)
- return -1;
- else if (pc >= (entry + 1)->pc)
- return 1;
- else
- return 0;
- }
- /* Sort the abbrevs by the abbrev code. This function is passed to
- both qsort and bsearch. */
- static int
- abbrev_compare (const void *v1, const void *v2)
- {
- const struct abbrev *a1 = (const struct abbrev *) v1;
- const struct abbrev *a2 = (const struct abbrev *) v2;
- if (a1->code < a2->code)
- return -1;
- else if (a1->code > a2->code)
- return 1;
- else
- {
- /* This really shouldn't happen. It means there are two
- different abbrevs with the same code, and that means we don't
- know which one lookup_abbrev should return. */
- return 0;
- }
- }
- /* Read the abbreviation table for a compilation unit. Returns 1 on
- success, 0 on failure. */
- static int
- read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
- const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size,
- int is_bigendian, backtrace_error_callback error_callback,
- void *data, struct abbrevs *abbrevs)
- {
- struct dwarf_buf abbrev_buf;
- struct dwarf_buf count_buf;
- size_t num_abbrevs;
- abbrevs->num_abbrevs = 0;
- abbrevs->abbrevs = NULL;
- if (abbrev_offset >= dwarf_abbrev_size)
- {
- error_callback (data, "abbrev offset out of range", 0);
- return 0;
- }
- abbrev_buf.name = ".debug_abbrev";
- abbrev_buf.start = dwarf_abbrev;
- abbrev_buf.buf = dwarf_abbrev + abbrev_offset;
- abbrev_buf.left = dwarf_abbrev_size - abbrev_offset;
- abbrev_buf.is_bigendian = is_bigendian;
- abbrev_buf.error_callback = error_callback;
- abbrev_buf.data = data;
- abbrev_buf.reported_underflow = 0;
- /* Count the number of abbrevs in this list. */
- count_buf = abbrev_buf;
- num_abbrevs = 0;
- while (read_uleb128 (&count_buf) != 0)
- {
- if (count_buf.reported_underflow)
- return 0;
- ++num_abbrevs;
- // Skip tag.
- read_uleb128 (&count_buf);
- // Skip has_children.
- read_byte (&count_buf);
- // Skip attributes.
- while (read_uleb128 (&count_buf) != 0)
- {
- uint64_t form;
- form = read_uleb128 (&count_buf);
- if ((enum dwarf_form) form == DW_FORM_implicit_const)
- read_sleb128 (&count_buf);
- }
- // Skip form of last attribute.
- read_uleb128 (&count_buf);
- }
- if (count_buf.reported_underflow)
- return 0;
- if (num_abbrevs == 0)
- return 1;
- abbrevs->abbrevs = ((struct abbrev *)
- backtrace_alloc (state,
- num_abbrevs * sizeof (struct abbrev),
- error_callback, data));
- if (abbrevs->abbrevs == NULL)
- return 0;
- abbrevs->num_abbrevs = num_abbrevs;
- memset (abbrevs->abbrevs, 0, num_abbrevs * sizeof (struct abbrev));
- num_abbrevs = 0;
- while (1)
- {
- uint64_t code;
- struct abbrev a;
- size_t num_attrs;
- struct attr *attrs;
- if (abbrev_buf.reported_underflow)
- goto fail;
- code = read_uleb128 (&abbrev_buf);
- if (code == 0)
- break;
- a.code = code;
- a.tag = (enum dwarf_tag) read_uleb128 (&abbrev_buf);
- a.has_children = read_byte (&abbrev_buf);
- count_buf = abbrev_buf;
- num_attrs = 0;
- while (read_uleb128 (&count_buf) != 0)
- {
- uint64_t form;
- ++num_attrs;
- form = read_uleb128 (&count_buf);
- if ((enum dwarf_form) form == DW_FORM_implicit_const)
- read_sleb128 (&count_buf);
- }
- if (num_attrs == 0)
- {
- attrs = NULL;
- read_uleb128 (&abbrev_buf);
- read_uleb128 (&abbrev_buf);
- }
- else
- {
- attrs = ((struct attr *)
- backtrace_alloc (state, num_attrs * sizeof *attrs,
- error_callback, data));
- if (attrs == NULL)
- goto fail;
- num_attrs = 0;
- while (1)
- {
- uint64_t name;
- uint64_t form;
- name = read_uleb128 (&abbrev_buf);
- form = read_uleb128 (&abbrev_buf);
- if (name == 0)
- break;
- attrs[num_attrs].name = (enum dwarf_attribute) name;
- attrs[num_attrs].form = (enum dwarf_form) form;
- if ((enum dwarf_form) form == DW_FORM_implicit_const)
- attrs[num_attrs].val = read_sleb128 (&abbrev_buf);
- else
- attrs[num_attrs].val = 0;
- ++num_attrs;
- }
- }
- a.num_attrs = num_attrs;
- a.attrs = attrs;
- abbrevs->abbrevs[num_abbrevs] = a;
- ++num_abbrevs;
- }
- backtrace_qsort (abbrevs->abbrevs, abbrevs->num_abbrevs,
- sizeof (struct abbrev), abbrev_compare);
- return 1;
- fail:
- free_abbrevs (state, abbrevs, error_callback, data);
- return 0;
- }
- /* Return the abbrev information for an abbrev code. */
- static const struct abbrev *
- lookup_abbrev (struct abbrevs *abbrevs, uint64_t code,
- backtrace_error_callback error_callback, void *data)
- {
- struct abbrev key;
- void *p;
- /* With GCC, where abbrevs are simply numbered in order, we should
- be able to just look up the entry. */
- if (code - 1 < abbrevs->num_abbrevs
- && abbrevs->abbrevs[code - 1].code == code)
- return &abbrevs->abbrevs[code - 1];
- /* Otherwise we have to search. */
- memset (&key, 0, sizeof key);
- key.code = code;
- p = bsearch (&key, abbrevs->abbrevs, abbrevs->num_abbrevs,
- sizeof (struct abbrev), abbrev_compare);
- if (p == NULL)
- {
- error_callback (data, "invalid abbreviation code", 0);
- return NULL;
- }
- return (const struct abbrev *) p;
- }
- /* This struct is used to gather address range information while
- reading attributes. We use this while building a mapping from
- address ranges to compilation units and then again while mapping
- from address ranges to function entries. Normally either
- lowpc/highpc is set or ranges is set. */
- struct pcrange {
- uintptr_t lowpc; /* The low PC value. */
- int have_lowpc; /* Whether a low PC value was found. */
- int lowpc_is_addr_index; /* Whether lowpc is in .debug_addr. */
- uintptr_t highpc; /* The high PC value. */
- int have_highpc; /* Whether a high PC value was found. */
- int highpc_is_relative; /* Whether highpc is relative to lowpc. */
- int highpc_is_addr_index; /* Whether highpc is in .debug_addr. */
- uint64_t ranges; /* Offset in ranges section. */
- int have_ranges; /* Whether ranges is valid. */
- int ranges_is_index; /* Whether ranges is DW_FORM_rnglistx. */
- };
- /* Update PCRANGE from an attribute value. */
- static void
- update_pcrange (const struct attr* attr, const struct attr_val* val,
- struct pcrange *pcrange)
- {
- switch (attr->name)
- {
- case DW_AT_low_pc:
- if (val->encoding == ATTR_VAL_ADDRESS)
- {
- pcrange->lowpc = (uintptr_t) val->u.uint;
- pcrange->have_lowpc = 1;
- }
- else if (val->encoding == ATTR_VAL_ADDRESS_INDEX)
- {
- pcrange->lowpc = (uintptr_t) val->u.uint;
- pcrange->have_lowpc = 1;
- pcrange->lowpc_is_addr_index = 1;
- }
- break;
- case DW_AT_high_pc:
- if (val->encoding == ATTR_VAL_ADDRESS)
- {
- pcrange->highpc = (uintptr_t) val->u.uint;
- pcrange->have_highpc = 1;
- }
- else if (val->encoding == ATTR_VAL_UINT)
- {
- pcrange->highpc = (uintptr_t) val->u.uint;
- pcrange->have_highpc = 1;
- pcrange->highpc_is_relative = 1;
- }
- else if (val->encoding == ATTR_VAL_ADDRESS_INDEX)
- {
- pcrange->highpc = (uintptr_t) val->u.uint;
- pcrange->have_highpc = 1;
- pcrange->highpc_is_addr_index = 1;
- }
- break;
- case DW_AT_ranges:
- if (val->encoding == ATTR_VAL_UINT
- || val->encoding == ATTR_VAL_REF_SECTION)
- {
- pcrange->ranges = val->u.uint;
- pcrange->have_ranges = 1;
- }
- else if (val->encoding == ATTR_VAL_RNGLISTS_INDEX)
- {
- pcrange->ranges = val->u.uint;
- pcrange->have_ranges = 1;
- pcrange->ranges_is_index = 1;
- }
- break;
- default:
- break;
- }
- }
- /* Call ADD_RANGE for a low/high PC pair. Returns 1 on success, 0 on
- error. */
- static int
- add_low_high_range (struct backtrace_state *state,
- const struct dwarf_sections *dwarf_sections,
- struct libbacktrace_base_address base_address,
- int is_bigendian, struct unit *u,
- const struct pcrange *pcrange,
- int (*add_range) (struct backtrace_state *state,
- void *rdata, uintptr_t lowpc,
- uintptr_t highpc,
- backtrace_error_callback error_callback,
- void *data, void *vec),
- void *rdata,
- backtrace_error_callback error_callback, void *data,
- void *vec)
- {
- uintptr_t lowpc;
- uintptr_t highpc;
- lowpc = pcrange->lowpc;
- if (pcrange->lowpc_is_addr_index)
- {
- if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize,
- is_bigendian, lowpc, error_callback, data,
- &lowpc))
- return 0;
- }
- highpc = pcrange->highpc;
- if (pcrange->highpc_is_addr_index)
- {
- if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize,
- is_bigendian, highpc, error_callback, data,
- &highpc))
- return 0;
- }
- if (pcrange->highpc_is_relative)
- highpc += lowpc;
- /* Add in the base address of the module when recording PC values,
- so that we can look up the PC directly. */
- lowpc = libbacktrace_add_base (lowpc, base_address);
- highpc = libbacktrace_add_base (highpc, base_address);
- return add_range (state, rdata, lowpc, highpc, error_callback, data, vec);
- }
- /* Call ADD_RANGE for each range read from .debug_ranges, as used in
- DWARF versions 2 through 4. */
- static int
- add_ranges_from_ranges (
- struct backtrace_state *state,
- const struct dwarf_sections *dwarf_sections,
- struct libbacktrace_base_address base_address, int is_bigendian,
- struct unit *u, uintptr_t base,
- const struct pcrange *pcrange,
- int (*add_range) (struct backtrace_state *state, void *rdata,
- uintptr_t lowpc, uintptr_t highpc,
- backtrace_error_callback error_callback, void *data,
- void *vec),
- void *rdata,
- backtrace_error_callback error_callback, void *data,
- void *vec)
- {
- struct dwarf_buf ranges_buf;
- if (pcrange->ranges >= dwarf_sections->size[DEBUG_RANGES])
- {
- error_callback (data, "ranges offset out of range", 0);
- return 0;
- }
- ranges_buf.name = ".debug_ranges";
- ranges_buf.start = dwarf_sections->data[DEBUG_RANGES];
- ranges_buf.buf = dwarf_sections->data[DEBUG_RANGES] + pcrange->ranges;
- ranges_buf.left = dwarf_sections->size[DEBUG_RANGES] - pcrange->ranges;
- ranges_buf.is_bigendian = is_bigendian;
- ranges_buf.error_callback = error_callback;
- ranges_buf.data = data;
- ranges_buf.reported_underflow = 0;
- while (1)
- {
- uint64_t low;
- uint64_t high;
- if (ranges_buf.reported_underflow)
- return 0;
- low = read_address (&ranges_buf, u->addrsize);
- high = read_address (&ranges_buf, u->addrsize);
- if (low == 0 && high == 0)
- break;
- if (is_highest_address (low, u->addrsize))
- base = (uintptr_t) high;
- else
- {
- uintptr_t rl, rh;
- rl = libbacktrace_add_base ((uintptr_t) low + base, base_address);
- rh = libbacktrace_add_base ((uintptr_t) high + base, base_address);
- if (!add_range (state, rdata, rl, rh, error_callback, data, vec))
- return 0;
- }
- }
- if (ranges_buf.reported_underflow)
- return 0;
- return 1;
- }
- /* Call ADD_RANGE for each range read from .debug_rnglists, as used in
- DWARF version 5. */
- static int
- add_ranges_from_rnglists (
- struct backtrace_state *state,
- const struct dwarf_sections *dwarf_sections,
- struct libbacktrace_base_address base_address, int is_bigendian,
- struct unit *u, uintptr_t base,
- const struct pcrange *pcrange,
- int (*add_range) (struct backtrace_state *state, void *rdata,
- uintptr_t lowpc, uintptr_t highpc,
- backtrace_error_callback error_callback, void *data,
- void *vec),
- void *rdata,
- backtrace_error_callback error_callback, void *data,
- void *vec)
- {
- uint64_t offset;
- struct dwarf_buf rnglists_buf;
- if (!pcrange->ranges_is_index)
- offset = pcrange->ranges;
- else
- offset = u->rnglists_base + pcrange->ranges * (u->is_dwarf64 ? 8 : 4);
- if (offset >= dwarf_sections->size[DEBUG_RNGLISTS])
- {
- error_callback (data, "rnglists offset out of range", 0);
- return 0;
- }
- rnglists_buf.name = ".debug_rnglists";
- rnglists_buf.start = dwarf_sections->data[DEBUG_RNGLISTS];
- rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset;
- rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset;
- rnglists_buf.is_bigendian = is_bigendian;
- rnglists_buf.error_callback = error_callback;
- rnglists_buf.data = data;
- rnglists_buf.reported_underflow = 0;
- if (pcrange->ranges_is_index)
- {
- offset = read_offset (&rnglists_buf, u->is_dwarf64);
- offset += u->rnglists_base;
- if (offset >= dwarf_sections->size[DEBUG_RNGLISTS])
- {
- error_callback (data, "rnglists index offset out of range", 0);
- return 0;
- }
- rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset;
- rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset;
- }
- while (1)
- {
- unsigned char rle;
- rle = read_byte (&rnglists_buf);
- if (rle == DW_RLE_end_of_list)
- break;
- switch (rle)
- {
- case DW_RLE_base_addressx:
- {
- uint64_t index;
- index = read_uleb128 (&rnglists_buf);
- if (!resolve_addr_index (dwarf_sections, u->addr_base,
- u->addrsize, is_bigendian, index,
- error_callback, data, &base))
- return 0;
- }
- break;
- case DW_RLE_startx_endx:
- {
- uint64_t index;
- uintptr_t low;
- uintptr_t high;
- index = read_uleb128 (&rnglists_buf);
- if (!resolve_addr_index (dwarf_sections, u->addr_base,
- u->addrsize, is_bigendian, index,
- error_callback, data, &low))
- return 0;
- index = read_uleb128 (&rnglists_buf);
- if (!resolve_addr_index (dwarf_sections, u->addr_base,
- u->addrsize, is_bigendian, index,
- error_callback, data, &high))
- return 0;
- if (!add_range (state, rdata,
- libbacktrace_add_base (low, base_address),
- libbacktrace_add_base (high, base_address),
- error_callback, data, vec))
- return 0;
- }
- break;
- case DW_RLE_startx_length:
- {
- uint64_t index;
- uintptr_t low;
- uintptr_t length;
- index = read_uleb128 (&rnglists_buf);
- if (!resolve_addr_index (dwarf_sections, u->addr_base,
- u->addrsize, is_bigendian, index,
- error_callback, data, &low))
- return 0;
- length = read_uleb128 (&rnglists_buf);
- low = libbacktrace_add_base (low, base_address);
- if (!add_range (state, rdata, low, low + length,
- error_callback, data, vec))
- return 0;
- }
- break;
- case DW_RLE_offset_pair:
- {
- uint64_t low;
- uint64_t high;
- low = read_uleb128 (&rnglists_buf);
- high = read_uleb128 (&rnglists_buf);
- if (!add_range (state, rdata,
- libbacktrace_add_base (low + base, base_address),
- libbacktrace_add_base (high + base, base_address),
- error_callback, data, vec))
- return 0;
- }
- break;
- case DW_RLE_base_address:
- base = (uintptr_t) read_address (&rnglists_buf, u->addrsize);
- break;
- case DW_RLE_start_end:
- {
- uintptr_t low;
- uintptr_t high;
- low = (uintptr_t) read_address (&rnglists_buf, u->addrsize);
- high = (uintptr_t) read_address (&rnglists_buf, u->addrsize);
- if (!add_range (state, rdata,
- libbacktrace_add_base (low, base_address),
- libbacktrace_add_base (high, base_address),
- error_callback, data, vec))
- return 0;
- }
- break;
- case DW_RLE_start_length:
- {
- uintptr_t low;
- uintptr_t length;
- low = (uintptr_t) read_address (&rnglists_buf, u->addrsize);
- length = (uintptr_t) read_uleb128 (&rnglists_buf);
- low = libbacktrace_add_base (low, base_address);
- if (!add_range (state, rdata, low, low + length,
- error_callback, data, vec))
- return 0;
- }
- break;
- default:
- dwarf_buf_error (&rnglists_buf, "unrecognized DW_RLE value", -1);
- return 0;
- }
- }
- if (rnglists_buf.reported_underflow)
- return 0;
- return 1;
- }
- /* Call ADD_RANGE for each lowpc/highpc pair in PCRANGE. RDATA is
- passed to ADD_RANGE, and is either a struct unit * or a struct
- function *. VEC is the vector we are adding ranges to, and is
- either a struct unit_addrs_vector * or a struct function_vector *.
- Returns 1 on success, 0 on error. */
- static int
- add_ranges (struct backtrace_state *state,
- const struct dwarf_sections *dwarf_sections,
- struct libbacktrace_base_address base_address, int is_bigendian,
- struct unit *u, uintptr_t base, const struct pcrange *pcrange,
- int (*add_range) (struct backtrace_state *state, void *rdata,
- uintptr_t lowpc, uintptr_t highpc,
- backtrace_error_callback error_callback,
- void *data, void *vec),
- void *rdata,
- backtrace_error_callback error_callback, void *data,
- void *vec)
- {
- if (pcrange->have_lowpc && pcrange->have_highpc)
- return add_low_high_range (state, dwarf_sections, base_address,
- is_bigendian, u, pcrange, add_range, rdata,
- error_callback, data, vec);
- if (!pcrange->have_ranges)
- {
- /* Did not find any address ranges to add. */
- return 1;
- }
- if (u->version < 5)
- return add_ranges_from_ranges (state, dwarf_sections, base_address,
- is_bigendian, u, base, pcrange, add_range,
- rdata, error_callback, data, vec);
- else
- return add_ranges_from_rnglists (state, dwarf_sections, base_address,
- is_bigendian, u, base, pcrange, add_range,
- rdata, error_callback, data, vec);
- }
- /* Find the address range covered by a compilation unit, reading from
- UNIT_BUF and adding values to U. Returns 1 if all data could be
- read, 0 if there is some error. */
- static int
- find_address_ranges (struct backtrace_state *state,
- struct libbacktrace_base_address base_address,
- struct dwarf_buf *unit_buf,
- const struct dwarf_sections *dwarf_sections,
- int is_bigendian, struct dwarf_data *altlink,
- backtrace_error_callback error_callback, void *data,
- struct unit *u, struct unit_addrs_vector *addrs,
- enum dwarf_tag *unit_tag)
- {
- while (unit_buf->left > 0)
- {
- uint64_t code;
- const struct abbrev *abbrev;
- struct pcrange pcrange;
- struct attr_val name_val;
- int have_name_val;
- struct attr_val comp_dir_val;
- int have_comp_dir_val;
- size_t i;
- code = read_uleb128 (unit_buf);
- if (code == 0)
- return 1;
- abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);
- if (abbrev == NULL)
- return 0;
- if (unit_tag != NULL)
- *unit_tag = abbrev->tag;
- memset (&pcrange, 0, sizeof pcrange);
- memset (&name_val, 0, sizeof name_val);
- have_name_val = 0;
- memset (&comp_dir_val, 0, sizeof comp_dir_val);
- have_comp_dir_val = 0;
- for (i = 0; i < abbrev->num_attrs; ++i)
- {
- struct attr_val val;
- if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
- unit_buf, u->is_dwarf64, u->version,
- u->addrsize, dwarf_sections, altlink, &val))
- return 0;
- switch (abbrev->attrs[i].name)
- {
- case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges:
- update_pcrange (&abbrev->attrs[i], &val, &pcrange);
- break;
- case DW_AT_stmt_list:
- if ((abbrev->tag == DW_TAG_compile_unit
- || abbrev->tag == DW_TAG_skeleton_unit)
- && (val.encoding == ATTR_VAL_UINT
- || val.encoding == ATTR_VAL_REF_SECTION))
- u->lineoff = val.u.uint;
- break;
- case DW_AT_name:
- if (abbrev->tag == DW_TAG_compile_unit
- || abbrev->tag == DW_TAG_skeleton_unit)
- {
- name_val = val;
- have_name_val = 1;
- }
- break;
- case DW_AT_comp_dir:
- if (abbrev->tag == DW_TAG_compile_unit
- || abbrev->tag == DW_TAG_skeleton_unit)
- {
- comp_dir_val = val;
- have_comp_dir_val = 1;
- }
- break;
- case DW_AT_str_offsets_base:
- if ((abbrev->tag == DW_TAG_compile_unit
- || abbrev->tag == DW_TAG_skeleton_unit)
- && val.encoding == ATTR_VAL_REF_SECTION)
- u->str_offsets_base = val.u.uint;
- break;
- case DW_AT_addr_base:
- if ((abbrev->tag == DW_TAG_compile_unit
- || abbrev->tag == DW_TAG_skeleton_unit)
- && val.encoding == ATTR_VAL_REF_SECTION)
- u->addr_base = val.u.uint;
- break;
- case DW_AT_rnglists_base:
- if ((abbrev->tag == DW_TAG_compile_unit
- || abbrev->tag == DW_TAG_skeleton_unit)
- && val.encoding == ATTR_VAL_REF_SECTION)
- u->rnglists_base = val.u.uint;
- break;
- default:
- break;
- }
- }
- // Resolve strings after we're sure that we have seen
- // DW_AT_str_offsets_base.
- if (have_name_val)
- {
- if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian,
- u->str_offsets_base, &name_val,
- error_callback, data, &u->filename))
- return 0;
- }
- if (have_comp_dir_val)
- {
- if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian,
- u->str_offsets_base, &comp_dir_val,
- error_callback, data, &u->comp_dir))
- return 0;
- }
- if (abbrev->tag == DW_TAG_compile_unit
- || abbrev->tag == DW_TAG_subprogram
- || abbrev->tag == DW_TAG_skeleton_unit)
- {
- if (!add_ranges (state, dwarf_sections, base_address,
- is_bigendian, u, pcrange.lowpc, &pcrange,
- add_unit_addr, (void *) u, error_callback, data,
- (void *) addrs))
- return 0;
- /* If we found the PC range in the DW_TAG_compile_unit or
- DW_TAG_skeleton_unit, we can stop now. */
- if ((abbrev->tag == DW_TAG_compile_unit
- || abbrev->tag == DW_TAG_skeleton_unit)
- && (pcrange.have_ranges
- || (pcrange.have_lowpc && pcrange.have_highpc)))
- return 1;
- }
- if (abbrev->has_children)
- {
- if (!find_address_ranges (state, base_address, unit_buf,
- dwarf_sections, is_bigendian, altlink,
- error_callback, data, u, addrs, NULL))
- return 0;
- }
- }
- return 1;
- }
- /* Build a mapping from address ranges to the compilation units where
- the line number information for that range can be found. Returns 1
- on success, 0 on failure. */
- static int
- build_address_map (struct backtrace_state *state,
- struct libbacktrace_base_address base_address,
- const struct dwarf_sections *dwarf_sections,
- int is_bigendian, struct dwarf_data *altlink,
- backtrace_error_callback error_callback, void *data,
- struct unit_addrs_vector *addrs,
- struct unit_vector *unit_vec)
- {
- struct dwarf_buf info;
- struct backtrace_vector units;
- size_t units_count;
- size_t i;
- struct unit **pu;
- size_t unit_offset = 0;
- struct unit_addrs *pa;
- memset (&addrs->vec, 0, sizeof addrs->vec);
- memset (&unit_vec->vec, 0, sizeof unit_vec->vec);
- addrs->count = 0;
- unit_vec->count = 0;
- /* Read through the .debug_info section. FIXME: Should we use the
- .debug_aranges section? gdb and addr2line don't use it, but I'm
- not sure why. */
- info.name = ".debug_info";
- info.start = dwarf_sections->data[DEBUG_INFO];
- info.buf = info.start;
- info.left = dwarf_sections->size[DEBUG_INFO];
- info.is_bigendian = is_bigendian;
- info.error_callback = error_callback;
- info.data = data;
- info.reported_underflow = 0;
- memset (&units, 0, sizeof units);
- units_count = 0;
- while (info.left > 0)
- {
- const unsigned char *unit_data_start;
- uint64_t len;
- int is_dwarf64;
- struct dwarf_buf unit_buf;
- int version;
- int unit_type;
- uint64_t abbrev_offset;
- int addrsize;
- struct unit *u;
- enum dwarf_tag unit_tag;
- if (info.reported_underflow)
- goto fail;
- unit_data_start = info.buf;
- len = read_initial_length (&info, &is_dwarf64);
- unit_buf = info;
- unit_buf.left = len;
- if (!advance (&info, len))
- goto fail;
- version = read_uint16 (&unit_buf);
- if (version < 2 || version > 5)
- {
- dwarf_buf_error (&unit_buf, "unrecognized DWARF version", -1);
- goto fail;
- }
- if (version < 5)
- unit_type = 0;
- else
- {
- unit_type = read_byte (&unit_buf);
- if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
- {
- /* This unit doesn't have anything we need. */
- continue;
- }
- }
- pu = ((struct unit **)
- backtrace_vector_grow (state, sizeof (struct unit *),
- error_callback, data, &units));
- if (pu == NULL)
- goto fail;
- u = ((struct unit *)
- backtrace_alloc (state, sizeof *u, error_callback, data));
- if (u == NULL)
- goto fail;
- *pu = u;
- ++units_count;
- if (version < 5)
- addrsize = 0; /* Set below. */
- else
- addrsize = read_byte (&unit_buf);
- memset (&u->abbrevs, 0, sizeof u->abbrevs);
- abbrev_offset = read_offset (&unit_buf, is_dwarf64);
- if (!read_abbrevs (state, abbrev_offset,
- dwarf_sections->data[DEBUG_ABBREV],
- dwarf_sections->size[DEBUG_ABBREV],
- is_bigendian, error_callback, data, &u->abbrevs))
- goto fail;
- if (version < 5)
- addrsize = read_byte (&unit_buf);
- switch (unit_type)
- {
- case 0:
- break;
- case DW_UT_compile: case DW_UT_partial:
- break;
- case DW_UT_skeleton: case DW_UT_split_compile:
- read_uint64 (&unit_buf); /* dwo_id */
- break;
- default:
- break;
- }
- u->low_offset = unit_offset;
- unit_offset += len + (is_dwarf64 ? 12 : 4);
- u->high_offset = unit_offset;
- u->unit_data = unit_buf.buf;
- u->unit_data_len = unit_buf.left;
- u->unit_data_offset = unit_buf.buf - unit_data_start;
- u->version = version;
- u->is_dwarf64 = is_dwarf64;
- u->addrsize = addrsize;
- u->filename = NULL;
- u->comp_dir = NULL;
- u->abs_filename = NULL;
- u->lineoff = 0;
- u->str_offsets_base = 0;
- u->addr_base = 0;
- u->rnglists_base = 0;
- /* The actual line number mappings will be read as needed. */
- u->lines = NULL;
- u->lines_count = 0;
- u->function_addrs = NULL;
- u->function_addrs_count = 0;
- if (!find_address_ranges (state, base_address, &unit_buf, dwarf_sections,
- is_bigendian, altlink, error_callback, data,
- u, addrs, &unit_tag))
- goto fail;
- if (unit_buf.reported_underflow)
- goto fail;
- }
- if (info.reported_underflow)
- goto fail;
- /* Add a trailing addrs entry, but don't include it in addrs->count. */
- pa = ((struct unit_addrs *)
- backtrace_vector_grow (state, sizeof (struct unit_addrs),
- error_callback, data, &addrs->vec));
- if (pa == NULL)
- goto fail;
- pa->low = 0;
- --pa->low;
- pa->high = pa->low;
- pa->u = NULL;
- unit_vec->vec = units;
- unit_vec->count = units_count;
- return 1;
- fail:
- if (units_count > 0)
- {
- pu = (struct unit **) units.base;
- for (i = 0; i < units_count; i++)
- {
- free_abbrevs (state, &pu[i]->abbrevs, error_callback, data);
- backtrace_free (state, pu[i], sizeof **pu, error_callback, data);
- }
- backtrace_vector_free (state, &units, error_callback, data);
- }
- if (addrs->count > 0)
- {
- backtrace_vector_free (state, &addrs->vec, error_callback, data);
- addrs->count = 0;
- }
- return 0;
- }
- /* Add a new mapping to the vector of line mappings that we are
- building. Returns 1 on success, 0 on failure. */
- static int
- add_line (struct backtrace_state *state, struct dwarf_data *ddata,
- uintptr_t pc, const char *filename, int lineno,
- backtrace_error_callback error_callback, void *data,
- struct line_vector *vec)
- {
- struct line *ln;
- /* If we are adding the same mapping, ignore it. This can happen
- when using discriminators. */
- if (vec->count > 0)
- {
- ln = (struct line *) vec->vec.base + (vec->count - 1);
- if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno)
- return 1;
- }
- ln = ((struct line *)
- backtrace_vector_grow (state, sizeof (struct line), error_callback,
- data, &vec->vec));
- if (ln == NULL)
- return 0;
- /* Add in the base address here, so that we can look up the PC
- directly. */
- ln->pc = libbacktrace_add_base (pc, ddata->base_address);
- ln->filename = filename;
- ln->lineno = lineno;
- ln->idx = vec->count;
- ++vec->count;
- return 1;
- }
- /* Free the line header information. */
- static void
- free_line_header (struct backtrace_state *state, struct line_header *hdr,
- backtrace_error_callback error_callback, void *data)
- {
- if (hdr->dirs_count != 0)
- backtrace_free (state, hdr->dirs, hdr->dirs_count * sizeof (const char *),
- error_callback, data);
- backtrace_free (state, hdr->filenames,
- hdr->filenames_count * sizeof (char *),
- error_callback, data);
- }
- /* Read the directories and file names for a line header for version
- 2, setting fields in HDR. Return 1 on success, 0 on failure. */
- static int
- read_v2_paths (struct backtrace_state *state, struct unit *u,
- struct dwarf_buf *hdr_buf, struct line_header *hdr)
- {
- const unsigned char *p;
- const unsigned char *pend;
- size_t i;
- /* Count the number of directory entries. */
- hdr->dirs_count = 0;
- p = hdr_buf->buf;
- pend = p + hdr_buf->left;
- while (p < pend && *p != '\0')
- {
- p += strnlen((const char *) p, pend - p) + 1;
- ++hdr->dirs_count;
- }
- /* The index of the first entry in the list of directories is 1. Index 0 is
- used for the current directory of the compilation. To simplify index
- handling, we set entry 0 to the compilation unit directory. */
- ++hdr->dirs_count;
- hdr->dirs = ((const char **)
- backtrace_alloc (state,
- hdr->dirs_count * sizeof (const char *),
- hdr_buf->error_callback,
- hdr_buf->data));
- if (hdr->dirs == NULL)
- return 0;
- hdr->dirs[0] = u->comp_dir;
- i = 1;
- while (*hdr_buf->buf != '\0')
- {
- if (hdr_buf->reported_underflow)
- return 0;
- hdr->dirs[i] = read_string (hdr_buf);
- if (hdr->dirs[i] == NULL)
- return 0;
- ++i;
- }
- if (!advance (hdr_buf, 1))
- return 0;
- /* Count the number of file entries. */
- hdr->filenames_count = 0;
- p = hdr_buf->buf;
- pend = p + hdr_buf->left;
- while (p < pend && *p != '\0')
- {
- p += strnlen ((const char *) p, pend - p) + 1;
- p += leb128_len (p);
- p += leb128_len (p);
- p += leb128_len (p);
- ++hdr->filenames_count;
- }
- /* The index of the first entry in the list of file names is 1. Index 0 is
- used for the DW_AT_name of the compilation unit. To simplify index
- handling, we set entry 0 to the compilation unit file name. */
- ++hdr->filenames_count;
- hdr->filenames = ((const char **)
- backtrace_alloc (state,
- hdr->filenames_count * sizeof (char *),
- hdr_buf->error_callback,
- hdr_buf->data));
- if (hdr->filenames == NULL)
- return 0;
- hdr->filenames[0] = u->filename;
- i = 1;
- while (*hdr_buf->buf != '\0')
- {
- const char *filename;
- uint64_t dir_index;
- if (hdr_buf->reported_underflow)
- return 0;
- filename = read_string (hdr_buf);
- if (filename == NULL)
- return 0;
- dir_index = read_uleb128 (hdr_buf);
- if (IS_ABSOLUTE_PATH (filename)
- || (dir_index < hdr->dirs_count && hdr->dirs[dir_index] == NULL))
- hdr->filenames[i] = filename;
- else
- {
- const char *dir;
- size_t dir_len;
- size_t filename_len;
- char *s;
- if (dir_index < hdr->dirs_count)
- dir = hdr->dirs[dir_index];
- else
- {
- dwarf_buf_error (hdr_buf,
- ("invalid directory index in "
- "line number program header"),
- 0);
- return 0;
- }
- dir_len = strlen (dir);
- filename_len = strlen (filename);
- s = ((char *) backtrace_alloc (state, dir_len + filename_len + 2,
- hdr_buf->error_callback,
- hdr_buf->data));
- if (s == NULL)
- return 0;
- memcpy (s, dir, dir_len);
- /* FIXME: If we are on a DOS-based file system, and the
- directory or the file name use backslashes, then we
- should use a backslash here. */
- s[dir_len] = '/';
- memcpy (s + dir_len + 1, filename, filename_len + 1);
- hdr->filenames[i] = s;
- }
- /* Ignore the modification time and size. */
- read_uleb128 (hdr_buf);
- read_uleb128 (hdr_buf);
- ++i;
- }
- return 1;
- }
- /* Read a single version 5 LNCT entry for a directory or file name in a
- line header. Sets *STRING to the resulting name, ignoring other
- data. Return 1 on success, 0 on failure. */
- static int
- read_lnct (struct backtrace_state *state, struct dwarf_data *ddata,
- struct unit *u, struct dwarf_buf *hdr_buf,
- const struct line_header *hdr, size_t formats_count,
- const struct line_header_format *formats, const char **string)
- {
- size_t i;
- const char *dir;
- const char *path;
- dir = NULL;
- path = NULL;
- for (i = 0; i < formats_count; i++)
- {
- struct attr_val val;
- if (!read_attribute (formats[i].form, 0, hdr_buf, u->is_dwarf64,
- u->version, hdr->addrsize, &ddata->dwarf_sections,
- ddata->altlink, &val))
- return 0;
- switch (formats[i].lnct)
- {
- case DW_LNCT_path:
- if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
- ddata->is_bigendian, u->str_offsets_base,
- &val, hdr_buf->error_callback, hdr_buf->data,
- &path))
- return 0;
- break;
- case DW_LNCT_directory_index:
- if (val.encoding == ATTR_VAL_UINT)
- {
- if (val.u.uint >= hdr->dirs_count)
- {
- dwarf_buf_error (hdr_buf,
- ("invalid directory index in "
- "line number program header"),
- 0);
- return 0;
- }
- dir = hdr->dirs[val.u.uint];
- }
- break;
- default:
- /* We don't care about timestamps or sizes or hashes. */
- break;
- }
- }
- if (path == NULL)
- {
- dwarf_buf_error (hdr_buf,
- "missing file name in line number program header",
- 0);
- return 0;
- }
- if (dir == NULL)
- *string = path;
- else
- {
- size_t dir_len;
- size_t path_len;
- char *s;
- dir_len = strlen (dir);
- path_len = strlen (path);
- s = (char *) backtrace_alloc (state, dir_len + path_len + 2,
- hdr_buf->error_callback, hdr_buf->data);
- if (s == NULL)
- return 0;
- memcpy (s, dir, dir_len);
- /* FIXME: If we are on a DOS-based file system, and the
- directory or the path name use backslashes, then we should
- use a backslash here. */
- s[dir_len] = '/';
- memcpy (s + dir_len + 1, path, path_len + 1);
- *string = s;
- }
- return 1;
- }
- /* Read a set of DWARF 5 line header format entries, setting *PCOUNT
- and *PPATHS. Return 1 on success, 0 on failure. */
- static int
- read_line_header_format_entries (struct backtrace_state *state,
- struct dwarf_data *ddata,
- struct unit *u,
- struct dwarf_buf *hdr_buf,
- struct line_header *hdr,
- size_t *pcount,
- const char ***ppaths)
- {
- size_t formats_count;
- struct line_header_format *formats;
- size_t paths_count;
- const char **paths;
- size_t i;
- int ret;
- formats_count = read_byte (hdr_buf);
- if (formats_count == 0)
- formats = NULL;
- else
- {
- formats = ((struct line_header_format *)
- backtrace_alloc (state,
- (formats_count
- * sizeof (struct line_header_format)),
- hdr_buf->error_callback,
- hdr_buf->data));
- if (formats == NULL)
- return 0;
- for (i = 0; i < formats_count; i++)
- {
- formats[i].lnct = (int) read_uleb128(hdr_buf);
- formats[i].form = (enum dwarf_form) read_uleb128 (hdr_buf);
- }
- }
- paths_count = read_uleb128 (hdr_buf);
- if (paths_count == 0)
- {
- *pcount = 0;
- *ppaths = NULL;
- ret = 1;
- goto exit;
- }
- paths = ((const char **)
- backtrace_alloc (state, paths_count * sizeof (const char *),
- hdr_buf->error_callback, hdr_buf->data));
- if (paths == NULL)
- {
- ret = 0;
- goto exit;
- }
- for (i = 0; i < paths_count; i++)
- {
- if (!read_lnct (state, ddata, u, hdr_buf, hdr, formats_count,
- formats, &paths[i]))
- {
- backtrace_free (state, paths,
- paths_count * sizeof (const char *),
- hdr_buf->error_callback, hdr_buf->data);
- ret = 0;
- goto exit;
- }
- }
- *pcount = paths_count;
- *ppaths = paths;
- ret = 1;
- exit:
- if (formats != NULL)
- backtrace_free (state, formats,
- formats_count * sizeof (struct line_header_format),
- hdr_buf->error_callback, hdr_buf->data);
- return ret;
- }
- /* Read the line header. Return 1 on success, 0 on failure. */
- static int
- read_line_header (struct backtrace_state *state, struct dwarf_data *ddata,
- struct unit *u, int is_dwarf64, struct dwarf_buf *line_buf,
- struct line_header *hdr)
- {
- uint64_t hdrlen;
- struct dwarf_buf hdr_buf;
- hdr->version = read_uint16 (line_buf);
- if (hdr->version < 2 || hdr->version > 5)
- {
- dwarf_buf_error (line_buf, "unsupported line number version", -1);
- return 0;
- }
- if (hdr->version < 5)
- hdr->addrsize = u->addrsize;
- else
- {
- hdr->addrsize = read_byte (line_buf);
- /* We could support a non-zero segment_selector_size but I doubt
- we'll ever see it. */
- if (read_byte (line_buf) != 0)
- {
- dwarf_buf_error (line_buf,
- "non-zero segment_selector_size not supported",
- -1);
- return 0;
- }
- }
- hdrlen = read_offset (line_buf, is_dwarf64);
- hdr_buf = *line_buf;
- hdr_buf.left = hdrlen;
- if (!advance (line_buf, hdrlen))
- return 0;
- hdr->min_insn_len = read_byte (&hdr_buf);
- if (hdr->version < 4)
- hdr->max_ops_per_insn = 1;
- else
- hdr->max_ops_per_insn = read_byte (&hdr_buf);
- /* We don't care about default_is_stmt. */
- read_byte (&hdr_buf);
- hdr->line_base = read_sbyte (&hdr_buf);
- hdr->line_range = read_byte (&hdr_buf);
- hdr->opcode_base = read_byte (&hdr_buf);
- hdr->opcode_lengths = hdr_buf.buf;
- if (!advance (&hdr_buf, hdr->opcode_base - 1))
- return 0;
- if (hdr->version < 5)
- {
- if (!read_v2_paths (state, u, &hdr_buf, hdr))
- return 0;
- }
- else
- {
- if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr,
- &hdr->dirs_count,
- &hdr->dirs))
- return 0;
- if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr,
- &hdr->filenames_count,
- &hdr->filenames))
- return 0;
- }
- if (hdr_buf.reported_underflow)
- return 0;
- return 1;
- }
- /* Read the line program, adding line mappings to VEC. Return 1 on
- success, 0 on failure. */
- static int
- read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
- const struct line_header *hdr, struct dwarf_buf *line_buf,
- struct line_vector *vec)
- {
- uint64_t address;
- unsigned int op_index;
- const char *reset_filename;
- const char *filename;
- int lineno;
- address = 0;
- op_index = 0;
- if (hdr->filenames_count > 1)
- reset_filename = hdr->filenames[1];
- else
- reset_filename = "";
- filename = reset_filename;
- lineno = 1;
- while (line_buf->left > 0)
- {
- unsigned int op;
- op = read_byte (line_buf);
- if (op >= hdr->opcode_base)
- {
- unsigned int advance;
- /* Special opcode. */
- op -= hdr->opcode_base;
- advance = op / hdr->line_range;
- address += (hdr->min_insn_len * (op_index + advance)
- / hdr->max_ops_per_insn);
- op_index = (op_index + advance) % hdr->max_ops_per_insn;
- lineno += hdr->line_base + (int) (op % hdr->line_range);
- add_line (state, ddata, address, filename, lineno,
- line_buf->error_callback, line_buf->data, vec);
- }
- else if (op == DW_LNS_extended_op)
- {
- uint64_t len;
- len = read_uleb128 (line_buf);
- op = read_byte (line_buf);
- switch (op)
- {
- case DW_LNE_end_sequence:
- /* FIXME: Should we mark the high PC here? It seems
- that we already have that information from the
- compilation unit. */
- address = 0;
- op_index = 0;
- filename = reset_filename;
- lineno = 1;
- break;
- case DW_LNE_set_address:
- address = read_address (line_buf, hdr->addrsize);
- break;
- case DW_LNE_define_file:
- {
- const char *f;
- unsigned int dir_index;
- f = read_string (line_buf);
- if (f == NULL)
- return 0;
- dir_index = read_uleb128 (line_buf);
- /* Ignore that time and length. */
- read_uleb128 (line_buf);
- read_uleb128 (line_buf);
- if (IS_ABSOLUTE_PATH (f))
- filename = f;
- else
- {
- const char *dir;
- size_t dir_len;
- size_t f_len;
- char *p;
- if (dir_index < hdr->dirs_count)
- dir = hdr->dirs[dir_index];
- else
- {
- dwarf_buf_error (line_buf,
- ("invalid directory index "
- "in line number program"),
- 0);
- return 0;
- }
- dir_len = strlen (dir);
- f_len = strlen (f);
- p = ((char *)
- backtrace_alloc (state, dir_len + f_len + 2,
- line_buf->error_callback,
- line_buf->data));
- if (p == NULL)
- return 0;
- memcpy (p, dir, dir_len);
- /* FIXME: If we are on a DOS-based file system,
- and the directory or the file name use
- backslashes, then we should use a backslash
- here. */
- p[dir_len] = '/';
- memcpy (p + dir_len + 1, f, f_len + 1);
- filename = p;
- }
- }
- break;
- case DW_LNE_set_discriminator:
- /* We don't care about discriminators. */
- read_uleb128 (line_buf);
- break;
- default:
- if (!advance (line_buf, len - 1))
- return 0;
- break;
- }
- }
- else
- {
- switch (op)
- {
- case DW_LNS_copy:
- add_line (state, ddata, address, filename, lineno,
- line_buf->error_callback, line_buf->data, vec);
- break;
- case DW_LNS_advance_pc:
- {
- uint64_t advance;
- advance = read_uleb128 (line_buf);
- address += (hdr->min_insn_len * (op_index + advance)
- / hdr->max_ops_per_insn);
- op_index = (op_index + advance) % hdr->max_ops_per_insn;
- }
- break;
- case DW_LNS_advance_line:
- lineno += (int) read_sleb128 (line_buf);
- break;
- case DW_LNS_set_file:
- {
- uint64_t fileno;
- fileno = read_uleb128 (line_buf);
- if (fileno >= hdr->filenames_count)
- {
- dwarf_buf_error (line_buf,
- ("invalid file number in "
- "line number program"),
- 0);
- return 0;
- }
- filename = hdr->filenames[fileno];
- }
- break;
- case DW_LNS_set_column:
- read_uleb128 (line_buf);
- break;
- case DW_LNS_negate_stmt:
- break;
- case DW_LNS_set_basic_block:
- break;
- case DW_LNS_const_add_pc:
- {
- unsigned int advance;
- op = 255 - hdr->opcode_base;
- advance = op / hdr->line_range;
- address += (hdr->min_insn_len * (op_index + advance)
- / hdr->max_ops_per_insn);
- op_index = (op_index + advance) % hdr->max_ops_per_insn;
- }
- break;
- case DW_LNS_fixed_advance_pc:
- address += read_uint16 (line_buf);
- op_index = 0;
- break;
- case DW_LNS_set_prologue_end:
- break;
- case DW_LNS_set_epilogue_begin:
- break;
- case DW_LNS_set_isa:
- read_uleb128 (line_buf);
- break;
- default:
- {
- unsigned int i;
- for (i = hdr->opcode_lengths[op - 1]; i > 0; --i)
- read_uleb128 (line_buf);
- }
- break;
- }
- }
- }
- return 1;
- }
- /* Read the line number information for a compilation unit. Returns 1
- on success, 0 on failure. */
- static int
- read_line_info (struct backtrace_state *state, struct dwarf_data *ddata,
- backtrace_error_callback error_callback, void *data,
- struct unit *u, struct line_header *hdr, struct line **lines,
- size_t *lines_count)
- {
- struct line_vector vec;
- struct dwarf_buf line_buf;
- uint64_t len;
- int is_dwarf64;
- struct line *ln;
- memset (&vec.vec, 0, sizeof vec.vec);
- vec.count = 0;
- memset (hdr, 0, sizeof *hdr);
- if (u->lineoff != (off_t) (size_t) u->lineoff
- || (size_t) u->lineoff >= ddata->dwarf_sections.size[DEBUG_LINE])
- {
- error_callback (data, "unit line offset out of range", 0);
- goto fail;
- }
- line_buf.name = ".debug_line";
- line_buf.start = ddata->dwarf_sections.data[DEBUG_LINE];
- line_buf.buf = ddata->dwarf_sections.data[DEBUG_LINE] + u->lineoff;
- line_buf.left = ddata->dwarf_sections.size[DEBUG_LINE] - u->lineoff;
- line_buf.is_bigendian = ddata->is_bigendian;
- line_buf.error_callback = error_callback;
- line_buf.data = data;
- line_buf.reported_underflow = 0;
- len = read_initial_length (&line_buf, &is_dwarf64);
- line_buf.left = len;
- if (!read_line_header (state, ddata, u, is_dwarf64, &line_buf, hdr))
- goto fail;
- if (!read_line_program (state, ddata, hdr, &line_buf, &vec))
- goto fail;
- if (line_buf.reported_underflow)
- goto fail;
- if (vec.count == 0)
- {
- /* This is not a failure in the sense of a generating an error,
- but it is a failure in that sense that we have no useful
- information. */
- goto fail;
- }
- /* Allocate one extra entry at the end. */
- ln = ((struct line *)
- backtrace_vector_grow (state, sizeof (struct line), error_callback,
- data, &vec.vec));
- if (ln == NULL)
- goto fail;
- ln->pc = (uintptr_t) -1;
- ln->filename = NULL;
- ln->lineno = 0;
- ln->idx = 0;
- if (!backtrace_vector_release (state, &vec.vec, error_callback, data))
- goto fail;
- ln = (struct line *) vec.vec.base;
- backtrace_qsort (ln, vec.count, sizeof (struct line), line_compare);
- *lines = ln;
- *lines_count = vec.count;
- return 1;
- fail:
- backtrace_vector_free (state, &vec.vec, error_callback, data);
- free_line_header (state, hdr, error_callback, data);
- *lines = (struct line *) (uintptr_t) -1;
- *lines_count = 0;
- return 0;
- }
- static const char *read_referenced_name (struct dwarf_data *, struct unit *,
- uint64_t, backtrace_error_callback,
- void *);
- /* Read the name of a function from a DIE referenced by ATTR with VAL. */
- static const char *
- read_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u,
- struct attr *attr, struct attr_val *val,
- backtrace_error_callback error_callback,
- void *data)
- {
- switch (attr->name)
- {
- case DW_AT_abstract_origin:
- case DW_AT_specification:
- break;
- default:
- return NULL;
- }
- if (attr->form == DW_FORM_ref_sig8)
- return NULL;
- if (val->encoding == ATTR_VAL_REF_INFO)
- {
- struct unit *unit
- = find_unit (ddata->units, ddata->units_count,
- val->u.uint);
- if (unit == NULL)
- return NULL;
- uint64_t offset = val->u.uint - unit->low_offset;
- return read_referenced_name (ddata, unit, offset, error_callback, data);
- }
- if (val->encoding == ATTR_VAL_UINT
- || val->encoding == ATTR_VAL_REF_UNIT)
- return read_referenced_name (ddata, u, val->u.uint, error_callback, data);
- if (val->encoding == ATTR_VAL_REF_ALT_INFO)
- {
- struct unit *alt_unit
- = find_unit (ddata->altlink->units, ddata->altlink->units_count,
- val->u.uint);
- if (alt_unit == NULL)
- return NULL;
- uint64_t offset = val->u.uint - alt_unit->low_offset;
- return read_referenced_name (ddata->altlink, alt_unit, offset,
- error_callback, data);
- }
- return NULL;
- }
- /* Read the name of a function from a DIE referenced by a
- DW_AT_abstract_origin or DW_AT_specification tag. OFFSET is within
- the same compilation unit. */
- static const char *
- read_referenced_name (struct dwarf_data *ddata, struct unit *u,
- uint64_t offset, backtrace_error_callback error_callback,
- void *data)
- {
- struct dwarf_buf unit_buf;
- uint64_t code;
- const struct abbrev *abbrev;
- const char *ret;
- size_t i;
- /* OFFSET is from the start of the data for this compilation unit.
- U->unit_data is the data, but it starts U->unit_data_offset bytes
- from the beginning. */
- if (offset < u->unit_data_offset
- || offset - u->unit_data_offset >= u->unit_data_len)
- {
- error_callback (data,
- "abstract origin or specification out of range",
- 0);
- return NULL;
- }
- offset -= u->unit_data_offset;
- unit_buf.name = ".debug_info";
- unit_buf.start = ddata->dwarf_sections.data[DEBUG_INFO];
- unit_buf.buf = u->unit_data + offset;
- unit_buf.left = u->unit_data_len - offset;
- unit_buf.is_bigendian = ddata->is_bigendian;
- unit_buf.error_callback = error_callback;
- unit_buf.data = data;
- unit_buf.reported_underflow = 0;
- code = read_uleb128 (&unit_buf);
- if (code == 0)
- {
- dwarf_buf_error (&unit_buf,
- "invalid abstract origin or specification",
- 0);
- return NULL;
- }
- abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);
- if (abbrev == NULL)
- return NULL;
- ret = NULL;
- for (i = 0; i < abbrev->num_attrs; ++i)
- {
- struct attr_val val;
- if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
- &unit_buf, u->is_dwarf64, u->version, u->addrsize,
- &ddata->dwarf_sections, ddata->altlink, &val))
- return NULL;
- switch (abbrev->attrs[i].name)
- {
- case DW_AT_name:
- /* Third name preference: don't override. A name we found in some
- other way, will normally be more useful -- e.g., this name is
- normally not mangled. */
- if (ret != NULL)
- break;
- if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
- ddata->is_bigendian, u->str_offsets_base,
- &val, error_callback, data, &ret))
- return NULL;
- break;
- case DW_AT_linkage_name:
- case DW_AT_MIPS_linkage_name:
- /* First name preference: override all. */
- {
- const char *s;
- s = NULL;
- if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
- ddata->is_bigendian, u->str_offsets_base,
- &val, error_callback, data, &s))
- return NULL;
- if (s != NULL)
- return s;
- }
- break;
- case DW_AT_specification:
- /* Second name preference: override DW_AT_name, don't override
- DW_AT_linkage_name. */
- {
- const char *name;
- name = read_referenced_name_from_attr (ddata, u, &abbrev->attrs[i],
- &val, error_callback, data);
- if (name != NULL)
- ret = name;
- }
- break;
- default:
- break;
- }
- }
- return ret;
- }
- /* Add a range to a unit that maps to a function. This is called via
- add_ranges. Returns 1 on success, 0 on error. */
- static int
- add_function_range (struct backtrace_state *state, void *rdata,
- uintptr_t lowpc, uintptr_t highpc,
- backtrace_error_callback error_callback, void *data,
- void *pvec)
- {
- struct function *function = (struct function *) rdata;
- struct function_vector *vec = (struct function_vector *) pvec;
- struct function_addrs *p;
- if (vec->count > 0)
- {
- p = (struct function_addrs *) vec->vec.base + (vec->count - 1);
- if ((lowpc == p->high || lowpc == p->high + 1)
- && function == p->function)
- {
- if (highpc > p->high)
- p->high = highpc;
- return 1;
- }
- }
- p = ((struct function_addrs *)
- backtrace_vector_grow (state, sizeof (struct function_addrs),
- error_callback, data, &vec->vec));
- if (p == NULL)
- return 0;
- p->low = lowpc;
- p->high = highpc;
- p->function = function;
- ++vec->count;
- return 1;
- }
- /* Read one entry plus all its children. Add function addresses to
- VEC. Returns 1 on success, 0 on error. */
- static int
- read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
- struct unit *u, uintptr_t base, struct dwarf_buf *unit_buf,
- const struct line_header *lhdr,
- backtrace_error_callback error_callback, void *data,
- struct function_vector *vec_function,
- struct function_vector *vec_inlined)
- {
- while (unit_buf->left > 0)
- {
- uint64_t code;
- const struct abbrev *abbrev;
- int is_function;
- struct function *function;
- struct function_vector *vec;
- size_t i;
- struct pcrange pcrange;
- int have_linkage_name;
- code = read_uleb128 (unit_buf);
- if (code == 0)
- return 1;
- abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);
- if (abbrev == NULL)
- return 0;
- is_function = (abbrev->tag == DW_TAG_subprogram
- || abbrev->tag == DW_TAG_entry_point
- || abbrev->tag == DW_TAG_inlined_subroutine);
- if (abbrev->tag == DW_TAG_inlined_subroutine)
- vec = vec_inlined;
- else
- vec = vec_function;
- function = NULL;
- if (is_function)
- {
- function = ((struct function *)
- backtrace_alloc (state, sizeof *function,
- error_callback, data));
- if (function == NULL)
- return 0;
- memset (function, 0, sizeof *function);
- }
- memset (&pcrange, 0, sizeof pcrange);
- have_linkage_name = 0;
- for (i = 0; i < abbrev->num_attrs; ++i)
- {
- struct attr_val val;
- if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
- unit_buf, u->is_dwarf64, u->version,
- u->addrsize, &ddata->dwarf_sections,
- ddata->altlink, &val))
- return 0;
- /* The compile unit sets the base address for any address
- ranges in the function entries. */
- if ((abbrev->tag == DW_TAG_compile_unit
- || abbrev->tag == DW_TAG_skeleton_unit)
- && abbrev->attrs[i].name == DW_AT_low_pc)
- {
- if (val.encoding == ATTR_VAL_ADDRESS)
- base = (uintptr_t) val.u.uint;
- else if (val.encoding == ATTR_VAL_ADDRESS_INDEX)
- {
- if (!resolve_addr_index (&ddata->dwarf_sections,
- u->addr_base, u->addrsize,
- ddata->is_bigendian, val.u.uint,
- error_callback, data, &base))
- return 0;
- }
- }
- if (is_function)
- {
- switch (abbrev->attrs[i].name)
- {
- case DW_AT_call_file:
- if (val.encoding == ATTR_VAL_UINT)
- {
- if (val.u.uint >= lhdr->filenames_count)
- {
- dwarf_buf_error (unit_buf,
- ("invalid file number in "
- "DW_AT_call_file attribute"),
- 0);
- return 0;
- }
- function->caller_filename = lhdr->filenames[val.u.uint];
- }
- break;
- case DW_AT_call_line:
- if (val.encoding == ATTR_VAL_UINT)
- function->caller_lineno = val.u.uint;
- break;
- case DW_AT_abstract_origin:
- case DW_AT_specification:
- /* Second name preference: override DW_AT_name, don't override
- DW_AT_linkage_name. */
- if (have_linkage_name)
- break;
- {
- const char *name;
- name
- = read_referenced_name_from_attr (ddata, u,
- &abbrev->attrs[i], &val,
- error_callback, data);
- if (name != NULL)
- function->name = name;
- }
- break;
- case DW_AT_name:
- /* Third name preference: don't override. */
- if (function->name != NULL)
- break;
- if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
- ddata->is_bigendian,
- u->str_offsets_base, &val,
- error_callback, data, &function->name))
- return 0;
- break;
- case DW_AT_linkage_name:
- case DW_AT_MIPS_linkage_name:
- /* First name preference: override all. */
- {
- const char *s;
- s = NULL;
- if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
- ddata->is_bigendian,
- u->str_offsets_base, &val,
- error_callback, data, &s))
- return 0;
- if (s != NULL)
- {
- function->name = s;
- have_linkage_name = 1;
- }
- }
- break;
- case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges:
- update_pcrange (&abbrev->attrs[i], &val, &pcrange);
- break;
- default:
- break;
- }
- }
- }
- /* If we couldn't find a name for the function, we have no use
- for it. */
- if (is_function && function->name == NULL)
- {
- backtrace_free (state, function, sizeof *function,
- error_callback, data);
- is_function = 0;
- }
- if (is_function)
- {
- if (pcrange.have_ranges
- || (pcrange.have_lowpc && pcrange.have_highpc))
- {
- if (!add_ranges (state, &ddata->dwarf_sections,
- ddata->base_address, ddata->is_bigendian,
- u, base, &pcrange, add_function_range,
- (void *) function, error_callback, data,
- (void *) vec))
- return 0;
- }
- else
- {
- backtrace_free (state, function, sizeof *function,
- error_callback, data);
- is_function = 0;
- }
- }
- if (abbrev->has_children)
- {
- if (!is_function)
- {
- if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr,
- error_callback, data, vec_function,
- vec_inlined))
- return 0;
- }
- else
- {
- struct function_vector fvec;
- /* Gather any information for inlined functions in
- FVEC. */
- memset (&fvec, 0, sizeof fvec);
- if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr,
- error_callback, data, vec_function,
- &fvec))
- return 0;
- if (fvec.count > 0)
- {
- struct function_addrs *p;
- struct function_addrs *faddrs;
- /* Allocate a trailing entry, but don't include it
- in fvec.count. */
- p = ((struct function_addrs *)
- backtrace_vector_grow (state,
- sizeof (struct function_addrs),
- error_callback, data,
- &fvec.vec));
- if (p == NULL)
- return 0;
- p->low = 0;
- --p->low;
- p->high = p->low;
- p->function = NULL;
- if (!backtrace_vector_release (state, &fvec.vec,
- error_callback, data))
- return 0;
- faddrs = (struct function_addrs *) fvec.vec.base;
- backtrace_qsort (faddrs, fvec.count,
- sizeof (struct function_addrs),
- function_addrs_compare);
- function->function_addrs = faddrs;
- function->function_addrs_count = fvec.count;
- }
- }
- }
- }
- return 1;
- }
- /* Read function name information for a compilation unit. We look
- through the whole unit looking for function tags. */
- static void
- read_function_info (struct backtrace_state *state, struct dwarf_data *ddata,
- const struct line_header *lhdr,
- backtrace_error_callback error_callback, void *data,
- struct unit *u, struct function_vector *fvec,
- struct function_addrs **ret_addrs,
- size_t *ret_addrs_count)
- {
- struct function_vector lvec;
- struct function_vector *pfvec;
- struct dwarf_buf unit_buf;
- struct function_addrs *p;
- struct function_addrs *addrs;
- size_t addrs_count;
- /* Use FVEC if it is not NULL. Otherwise use our own vector. */
- if (fvec != NULL)
- pfvec = fvec;
- else
- {
- memset (&lvec, 0, sizeof lvec);
- pfvec = &lvec;
- }
- unit_buf.name = ".debug_info";
- unit_buf.start = ddata->dwarf_sections.data[DEBUG_INFO];
- unit_buf.buf = u->unit_data;
- unit_buf.left = u->unit_data_len;
- unit_buf.is_bigendian = ddata->is_bigendian;
- unit_buf.error_callback = error_callback;
- unit_buf.data = data;
- unit_buf.reported_underflow = 0;
- while (unit_buf.left > 0)
- {
- if (!read_function_entry (state, ddata, u, 0, &unit_buf, lhdr,
- error_callback, data, pfvec, pfvec))
- return;
- }
- if (pfvec->count == 0)
- return;
- /* Allocate a trailing entry, but don't include it in
- pfvec->count. */
- p = ((struct function_addrs *)
- backtrace_vector_grow (state, sizeof (struct function_addrs),
- error_callback, data, &pfvec->vec));
- if (p == NULL)
- return;
- p->low = 0;
- --p->low;
- p->high = p->low;
- p->function = NULL;
- addrs_count = pfvec->count;
- if (fvec == NULL)
- {
- if (!backtrace_vector_release (state, &lvec.vec, error_callback, data))
- return;
- addrs = (struct function_addrs *) pfvec->vec.base;
- }
- else
- {
- /* Finish this list of addresses, but leave the remaining space in
- the vector available for the next function unit. */
- addrs = ((struct function_addrs *)
- backtrace_vector_finish (state, &fvec->vec,
- error_callback, data));
- if (addrs == NULL)
- return;
- fvec->count = 0;
- }
- backtrace_qsort (addrs, addrs_count, sizeof (struct function_addrs),
- function_addrs_compare);
- *ret_addrs = addrs;
- *ret_addrs_count = addrs_count;
- }
- /* See if PC is inlined in FUNCTION. If it is, print out the inlined
- information, and update FILENAME and LINENO for the caller.
- Returns whatever CALLBACK returns, or 0 to keep going. */
- static int
- report_inlined_functions (uintptr_t pc, struct function *function,
- backtrace_full_callback callback, void *data,
- const char **filename, int *lineno)
- {
- struct function_addrs *p;
- struct function_addrs *match;
- struct function *inlined;
- int ret;
- if (function->function_addrs_count == 0)
- return 0;
- /* Our search isn't safe if pc == -1, as that is the sentinel
- value. */
- if (pc + 1 == 0)
- return 0;
- p = ((struct function_addrs *)
- bsearch (&pc, function->function_addrs,
- function->function_addrs_count,
- sizeof (struct function_addrs),
- function_addrs_search));
- if (p == NULL)
- return 0;
- /* Here pc >= p->low && pc < (p + 1)->low. The function_addrs are
- sorted by low, so if pc > p->low we are at the end of a range of
- function_addrs with the same low value. If pc == p->low walk
- forward to the end of the range with that low value. Then walk
- backward and use the first range that includes pc. */
- while (pc == (p + 1)->low)
- ++p;
- match = NULL;
- while (1)
- {
- if (pc < p->high)
- {
- match = p;
- break;
- }
- if (p == function->function_addrs)
- break;
- if ((p - 1)->low < p->low)
- break;
- --p;
- }
- if (match == NULL)
- return 0;
- /* We found an inlined call. */
- inlined = match->function;
- /* Report any calls inlined into this one. */
- ret = report_inlined_functions (pc, inlined, callback, data,
- filename, lineno);
- if (ret != 0)
- return ret;
- /* Report this inlined call. */
- ret = callback (data, pc, *filename, *lineno, inlined->name);
- if (ret != 0)
- return ret;
- /* Our caller will report the caller of the inlined function; tell
- it the appropriate filename and line number. */
- *filename = inlined->caller_filename;
- *lineno = inlined->caller_lineno;
- return 0;
- }
- /* Look for a PC in the DWARF mapping 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
- dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
- uintptr_t pc, backtrace_full_callback callback,
- backtrace_error_callback error_callback, void *data,
- int *found)
- {
- struct unit_addrs *entry;
- int found_entry;
- struct unit *u;
- int new_data;
- struct line *lines;
- struct line *ln;
- struct function_addrs *p;
- struct function_addrs *fmatch;
- struct function *function;
- const char *filename;
- int lineno;
- int ret;
- *found = 1;
- /* Find an address range that includes PC. Our search isn't safe if
- PC == -1, as we use that as a sentinel value, so skip the search
- in that case. */
- entry = (ddata->addrs_count == 0 || pc + 1 == 0
- ? NULL
- : bsearch (&pc, ddata->addrs, ddata->addrs_count,
- sizeof (struct unit_addrs), unit_addrs_search));
- if (entry == NULL)
- {
- *found = 0;
- return 0;
- }
- /* Here pc >= entry->low && pc < (entry + 1)->low. The unit_addrs
- are sorted by low, so if pc > p->low we are at the end of a range
- of unit_addrs with the same low value. If pc == p->low walk
- forward to the end of the range with that low value. Then walk
- backward and use the first range that includes pc. */
- while (pc == (entry + 1)->low)
- ++entry;
- found_entry = 0;
- while (1)
- {
- if (pc < entry->high)
- {
- found_entry = 1;
- break;
- }
- if (entry == ddata->addrs)
- break;
- if ((entry - 1)->low < entry->low)
- break;
- --entry;
- }
- if (!found_entry)
- {
- *found = 0;
- return 0;
- }
- /* We need the lines, lines_count, function_addrs,
- function_addrs_count fields of u. If they are not set, we need
- to set them. When running in threaded mode, we need to allow for
- the possibility that some other thread is setting them
- simultaneously. */
- u = entry->u;
- lines = u->lines;
- /* Skip units with no useful line number information by walking
- backward. Useless line number information is marked by setting
- lines == -1. */
- while (entry > ddata->addrs
- && pc >= (entry - 1)->low
- && pc < (entry - 1)->high)
- {
- if (state->threaded)
- lines = (struct line *) backtrace_atomic_load_pointer (&u->lines);
- if (lines != (struct line *) (uintptr_t) -1)
- break;
- --entry;
- u = entry->u;
- lines = u->lines;
- }
- if (state->threaded)
- lines = backtrace_atomic_load_pointer (&u->lines);
- new_data = 0;
- if (lines == NULL)
- {
- struct function_addrs *function_addrs;
- size_t function_addrs_count;
- struct line_header lhdr;
- size_t count;
- /* We have never read the line information for this unit. Read
- it now. */
- function_addrs = NULL;
- function_addrs_count = 0;
- if (read_line_info (state, ddata, error_callback, data, entry->u, &lhdr,
- &lines, &count))
- {
- struct function_vector *pfvec;
- /* If not threaded, reuse DDATA->FVEC for better memory
- consumption. */
- if (state->threaded)
- pfvec = NULL;
- else
- pfvec = &ddata->fvec;
- read_function_info (state, ddata, &lhdr, error_callback, data,
- entry->u, pfvec, &function_addrs,
- &function_addrs_count);
- free_line_header (state, &lhdr, error_callback, data);
- new_data = 1;
- }
- /* Atomically store the information we just read into the unit.
- If another thread is simultaneously writing, it presumably
- read the same information, and we don't care which one we
- wind up with; we just leak the other one. We do have to
- write the lines field last, so that the acquire-loads above
- ensure that the other fields are set. */
- if (!state->threaded)
- {
- u->lines_count = count;
- u->function_addrs = function_addrs;
- u->function_addrs_count = function_addrs_count;
- u->lines = lines;
- }
- else
- {
- backtrace_atomic_store_size_t (&u->lines_count, count);
- backtrace_atomic_store_pointer (&u->function_addrs, function_addrs);
- backtrace_atomic_store_size_t (&u->function_addrs_count,
- function_addrs_count);
- backtrace_atomic_store_pointer (&u->lines, lines);
- }
- }
- /* Now all fields of U have been initialized. */
- if (lines == (struct line *) (uintptr_t) -1)
- {
- /* If reading the line number information failed in some way,
- try again to see if there is a better compilation unit for
- this PC. */
- if (new_data)
- return dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
- data, found);
- return callback (data, pc, NULL, 0, NULL);
- }
- /* Search for PC within this unit. */
- ln = (struct line *) bsearch (&pc, lines, entry->u->lines_count,
- sizeof (struct line), line_search);
- if (ln == NULL)
- {
- /* The PC is between the low_pc and high_pc attributes of the
- compilation unit, but no entry in the line table covers it.
- This implies that the start of the compilation unit has no
- line number information. */
- if (entry->u->abs_filename == NULL)
- {
- const char *filename;
- filename = entry->u->filename;
- if (filename != NULL
- && !IS_ABSOLUTE_PATH (filename)
- && entry->u->comp_dir != NULL)
- {
- size_t filename_len;
- const char *dir;
- size_t dir_len;
- char *s;
- filename_len = strlen (filename);
- dir = entry->u->comp_dir;
- dir_len = strlen (dir);
- s = (char *) backtrace_alloc (state, dir_len + filename_len + 2,
- error_callback, data);
- if (s == NULL)
- {
- *found = 0;
- return 0;
- }
- memcpy (s, dir, dir_len);
- /* FIXME: Should use backslash if DOS file system. */
- s[dir_len] = '/';
- memcpy (s + dir_len + 1, filename, filename_len + 1);
- filename = s;
- }
- entry->u->abs_filename = filename;
- }
- return callback (data, pc, entry->u->abs_filename, 0, NULL);
- }
- /* Search for function name within this unit. */
- if (entry->u->function_addrs_count == 0)
- return callback (data, pc, ln->filename, ln->lineno, NULL);
- p = ((struct function_addrs *)
- bsearch (&pc, entry->u->function_addrs,
- entry->u->function_addrs_count,
- sizeof (struct function_addrs),
- function_addrs_search));
- if (p == NULL)
- return callback (data, pc, ln->filename, ln->lineno, NULL);
- /* Here pc >= p->low && pc < (p + 1)->low. The function_addrs are
- sorted by low, so if pc > p->low we are at the end of a range of
- function_addrs with the same low value. If pc == p->low walk
- forward to the end of the range with that low value. Then walk
- backward and use the first range that includes pc. */
- while (pc == (p + 1)->low)
- ++p;
- fmatch = NULL;
- while (1)
- {
- if (pc < p->high)
- {
- fmatch = p;
- break;
- }
- if (p == entry->u->function_addrs)
- break;
- if ((p - 1)->low < p->low)
- break;
- --p;
- }
- if (fmatch == NULL)
- return callback (data, pc, ln->filename, ln->lineno, NULL);
- function = fmatch->function;
- filename = ln->filename;
- lineno = ln->lineno;
- ret = report_inlined_functions (pc, function, callback, data,
- &filename, &lineno);
- if (ret != 0)
- return ret;
- return callback (data, pc, filename, lineno, function->name);
- }
- /* Return the file/line information for a PC using the DWARF mapping
- we built earlier. */
- static int
- dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
- backtrace_full_callback callback,
- backtrace_error_callback error_callback, void *data)
- {
- struct dwarf_data *ddata;
- int found;
- int ret;
- if (!state->threaded)
- {
- for (ddata = (struct dwarf_data *) state->fileline_data;
- ddata != NULL;
- ddata = ddata->next)
- {
- ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
- data, &found);
- if (ret != 0 || found)
- return ret;
- }
- }
- else
- {
- struct dwarf_data **pp;
- pp = (struct dwarf_data **) (void *) &state->fileline_data;
- while (1)
- {
- ddata = backtrace_atomic_load_pointer (pp);
- if (ddata == NULL)
- break;
- ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
- data, &found);
- if (ret != 0 || found)
- return ret;
- pp = &ddata->next;
- }
- }
- /* FIXME: See if any libraries have been dlopen'ed. */
- return callback (data, pc, NULL, 0, NULL);
- }
- /* Initialize our data structures from the DWARF debug info for a
- file. Return NULL on failure. */
- static struct dwarf_data *
- build_dwarf_data (struct backtrace_state *state,
- struct libbacktrace_base_address base_address,
- const struct dwarf_sections *dwarf_sections,
- int is_bigendian,
- struct dwarf_data *altlink,
- backtrace_error_callback error_callback,
- void *data)
- {
- struct unit_addrs_vector addrs_vec;
- struct unit_addrs *addrs;
- size_t addrs_count;
- struct unit_vector units_vec;
- struct unit **units;
- size_t units_count;
- struct dwarf_data *fdata;
- if (!build_address_map (state, base_address, dwarf_sections, is_bigendian,
- altlink, error_callback, data, &addrs_vec,
- &units_vec))
- return NULL;
- if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data))
- return NULL;
- if (!backtrace_vector_release (state, &units_vec.vec, error_callback, data))
- return NULL;
- addrs = (struct unit_addrs *) addrs_vec.vec.base;
- units = (struct unit **) units_vec.vec.base;
- addrs_count = addrs_vec.count;
- units_count = units_vec.count;
- backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs),
- unit_addrs_compare);
- /* No qsort for units required, already sorted. */
- fdata = ((struct dwarf_data *)
- backtrace_alloc (state, sizeof (struct dwarf_data),
- error_callback, data));
- if (fdata == NULL)
- return NULL;
- fdata->next = NULL;
- fdata->altlink = altlink;
- fdata->base_address = base_address;
- fdata->addrs = addrs;
- fdata->addrs_count = addrs_count;
- fdata->units = units;
- fdata->units_count = units_count;
- fdata->dwarf_sections = *dwarf_sections;
- fdata->is_bigendian = is_bigendian;
- memset (&fdata->fvec, 0, sizeof fdata->fvec);
- return fdata;
- }
- /* Build our data structures from the DWARF sections for a module.
- Set FILELINE_FN and STATE->FILELINE_DATA. Return 1 on success, 0
- on failure. */
- int
- backtrace_dwarf_add (struct backtrace_state *state,
- struct libbacktrace_base_address base_address,
- const struct dwarf_sections *dwarf_sections,
- int is_bigendian,
- struct dwarf_data *fileline_altlink,
- backtrace_error_callback error_callback,
- void *data, fileline *fileline_fn,
- struct dwarf_data **fileline_entry)
- {
- struct dwarf_data *fdata;
- fdata = build_dwarf_data (state, base_address, dwarf_sections, is_bigendian,
- fileline_altlink, error_callback, data);
- if (fdata == NULL)
- return 0;
- if (fileline_entry != NULL)
- *fileline_entry = fdata;
- if (!state->threaded)
- {
- struct dwarf_data **pp;
- for (pp = (struct dwarf_data **) (void *) &state->fileline_data;
- *pp != NULL;
- pp = &(*pp)->next)
- ;
- *pp = fdata;
- }
- else
- {
- while (1)
- {
- struct dwarf_data **pp;
- pp = (struct dwarf_data **) (void *) &state->fileline_data;
- while (1)
- {
- struct dwarf_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;
- }
- }
- *fileline_fn = dwarf_fileline;
- return 1;
- }
|