123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089 |
- /* Output Dwarf2 format symbol table information from GCC.
- Copyright (C) 1992-2015 Free Software Foundation, Inc.
- Contributed by Gary Funck (gary@intrepid.com).
- Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
- Extensively modified by Jason Merrill (jason@cygnus.com).
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- /* TODO: Emit .debug_line header even when there are no functions, since
- the file numbers are used by .debug_info. Alternately, leave
- out locations for types and decls.
- Avoid talking about ctors and op= for PODs.
- Factor out common prologue sequences into multiple CIEs. */
- /* The first part of this file deals with the DWARF 2 frame unwind
- information, which is also used by the GCC efficient exception handling
- mechanism. The second part, controlled only by an #ifdef
- DWARF2_DEBUGGING_INFO, deals with the other DWARF 2 debugging
- information. */
- /* DWARF2 Abbreviation Glossary:
- CFA = Canonical Frame Address
- a fixed address on the stack which identifies a call frame.
- We define it to be the value of SP just before the call insn.
- The CFA register and offset, which may change during the course
- of the function, are used to calculate its value at runtime.
- CFI = Call Frame Instruction
- an instruction for the DWARF2 abstract machine
- CIE = Common Information Entry
- information describing information common to one or more FDEs
- DIE = Debugging Information Entry
- FDE = Frame Description Entry
- information describing the stack call frame, in particular,
- how to restore registers
- DW_CFA_... = DWARF2 CFA call frame instruction
- DW_TAG_... = DWARF2 DIE tag */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "tm.h"
- #include "rtl.h"
- #include "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "real.h"
- #include "tree.h"
- #include "fold-const.h"
- #include "stringpool.h"
- #include "stor-layout.h"
- #include "varasm.h"
- #include "hashtab.h"
- #include "hard-reg-set.h"
- #include "function.h"
- #include "emit-rtl.h"
- #include "hash-table.h"
- #include "version.h"
- #include "flags.h"
- #include "regs.h"
- #include "rtlhash.h"
- #include "insn-config.h"
- #include "reload.h"
- #include "output.h"
- #include "statistics.h"
- #include "fixed-value.h"
- #include "expmed.h"
- #include "dojump.h"
- #include "explow.h"
- #include "calls.h"
- #include "stmt.h"
- #include "expr.h"
- #include "except.h"
- #include "dwarf2.h"
- #include "dwarf2out.h"
- #include "dwarf2asm.h"
- #include "toplev.h"
- #include "md5.h"
- #include "tm_p.h"
- #include "diagnostic.h"
- #include "tree-pretty-print.h"
- #include "debug.h"
- #include "target.h"
- #include "common/common-target.h"
- #include "langhooks.h"
- #include "hash-map.h"
- #include "is-a.h"
- #include "plugin-api.h"
- #include "ipa-ref.h"
- #include "cgraph.h"
- #include "ira.h"
- #include "lra.h"
- #include "dumpfile.h"
- #include "opts.h"
- #include "tree-dfa.h"
- #include "gdb/gdb-index.h"
- #include "rtl-iter.h"
- static void dwarf2out_source_line (unsigned int, const char *, int, bool);
- static rtx_insn *last_var_location_insn;
- static rtx_insn *cached_next_real_insn;
- static void dwarf2out_decl (tree);
- #ifdef VMS_DEBUGGING_INFO
- int vms_file_stats_name (const char *, long long *, long *, char *, int *);
- /* Define this macro to be a nonzero value if the directory specifications
- which are output in the debug info should end with a separator. */
- #define DWARF2_DIR_SHOULD_END_WITH_SEPARATOR 1
- /* Define this macro to evaluate to a nonzero value if GCC should refrain
- from generating indirect strings in DWARF2 debug information, for instance
- if your target is stuck with an old version of GDB that is unable to
- process them properly or uses VMS Debug. */
- #define DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET 1
- #else
- #define DWARF2_DIR_SHOULD_END_WITH_SEPARATOR 0
- #define DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET 0
- #endif
- /* ??? Poison these here until it can be done generically. They've been
- totally replaced in this file; make sure it stays that way. */
- #undef DWARF2_UNWIND_INFO
- #undef DWARF2_FRAME_INFO
- #if (GCC_VERSION >= 3000)
- #pragma GCC poison DWARF2_UNWIND_INFO DWARF2_FRAME_INFO
- #endif
- /* The size of the target's pointer type. */
- #ifndef PTR_SIZE
- #define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
- #endif
- /* Array of RTXes referenced by the debugging information, which therefore
- must be kept around forever. */
- static GTY(()) vec<rtx, va_gc> *used_rtx_array;
- /* A pointer to the base of a list of incomplete types which might be
- completed at some later time. incomplete_types_list needs to be a
- vec<tree, va_gc> *because we want to tell the garbage collector about
- it. */
- static GTY(()) vec<tree, va_gc> *incomplete_types;
- /* A pointer to the base of a table of references to declaration
- scopes. This table is a display which tracks the nesting
- of declaration scopes at the current scope and containing
- scopes. This table is used to find the proper place to
- define type declaration DIE's. */
- static GTY(()) vec<tree, va_gc> *decl_scope_table;
- /* Pointers to various DWARF2 sections. */
- static GTY(()) section *debug_info_section;
- static GTY(()) section *debug_skeleton_info_section;
- static GTY(()) section *debug_abbrev_section;
- static GTY(()) section *debug_skeleton_abbrev_section;
- static GTY(()) section *debug_aranges_section;
- static GTY(()) section *debug_addr_section;
- static GTY(()) section *debug_macinfo_section;
- static GTY(()) section *debug_line_section;
- static GTY(()) section *debug_skeleton_line_section;
- static GTY(()) section *debug_loc_section;
- static GTY(()) section *debug_pubnames_section;
- static GTY(()) section *debug_pubtypes_section;
- static GTY(()) section *debug_str_section;
- static GTY(()) section *debug_str_dwo_section;
- static GTY(()) section *debug_str_offsets_section;
- static GTY(()) section *debug_ranges_section;
- static GTY(()) section *debug_frame_section;
- /* Maximum size (in bytes) of an artificially generated label. */
- #define MAX_ARTIFICIAL_LABEL_BYTES 30
- /* According to the (draft) DWARF 3 specification, the initial length
- should either be 4 or 12 bytes. When it's 12 bytes, the first 4
- bytes are 0xffffffff, followed by the length stored in the next 8
- bytes.
- However, the SGI/MIPS ABI uses an initial length which is equal to
- DWARF_OFFSET_SIZE. It is defined (elsewhere) accordingly. */
- #ifndef DWARF_INITIAL_LENGTH_SIZE
- #define DWARF_INITIAL_LENGTH_SIZE (DWARF_OFFSET_SIZE == 4 ? 4 : 12)
- #endif
- /* Round SIZE up to the nearest BOUNDARY. */
- #define DWARF_ROUND(SIZE,BOUNDARY) \
- ((((SIZE) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY))
- /* CIE identifier. */
- #if HOST_BITS_PER_WIDE_INT >= 64
- #define DWARF_CIE_ID \
- (unsigned HOST_WIDE_INT) (DWARF_OFFSET_SIZE == 4 ? DW_CIE_ID : DW64_CIE_ID)
- #else
- #define DWARF_CIE_ID DW_CIE_ID
- #endif
- /* A vector for a table that contains frame description
- information for each routine. */
- #define NOT_INDEXED (-1U)
- #define NO_INDEX_ASSIGNED (-2U)
- static GTY(()) vec<dw_fde_ref, va_gc> *fde_vec;
- struct GTY((for_user)) indirect_string_node {
- const char *str;
- unsigned int refcount;
- enum dwarf_form form;
- char *label;
- unsigned int index;
- };
- struct indirect_string_hasher : ggc_hasher<indirect_string_node *>
- {
- typedef const char *compare_type;
- static hashval_t hash (indirect_string_node *);
- static bool equal (indirect_string_node *, const char *);
- };
- static GTY (()) hash_table<indirect_string_hasher> *debug_str_hash;
- /* With split_debug_info, both the comp_dir and dwo_name go in the
- main object file, rather than the dwo, similar to the force_direct
- parameter elsewhere but with additional complications:
- 1) The string is needed in both the main object file and the dwo.
- That is, the comp_dir and dwo_name will appear in both places.
- 2) Strings can use three forms: DW_FORM_string, DW_FORM_strp or
- DW_FORM_GNU_str_index.
- 3) GCC chooses the form to use late, depending on the size and
- reference count.
- Rather than forcing the all debug string handling functions and
- callers to deal with these complications, simply use a separate,
- special-cased string table for any attribute that should go in the
- main object file. This limits the complexity to just the places
- that need it. */
- static GTY (()) hash_table<indirect_string_hasher> *skeleton_debug_str_hash;
- static GTY(()) int dw2_string_counter;
- /* True if the compilation unit places functions in more than one section. */
- static GTY(()) bool have_multiple_function_sections = false;
- /* Whether the default text and cold text sections have been used at all. */
- static GTY(()) bool text_section_used = false;
- static GTY(()) bool cold_text_section_used = false;
- /* The default cold text section. */
- static GTY(()) section *cold_text_section;
- /* The DIE for C++14 'auto' in a function return type. */
- static GTY(()) dw_die_ref auto_die;
- /* The DIE for C++14 'decltype(auto)' in a function return type. */
- static GTY(()) dw_die_ref decltype_auto_die;
- /* Forward declarations for functions defined in this file. */
- static char *stripattributes (const char *);
- static void output_call_frame_info (int);
- static void dwarf2out_note_section_used (void);
- /* Personality decl of current unit. Used only when assembler does not support
- personality CFI. */
- static GTY(()) rtx current_unit_personality;
- /* Data and reference forms for relocatable data. */
- #define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4)
- #define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4)
- #ifndef DEBUG_FRAME_SECTION
- #define DEBUG_FRAME_SECTION ".debug_frame"
- #endif
- #ifndef FUNC_BEGIN_LABEL
- #define FUNC_BEGIN_LABEL "LFB"
- #endif
- #ifndef FUNC_END_LABEL
- #define FUNC_END_LABEL "LFE"
- #endif
- #ifndef PROLOGUE_END_LABEL
- #define PROLOGUE_END_LABEL "LPE"
- #endif
- #ifndef EPILOGUE_BEGIN_LABEL
- #define EPILOGUE_BEGIN_LABEL "LEB"
- #endif
- #ifndef FRAME_BEGIN_LABEL
- #define FRAME_BEGIN_LABEL "Lframe"
- #endif
- #define CIE_AFTER_SIZE_LABEL "LSCIE"
- #define CIE_END_LABEL "LECIE"
- #define FDE_LABEL "LSFDE"
- #define FDE_AFTER_SIZE_LABEL "LASFDE"
- #define FDE_END_LABEL "LEFDE"
- #define LINE_NUMBER_BEGIN_LABEL "LSLT"
- #define LINE_NUMBER_END_LABEL "LELT"
- #define LN_PROLOG_AS_LABEL "LASLTP"
- #define LN_PROLOG_END_LABEL "LELTP"
- #define DIE_LABEL_PREFIX "DW"
- /* Match the base name of a file to the base name of a compilation unit. */
- static int
- matches_main_base (const char *path)
- {
- /* Cache the last query. */
- static const char *last_path = NULL;
- static int last_match = 0;
- if (path != last_path)
- {
- const char *base;
- int length = base_of_path (path, &base);
- last_path = path;
- last_match = (length == main_input_baselength
- && memcmp (base, main_input_basename, length) == 0);
- }
- return last_match;
- }
- #ifdef DEBUG_DEBUG_STRUCT
- static int
- dump_struct_debug (tree type, enum debug_info_usage usage,
- enum debug_struct_file criterion, int generic,
- int matches, int result)
- {
- /* Find the type name. */
- tree type_decl = TYPE_STUB_DECL (type);
- tree t = type_decl;
- const char *name = 0;
- if (TREE_CODE (t) == TYPE_DECL)
- t = DECL_NAME (t);
- if (t)
- name = IDENTIFIER_POINTER (t);
- fprintf (stderr, " struct %d %s %s %s %s %d %p %s\n",
- criterion,
- DECL_IN_SYSTEM_HEADER (type_decl) ? "sys" : "usr",
- matches ? "bas" : "hdr",
- generic ? "gen" : "ord",
- usage == DINFO_USAGE_DFN ? ";" :
- usage == DINFO_USAGE_DIR_USE ? "." : "*",
- result,
- (void*) type_decl, name);
- return result;
- }
- #define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
- dump_struct_debug (type, usage, criterion, generic, matches, result)
- #else
- #define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
- (result)
- #endif
- /* Get the number of HOST_WIDE_INTs needed to represent the precision
- of the number. */
- static unsigned int
- get_full_len (const wide_int &op)
- {
- return ((op.get_precision () + HOST_BITS_PER_WIDE_INT - 1)
- / HOST_BITS_PER_WIDE_INT);
- }
- static bool
- should_emit_struct_debug (tree type, enum debug_info_usage usage)
- {
- enum debug_struct_file criterion;
- tree type_decl;
- bool generic = lang_hooks.types.generic_p (type);
- if (generic)
- criterion = debug_struct_generic[usage];
- else
- criterion = debug_struct_ordinary[usage];
- if (criterion == DINFO_STRUCT_FILE_NONE)
- return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
- if (criterion == DINFO_STRUCT_FILE_ANY)
- return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
- type_decl = TYPE_STUB_DECL (TYPE_MAIN_VARIANT (type));
- if (type_decl != NULL)
- {
- if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl))
- return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
- if (matches_main_base (DECL_SOURCE_FILE (type_decl)))
- return DUMP_GSTRUCT (type, usage, criterion, generic, true, true);
- }
- return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
- }
- /* Return a pointer to a copy of the section string name S with all
- attributes stripped off, and an asterisk prepended (for assemble_name). */
- static inline char *
- stripattributes (const char *s)
- {
- char *stripped = XNEWVEC (char, strlen (s) + 2);
- char *p = stripped;
- *p++ = '*';
- while (*s && *s != ',')
- *p++ = *s++;
- *p = '\0';
- return stripped;
- }
- /* Switch [BACK] to eh_frame_section. If we don't have an eh_frame_section,
- switch to the data section instead, and write out a synthetic start label
- for collect2 the first time around. */
- static void
- switch_to_eh_frame_section (bool back)
- {
- tree label;
- #ifdef EH_FRAME_SECTION_NAME
- if (eh_frame_section == 0)
- {
- int flags;
- if (EH_TABLES_CAN_BE_READ_ONLY)
- {
- int fde_encoding;
- int per_encoding;
- int lsda_encoding;
- fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1,
- /*global=*/0);
- per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2,
- /*global=*/1);
- lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0,
- /*global=*/0);
- flags = ((! flag_pic
- || ((fde_encoding & 0x70) != DW_EH_PE_absptr
- && (fde_encoding & 0x70) != DW_EH_PE_aligned
- && (per_encoding & 0x70) != DW_EH_PE_absptr
- && (per_encoding & 0x70) != DW_EH_PE_aligned
- && (lsda_encoding & 0x70) != DW_EH_PE_absptr
- && (lsda_encoding & 0x70) != DW_EH_PE_aligned))
- ? 0 : SECTION_WRITE);
- }
- else
- flags = SECTION_WRITE;
- eh_frame_section = get_section (EH_FRAME_SECTION_NAME, flags, NULL);
- }
- #endif /* EH_FRAME_SECTION_NAME */
- if (eh_frame_section)
- switch_to_section (eh_frame_section);
- else
- {
- /* We have no special eh_frame section. Put the information in
- the data section and emit special labels to guide collect2. */
- switch_to_section (data_section);
- if (!back)
- {
- label = get_file_function_name ("F");
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
- targetm.asm_out.globalize_label (asm_out_file,
- IDENTIFIER_POINTER (label));
- ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
- }
- }
- }
- /* Switch [BACK] to the eh or debug frame table section, depending on
- FOR_EH. */
- static void
- switch_to_frame_table_section (int for_eh, bool back)
- {
- if (for_eh)
- switch_to_eh_frame_section (back);
- else
- {
- if (!debug_frame_section)
- debug_frame_section = get_section (DEBUG_FRAME_SECTION,
- SECTION_DEBUG, NULL);
- switch_to_section (debug_frame_section);
- }
- }
- /* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used. */
- enum dw_cfi_oprnd_type
- dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
- {
- switch (cfi)
- {
- case DW_CFA_nop:
- case DW_CFA_GNU_window_save:
- case DW_CFA_remember_state:
- case DW_CFA_restore_state:
- return dw_cfi_oprnd_unused;
- case DW_CFA_set_loc:
- case DW_CFA_advance_loc1:
- case DW_CFA_advance_loc2:
- case DW_CFA_advance_loc4:
- case DW_CFA_MIPS_advance_loc8:
- return dw_cfi_oprnd_addr;
- case DW_CFA_offset:
- case DW_CFA_offset_extended:
- case DW_CFA_def_cfa:
- case DW_CFA_offset_extended_sf:
- case DW_CFA_def_cfa_sf:
- case DW_CFA_restore:
- case DW_CFA_restore_extended:
- case DW_CFA_undefined:
- case DW_CFA_same_value:
- case DW_CFA_def_cfa_register:
- case DW_CFA_register:
- case DW_CFA_expression:
- return dw_cfi_oprnd_reg_num;
- case DW_CFA_def_cfa_offset:
- case DW_CFA_GNU_args_size:
- case DW_CFA_def_cfa_offset_sf:
- return dw_cfi_oprnd_offset;
- case DW_CFA_def_cfa_expression:
- return dw_cfi_oprnd_loc;
- default:
- gcc_unreachable ();
- }
- }
- /* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used. */
- enum dw_cfi_oprnd_type
- dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
- {
- switch (cfi)
- {
- case DW_CFA_def_cfa:
- case DW_CFA_def_cfa_sf:
- case DW_CFA_offset:
- case DW_CFA_offset_extended_sf:
- case DW_CFA_offset_extended:
- return dw_cfi_oprnd_offset;
- case DW_CFA_register:
- return dw_cfi_oprnd_reg_num;
- case DW_CFA_expression:
- return dw_cfi_oprnd_loc;
- default:
- return dw_cfi_oprnd_unused;
- }
- }
- /* Output one FDE. */
- static void
- output_fde (dw_fde_ref fde, bool for_eh, bool second,
- char *section_start_label, int fde_encoding, char *augmentation,
- bool any_lsda_needed, int lsda_encoding)
- {
- const char *begin, *end;
- static unsigned int j;
- char l1[20], l2[20];
- targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, for_eh,
- /* empty */ 0);
- targetm.asm_out.internal_label (asm_out_file, FDE_LABEL,
- for_eh + j);
- ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + j);
- ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + j);
- if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
- dw2_asm_output_data (4, 0xffffffff, "Initial length escape value"
- " indicating 64-bit DWARF extension");
- dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
- "FDE Length");
- ASM_OUTPUT_LABEL (asm_out_file, l1);
- if (for_eh)
- dw2_asm_output_delta (4, l1, section_start_label, "FDE CIE offset");
- else
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label,
- debug_frame_section, "FDE CIE offset");
- begin = second ? fde->dw_fde_second_begin : fde->dw_fde_begin;
- end = second ? fde->dw_fde_second_end : fde->dw_fde_end;
- if (for_eh)
- {
- rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, begin);
- SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
- dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref, false,
- "FDE initial location");
- dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
- end, begin, "FDE address range");
- }
- else
- {
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, begin, "FDE initial location");
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, end, begin, "FDE address range");
- }
- if (augmentation[0])
- {
- if (any_lsda_needed)
- {
- int size = size_of_encoded_value (lsda_encoding);
- if (lsda_encoding == DW_EH_PE_aligned)
- {
- int offset = ( 4 /* Length */
- + 4 /* CIE offset */
- + 2 * size_of_encoded_value (fde_encoding)
- + 1 /* Augmentation size */ );
- int pad = -offset & (PTR_SIZE - 1);
- size += pad;
- gcc_assert (size_of_uleb128 (size) == 1);
- }
- dw2_asm_output_data_uleb128 (size, "Augmentation size");
- if (fde->uses_eh_lsda)
- {
- ASM_GENERATE_INTERNAL_LABEL (l1, second ? "LLSDAC" : "LLSDA",
- fde->funcdef_number);
- dw2_asm_output_encoded_addr_rtx (lsda_encoding,
- gen_rtx_SYMBOL_REF (Pmode, l1),
- false,
- "Language Specific Data Area");
- }
- else
- {
- if (lsda_encoding == DW_EH_PE_aligned)
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
- dw2_asm_output_data (size_of_encoded_value (lsda_encoding), 0,
- "Language Specific Data Area (none)");
- }
- }
- else
- dw2_asm_output_data_uleb128 (0, "Augmentation size");
- }
- /* Loop through the Call Frame Instructions associated with this FDE. */
- fde->dw_fde_current_label = begin;
- {
- size_t from, until, i;
- from = 0;
- until = vec_safe_length (fde->dw_fde_cfi);
- if (fde->dw_fde_second_begin == NULL)
- ;
- else if (!second)
- until = fde->dw_fde_switch_cfi_index;
- else
- from = fde->dw_fde_switch_cfi_index;
- for (i = from; i < until; i++)
- output_cfi ((*fde->dw_fde_cfi)[i], fde, for_eh);
- }
- /* If we are to emit a ref/link from function bodies to their frame tables,
- do it now. This is typically performed to make sure that tables
- associated with functions are dragged with them and not discarded in
- garbage collecting links. We need to do this on a per function basis to
- cope with -ffunction-sections. */
- #ifdef ASM_OUTPUT_DWARF_TABLE_REF
- /* Switch to the function section, emit the ref to the tables, and
- switch *back* into the table section. */
- switch_to_section (function_section (fde->decl));
- ASM_OUTPUT_DWARF_TABLE_REF (section_start_label);
- switch_to_frame_table_section (for_eh, true);
- #endif
- /* Pad the FDE out to an address sized boundary. */
- ASM_OUTPUT_ALIGN (asm_out_file,
- floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
- ASM_OUTPUT_LABEL (asm_out_file, l2);
- j += 2;
- }
- /* Return true if frame description entry FDE is needed for EH. */
- static bool
- fde_needed_for_eh_p (dw_fde_ref fde)
- {
- if (flag_asynchronous_unwind_tables)
- return true;
- if (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde->decl))
- return true;
- if (fde->uses_eh_lsda)
- return true;
- /* If exceptions are enabled, we have collected nothrow info. */
- if (flag_exceptions && (fde->all_throwers_are_sibcalls || fde->nothrow))
- return false;
- return true;
- }
- /* Output the call frame information used to record information
- that relates to calculating the frame pointer, and records the
- location of saved registers. */
- static void
- output_call_frame_info (int for_eh)
- {
- unsigned int i;
- dw_fde_ref fde;
- dw_cfi_ref cfi;
- char l1[20], l2[20], section_start_label[20];
- bool any_lsda_needed = false;
- char augmentation[6];
- int augmentation_size;
- int fde_encoding = DW_EH_PE_absptr;
- int per_encoding = DW_EH_PE_absptr;
- int lsda_encoding = DW_EH_PE_absptr;
- int return_reg;
- rtx personality = NULL;
- int dw_cie_version;
- /* Don't emit a CIE if there won't be any FDEs. */
- if (!fde_vec)
- return;
- /* Nothing to do if the assembler's doing it all. */
- if (dwarf2out_do_cfi_asm ())
- return;
- /* If we don't have any functions we'll want to unwind out of, don't emit
- any EH unwind information. If we make FDEs linkonce, we may have to
- emit an empty label for an FDE that wouldn't otherwise be emitted. We
- want to avoid having an FDE kept around when the function it refers to
- is discarded. Example where this matters: a primary function template
- in C++ requires EH information, an explicit specialization doesn't. */
- if (for_eh)
- {
- bool any_eh_needed = false;
- FOR_EACH_VEC_ELT (*fde_vec, i, fde)
- {
- if (fde->uses_eh_lsda)
- any_eh_needed = any_lsda_needed = true;
- else if (fde_needed_for_eh_p (fde))
- any_eh_needed = true;
- else if (TARGET_USES_WEAK_UNWIND_INFO)
- targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, 1, 1);
- }
- if (!any_eh_needed)
- return;
- }
- /* We're going to be generating comments, so turn on app. */
- if (flag_debug_asm)
- app_enable ();
- /* Switch to the proper frame section, first time. */
- switch_to_frame_table_section (for_eh, false);
- ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
- ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
- /* Output the CIE. */
- ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
- ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
- if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
- dw2_asm_output_data (4, 0xffffffff,
- "Initial length escape value indicating 64-bit DWARF extension");
- dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
- "Length of Common Information Entry");
- ASM_OUTPUT_LABEL (asm_out_file, l1);
- /* Now that the CIE pointer is PC-relative for EH,
- use 0 to identify the CIE. */
- dw2_asm_output_data ((for_eh ? 4 : DWARF_OFFSET_SIZE),
- (for_eh ? 0 : DWARF_CIE_ID),
- "CIE Identifier Tag");
- /* Use the CIE version 3 for DWARF3; allow DWARF2 to continue to
- use CIE version 1, unless that would produce incorrect results
- due to overflowing the return register column. */
- return_reg = DWARF2_FRAME_REG_OUT (DWARF_FRAME_RETURN_COLUMN, for_eh);
- dw_cie_version = 1;
- if (return_reg >= 256 || dwarf_version > 2)
- dw_cie_version = 3;
- dw2_asm_output_data (1, dw_cie_version, "CIE Version");
- augmentation[0] = 0;
- augmentation_size = 0;
- personality = current_unit_personality;
- if (for_eh)
- {
- char *p;
- /* Augmentation:
- z Indicates that a uleb128 is present to size the
- augmentation section.
- L Indicates the encoding (and thus presence) of
- an LSDA pointer in the FDE augmentation.
- R Indicates a non-default pointer encoding for
- FDE code pointers.
- P Indicates the presence of an encoding + language
- personality routine in the CIE augmentation. */
- fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
- per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
- lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
- p = augmentation + 1;
- if (personality)
- {
- *p++ = 'P';
- augmentation_size += 1 + size_of_encoded_value (per_encoding);
- assemble_external_libcall (personality);
- }
- if (any_lsda_needed)
- {
- *p++ = 'L';
- augmentation_size += 1;
- }
- if (fde_encoding != DW_EH_PE_absptr)
- {
- *p++ = 'R';
- augmentation_size += 1;
- }
- if (p > augmentation + 1)
- {
- augmentation[0] = 'z';
- *p = '\0';
- }
- /* Ug. Some platforms can't do unaligned dynamic relocations at all. */
- if (personality && per_encoding == DW_EH_PE_aligned)
- {
- int offset = ( 4 /* Length */
- + 4 /* CIE Id */
- + 1 /* CIE version */
- + strlen (augmentation) + 1 /* Augmentation */
- + size_of_uleb128 (1) /* Code alignment */
- + size_of_sleb128 (DWARF_CIE_DATA_ALIGNMENT)
- + 1 /* RA column */
- + 1 /* Augmentation size */
- + 1 /* Personality encoding */ );
- int pad = -offset & (PTR_SIZE - 1);
- augmentation_size += pad;
- /* Augmentations should be small, so there's scarce need to
- iterate for a solution. Die if we exceed one uleb128 byte. */
- gcc_assert (size_of_uleb128 (augmentation_size) == 1);
- }
- }
- dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation");
- if (dw_cie_version >= 4)
- {
- dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "CIE Address Size");
- dw2_asm_output_data (1, 0, "CIE Segment Size");
- }
- dw2_asm_output_data_uleb128 (1, "CIE Code Alignment Factor");
- dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT,
- "CIE Data Alignment Factor");
- if (dw_cie_version == 1)
- dw2_asm_output_data (1, return_reg, "CIE RA Column");
- else
- dw2_asm_output_data_uleb128 (return_reg, "CIE RA Column");
- if (augmentation[0])
- {
- dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
- if (personality)
- {
- dw2_asm_output_data (1, per_encoding, "Personality (%s)",
- eh_data_format_name (per_encoding));
- dw2_asm_output_encoded_addr_rtx (per_encoding,
- personality,
- true, NULL);
- }
- if (any_lsda_needed)
- dw2_asm_output_data (1, lsda_encoding, "LSDA Encoding (%s)",
- eh_data_format_name (lsda_encoding));
- if (fde_encoding != DW_EH_PE_absptr)
- dw2_asm_output_data (1, fde_encoding, "FDE Encoding (%s)",
- eh_data_format_name (fde_encoding));
- }
- FOR_EACH_VEC_ELT (*cie_cfi_vec, i, cfi)
- output_cfi (cfi, NULL, for_eh);
- /* Pad the CIE out to an address sized boundary. */
- ASM_OUTPUT_ALIGN (asm_out_file,
- floor_log2 (for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE));
- ASM_OUTPUT_LABEL (asm_out_file, l2);
- /* Loop through all of the FDE's. */
- FOR_EACH_VEC_ELT (*fde_vec, i, fde)
- {
- unsigned int k;
- /* Don't emit EH unwind info for leaf functions that don't need it. */
- if (for_eh && !fde_needed_for_eh_p (fde))
- continue;
- for (k = 0; k < (fde->dw_fde_second_begin ? 2 : 1); k++)
- output_fde (fde, for_eh, k, section_start_label, fde_encoding,
- augmentation, any_lsda_needed, lsda_encoding);
- }
- if (for_eh && targetm.terminate_dw2_eh_frame_info)
- dw2_asm_output_data (4, 0, "End of Table");
- /* Turn off app to make assembly quicker. */
- if (flag_debug_asm)
- app_disable ();
- }
- /* Emit .cfi_startproc and .cfi_personality/.cfi_lsda if needed. */
- static void
- dwarf2out_do_cfi_startproc (bool second)
- {
- int enc;
- rtx ref;
- rtx personality = get_personality_function (current_function_decl);
- fprintf (asm_out_file, "\t.cfi_startproc\n");
- if (personality)
- {
- enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
- ref = personality;
- /* ??? The GAS support isn't entirely consistent. We have to
- handle indirect support ourselves, but PC-relative is done
- in the assembler. Further, the assembler can't handle any
- of the weirder relocation types. */
- if (enc & DW_EH_PE_indirect)
- ref = dw2_force_const_mem (ref, true);
- fprintf (asm_out_file, "\t.cfi_personality %#x,", enc);
- output_addr_const (asm_out_file, ref);
- fputc ('\n', asm_out_file);
- }
- if (crtl->uses_eh_lsda)
- {
- char lab[20];
- enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
- ASM_GENERATE_INTERNAL_LABEL (lab, second ? "LLSDAC" : "LLSDA",
- current_function_funcdef_no);
- ref = gen_rtx_SYMBOL_REF (Pmode, lab);
- SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL;
- if (enc & DW_EH_PE_indirect)
- ref = dw2_force_const_mem (ref, true);
- fprintf (asm_out_file, "\t.cfi_lsda %#x,", enc);
- output_addr_const (asm_out_file, ref);
- fputc ('\n', asm_out_file);
- }
- }
- /* Allocate CURRENT_FDE. Immediately initialize all we can, noting that
- this allocation may be done before pass_final. */
- dw_fde_ref
- dwarf2out_alloc_current_fde (void)
- {
- dw_fde_ref fde;
- fde = ggc_cleared_alloc<dw_fde_node> ();
- fde->decl = current_function_decl;
- fde->funcdef_number = current_function_funcdef_no;
- fde->fde_index = vec_safe_length (fde_vec);
- fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls;
- fde->uses_eh_lsda = crtl->uses_eh_lsda;
- fde->nothrow = crtl->nothrow;
- fde->drap_reg = INVALID_REGNUM;
- fde->vdrap_reg = INVALID_REGNUM;
- /* Record the FDE associated with this function. */
- cfun->fde = fde;
- vec_safe_push (fde_vec, fde);
- return fde;
- }
- /* Output a marker (i.e. a label) for the beginning of a function, before
- the prologue. */
- void
- dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
- const char *file ATTRIBUTE_UNUSED)
- {
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- char * dup_label;
- dw_fde_ref fde;
- section *fnsec;
- bool do_frame;
- current_function_func_begin_label = NULL;
- do_frame = dwarf2out_do_frame ();
- /* ??? current_function_func_begin_label is also used by except.c for
- call-site information. We must emit this label if it might be used. */
- if (!do_frame
- && (!flag_exceptions
- || targetm_common.except_unwind_info (&global_options) == UI_SJLJ))
- return;
- fnsec = function_section (current_function_decl);
- switch_to_section (fnsec);
- ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
- current_function_funcdef_no);
- ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
- current_function_funcdef_no);
- dup_label = xstrdup (label);
- current_function_func_begin_label = dup_label;
- /* We can elide the fde allocation if we're not emitting debug info. */
- if (!do_frame)
- return;
- /* Cater to the various TARGET_ASM_OUTPUT_MI_THUNK implementations that
- emit insns as rtx but bypass the bulk of rest_of_compilation, which
- would include pass_dwarf2_frame. If we've not created the FDE yet,
- do so now. */
- fde = cfun->fde;
- if (fde == NULL)
- fde = dwarf2out_alloc_current_fde ();
- /* Initialize the bits of CURRENT_FDE that were not available earlier. */
- fde->dw_fde_begin = dup_label;
- fde->dw_fde_current_label = dup_label;
- fde->in_std_section = (fnsec == text_section
- || (cold_text_section && fnsec == cold_text_section));
- /* We only want to output line number information for the genuine dwarf2
- prologue case, not the eh frame case. */
- #ifdef DWARF2_DEBUGGING_INFO
- if (file)
- dwarf2out_source_line (line, file, 0, true);
- #endif
- if (dwarf2out_do_cfi_asm ())
- dwarf2out_do_cfi_startproc (false);
- else
- {
- rtx personality = get_personality_function (current_function_decl);
- if (!current_unit_personality)
- current_unit_personality = personality;
- /* We cannot keep a current personality per function as without CFI
- asm, at the point where we emit the CFI data, there is no current
- function anymore. */
- if (personality && current_unit_personality != personality)
- sorry ("multiple EH personalities are supported only with assemblers "
- "supporting .cfi_personality directive");
- }
- }
- /* Output a marker (i.e. a label) for the end of the generated code
- for a function prologue. This gets called *after* the prologue code has
- been generated. */
- void
- dwarf2out_vms_end_prologue (unsigned int line ATTRIBUTE_UNUSED,
- const char *file ATTRIBUTE_UNUSED)
- {
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- /* Output a label to mark the endpoint of the code generated for this
- function. */
- ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
- current_function_funcdef_no);
- ASM_OUTPUT_DEBUG_LABEL (asm_out_file, PROLOGUE_END_LABEL,
- current_function_funcdef_no);
- cfun->fde->dw_fde_vms_end_prologue = xstrdup (label);
- }
- /* Output a marker (i.e. a label) for the beginning of the generated code
- for a function epilogue. This gets called *before* the prologue code has
- been generated. */
- void
- dwarf2out_vms_begin_epilogue (unsigned int line ATTRIBUTE_UNUSED,
- const char *file ATTRIBUTE_UNUSED)
- {
- dw_fde_ref fde = cfun->fde;
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- if (fde->dw_fde_vms_begin_epilogue)
- return;
- /* Output a label to mark the endpoint of the code generated for this
- function. */
- ASM_GENERATE_INTERNAL_LABEL (label, EPILOGUE_BEGIN_LABEL,
- current_function_funcdef_no);
- ASM_OUTPUT_DEBUG_LABEL (asm_out_file, EPILOGUE_BEGIN_LABEL,
- current_function_funcdef_no);
- fde->dw_fde_vms_begin_epilogue = xstrdup (label);
- }
- /* Output a marker (i.e. a label) for the absolute end of the generated code
- for a function definition. This gets called *after* the epilogue code has
- been generated. */
- void
- dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
- const char *file ATTRIBUTE_UNUSED)
- {
- dw_fde_ref fde;
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- last_var_location_insn = NULL;
- cached_next_real_insn = NULL;
- if (dwarf2out_do_cfi_asm ())
- fprintf (asm_out_file, "\t.cfi_endproc\n");
- /* Output a label to mark the endpoint of the code generated for this
- function. */
- ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL,
- current_function_funcdef_no);
- ASM_OUTPUT_LABEL (asm_out_file, label);
- fde = cfun->fde;
- gcc_assert (fde != NULL);
- if (fde->dw_fde_second_begin == NULL)
- fde->dw_fde_end = xstrdup (label);
- }
- void
- dwarf2out_frame_finish (void)
- {
- /* Output call frame information. */
- if (targetm.debug_unwind_info () == UI_DWARF2)
- output_call_frame_info (0);
- /* Output another copy for the unwinder. */
- if ((flag_unwind_tables || flag_exceptions)
- && targetm_common.except_unwind_info (&global_options) == UI_DWARF2)
- output_call_frame_info (1);
- }
- /* Note that the current function section is being used for code. */
- static void
- dwarf2out_note_section_used (void)
- {
- section *sec = current_function_section ();
- if (sec == text_section)
- text_section_used = true;
- else if (sec == cold_text_section)
- cold_text_section_used = true;
- }
- static void var_location_switch_text_section (void);
- static void set_cur_line_info_table (section *);
- void
- dwarf2out_switch_text_section (void)
- {
- section *sect;
- dw_fde_ref fde = cfun->fde;
- gcc_assert (cfun && fde && fde->dw_fde_second_begin == NULL);
- if (!in_cold_section_p)
- {
- fde->dw_fde_end = crtl->subsections.cold_section_end_label;
- fde->dw_fde_second_begin = crtl->subsections.hot_section_label;
- fde->dw_fde_second_end = crtl->subsections.hot_section_end_label;
- }
- else
- {
- fde->dw_fde_end = crtl->subsections.hot_section_end_label;
- fde->dw_fde_second_begin = crtl->subsections.cold_section_label;
- fde->dw_fde_second_end = crtl->subsections.cold_section_end_label;
- }
- have_multiple_function_sections = true;
- /* There is no need to mark used sections when not debugging. */
- if (cold_text_section != NULL)
- dwarf2out_note_section_used ();
- if (dwarf2out_do_cfi_asm ())
- fprintf (asm_out_file, "\t.cfi_endproc\n");
- /* Now do the real section switch. */
- sect = current_function_section ();
- switch_to_section (sect);
- fde->second_in_std_section
- = (sect == text_section
- || (cold_text_section && sect == cold_text_section));
- if (dwarf2out_do_cfi_asm ())
- dwarf2out_do_cfi_startproc (true);
- var_location_switch_text_section ();
- if (cold_text_section != NULL)
- set_cur_line_info_table (sect);
- }
- /* And now, the subset of the debugging information support code necessary
- for emitting location expressions. */
- /* Data about a single source file. */
- struct GTY((for_user)) dwarf_file_data {
- const char * filename;
- int emitted_number;
- };
- typedef struct GTY(()) deferred_locations_struct
- {
- tree variable;
- dw_die_ref die;
- } deferred_locations;
- static GTY(()) vec<deferred_locations, va_gc> *deferred_locations_list;
- /* Describe an entry into the .debug_addr section. */
- enum ate_kind {
- ate_kind_rtx,
- ate_kind_rtx_dtprel,
- ate_kind_label
- };
- typedef struct GTY((for_user)) addr_table_entry_struct {
- enum ate_kind kind;
- unsigned int refcount;
- unsigned int index;
- union addr_table_entry_struct_union
- {
- rtx GTY ((tag ("0"))) rtl;
- char * GTY ((tag ("1"))) label;
- }
- GTY ((desc ("%1.kind"))) addr;
- }
- addr_table_entry;
- /* Location lists are ranges + location descriptions for that range,
- so you can track variables that are in different places over
- their entire life. */
- typedef struct GTY(()) dw_loc_list_struct {
- dw_loc_list_ref dw_loc_next;
- const char *begin; /* Label and addr_entry for start of range */
- addr_table_entry *begin_entry;
- const char *end; /* Label for end of range */
- char *ll_symbol; /* Label for beginning of location list.
- Only on head of list */
- const char *section; /* Section this loclist is relative to */
- dw_loc_descr_ref expr;
- hashval_t hash;
- /* True if all addresses in this and subsequent lists are known to be
- resolved. */
- bool resolved_addr;
- /* True if this list has been replaced by dw_loc_next. */
- bool replaced;
- bool emitted;
- /* True if the range should be emitted even if begin and end
- are the same. */
- bool force;
- } dw_loc_list_node;
- static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
- /* Convert a DWARF stack opcode into its string name. */
- static const char *
- dwarf_stack_op_name (unsigned int op)
- {
- const char *name = get_DW_OP_name (op);
- if (name != NULL)
- return name;
- return "OP_<unknown>";
- }
- /* Return a pointer to a newly allocated location description. Location
- descriptions are simple expression terms that can be strung
- together to form more complicated location (address) descriptions. */
- static inline dw_loc_descr_ref
- new_loc_descr (enum dwarf_location_atom op, unsigned HOST_WIDE_INT oprnd1,
- unsigned HOST_WIDE_INT oprnd2)
- {
- dw_loc_descr_ref descr = ggc_cleared_alloc<dw_loc_descr_node> ();
- descr->dw_loc_opc = op;
- descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
- descr->dw_loc_oprnd1.val_entry = NULL;
- descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
- descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
- descr->dw_loc_oprnd2.val_entry = NULL;
- descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
- return descr;
- }
- /* Return a pointer to a newly allocated location description for
- REG and OFFSET. */
- static inline dw_loc_descr_ref
- new_reg_loc_descr (unsigned int reg, unsigned HOST_WIDE_INT offset)
- {
- if (reg <= 31)
- return new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + reg),
- offset, 0);
- else
- return new_loc_descr (DW_OP_bregx, reg, offset);
- }
- /* Add a location description term to a location description expression. */
- static inline void
- add_loc_descr (dw_loc_descr_ref *list_head, dw_loc_descr_ref descr)
- {
- dw_loc_descr_ref *d;
- /* Find the end of the chain. */
- for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
- ;
- *d = descr;
- }
- /* Compare two location operands for exact equality. */
- static bool
- dw_val_equal_p (dw_val_node *a, dw_val_node *b)
- {
- if (a->val_class != b->val_class)
- return false;
- switch (a->val_class)
- {
- case dw_val_class_none:
- return true;
- case dw_val_class_addr:
- return rtx_equal_p (a->v.val_addr, b->v.val_addr);
- case dw_val_class_offset:
- case dw_val_class_unsigned_const:
- case dw_val_class_const:
- case dw_val_class_range_list:
- case dw_val_class_lineptr:
- case dw_val_class_macptr:
- /* These are all HOST_WIDE_INT, signed or unsigned. */
- return a->v.val_unsigned == b->v.val_unsigned;
- case dw_val_class_loc:
- return a->v.val_loc == b->v.val_loc;
- case dw_val_class_loc_list:
- return a->v.val_loc_list == b->v.val_loc_list;
- case dw_val_class_die_ref:
- return a->v.val_die_ref.die == b->v.val_die_ref.die;
- case dw_val_class_fde_ref:
- return a->v.val_fde_index == b->v.val_fde_index;
- case dw_val_class_lbl_id:
- case dw_val_class_high_pc:
- return strcmp (a->v.val_lbl_id, b->v.val_lbl_id) == 0;
- case dw_val_class_str:
- return a->v.val_str == b->v.val_str;
- case dw_val_class_flag:
- return a->v.val_flag == b->v.val_flag;
- case dw_val_class_file:
- return a->v.val_file == b->v.val_file;
- case dw_val_class_decl_ref:
- return a->v.val_decl_ref == b->v.val_decl_ref;
-
- case dw_val_class_const_double:
- return (a->v.val_double.high == b->v.val_double.high
- && a->v.val_double.low == b->v.val_double.low);
- case dw_val_class_wide_int:
- return *a->v.val_wide == *b->v.val_wide;
- case dw_val_class_vec:
- {
- size_t a_len = a->v.val_vec.elt_size * a->v.val_vec.length;
- size_t b_len = b->v.val_vec.elt_size * b->v.val_vec.length;
- return (a_len == b_len
- && !memcmp (a->v.val_vec.array, b->v.val_vec.array, a_len));
- }
- case dw_val_class_data8:
- return memcmp (a->v.val_data8, b->v.val_data8, 8) == 0;
- case dw_val_class_vms_delta:
- return (!strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)
- && !strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1));
- }
- gcc_unreachable ();
- }
- /* Compare two location atoms for exact equality. */
- static bool
- loc_descr_equal_p_1 (dw_loc_descr_ref a, dw_loc_descr_ref b)
- {
- if (a->dw_loc_opc != b->dw_loc_opc)
- return false;
- /* ??? This is only ever set for DW_OP_constNu, for N equal to the
- address size, but since we always allocate cleared storage it
- should be zero for other types of locations. */
- if (a->dtprel != b->dtprel)
- return false;
- return (dw_val_equal_p (&a->dw_loc_oprnd1, &b->dw_loc_oprnd1)
- && dw_val_equal_p (&a->dw_loc_oprnd2, &b->dw_loc_oprnd2));
- }
- /* Compare two complete location expressions for exact equality. */
- bool
- loc_descr_equal_p (dw_loc_descr_ref a, dw_loc_descr_ref b)
- {
- while (1)
- {
- if (a == b)
- return true;
- if (a == NULL || b == NULL)
- return false;
- if (!loc_descr_equal_p_1 (a, b))
- return false;
- a = a->dw_loc_next;
- b = b->dw_loc_next;
- }
- }
- /* Add a constant OFFSET to a location expression. */
- static void
- loc_descr_plus_const (dw_loc_descr_ref *list_head, HOST_WIDE_INT offset)
- {
- dw_loc_descr_ref loc;
- HOST_WIDE_INT *p;
- gcc_assert (*list_head != NULL);
- if (!offset)
- return;
- /* Find the end of the chain. */
- for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
- ;
- p = NULL;
- if (loc->dw_loc_opc == DW_OP_fbreg
- || (loc->dw_loc_opc >= DW_OP_breg0 && loc->dw_loc_opc <= DW_OP_breg31))
- p = &loc->dw_loc_oprnd1.v.val_int;
- else if (loc->dw_loc_opc == DW_OP_bregx)
- p = &loc->dw_loc_oprnd2.v.val_int;
- /* If the last operation is fbreg, breg{0..31,x}, optimize by adjusting its
- offset. Don't optimize if an signed integer overflow would happen. */
- if (p != NULL
- && ((offset > 0 && *p <= INTTYPE_MAXIMUM (HOST_WIDE_INT) - offset)
- || (offset < 0 && *p >= INTTYPE_MINIMUM (HOST_WIDE_INT) - offset)))
- *p += offset;
- else if (offset > 0)
- loc->dw_loc_next = new_loc_descr (DW_OP_plus_uconst, offset, 0);
- else
- {
- loc->dw_loc_next = int_loc_descriptor (-offset);
- add_loc_descr (&loc->dw_loc_next, new_loc_descr (DW_OP_minus, 0, 0));
- }
- }
- /* Add a constant OFFSET to a location list. */
- static void
- loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset)
- {
- dw_loc_list_ref d;
- for (d = list_head; d != NULL; d = d->dw_loc_next)
- loc_descr_plus_const (&d->expr, offset);
- }
- #define DWARF_REF_SIZE \
- (dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE)
- static unsigned long int get_base_type_offset (dw_die_ref);
- /* Return the size of a location descriptor. */
- static unsigned long
- size_of_loc_descr (dw_loc_descr_ref loc)
- {
- unsigned long size = 1;
- switch (loc->dw_loc_opc)
- {
- case DW_OP_addr:
- size += DWARF2_ADDR_SIZE;
- break;
- case DW_OP_GNU_addr_index:
- case DW_OP_GNU_const_index:
- gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED);
- size += size_of_uleb128 (loc->dw_loc_oprnd1.val_entry->index);
- break;
- case DW_OP_const1u:
- case DW_OP_const1s:
- size += 1;
- break;
- case DW_OP_const2u:
- case DW_OP_const2s:
- size += 2;
- break;
- case DW_OP_const4u:
- case DW_OP_const4s:
- size += 4;
- break;
- case DW_OP_const8u:
- case DW_OP_const8s:
- size += 8;
- break;
- case DW_OP_constu:
- size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
- break;
- case DW_OP_consts:
- size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
- break;
- case DW_OP_pick:
- size += 1;
- break;
- case DW_OP_plus_uconst:
- size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
- break;
- case DW_OP_skip:
- case DW_OP_bra:
- size += 2;
- break;
- case DW_OP_breg0:
- case DW_OP_breg1:
- case DW_OP_breg2:
- case DW_OP_breg3:
- case DW_OP_breg4:
- case DW_OP_breg5:
- case DW_OP_breg6:
- case DW_OP_breg7:
- case DW_OP_breg8:
- case DW_OP_breg9:
- case DW_OP_breg10:
- case DW_OP_breg11:
- case DW_OP_breg12:
- case DW_OP_breg13:
- case DW_OP_breg14:
- case DW_OP_breg15:
- case DW_OP_breg16:
- case DW_OP_breg17:
- case DW_OP_breg18:
- case DW_OP_breg19:
- case DW_OP_breg20:
- case DW_OP_breg21:
- case DW_OP_breg22:
- case DW_OP_breg23:
- case DW_OP_breg24:
- case DW_OP_breg25:
- case DW_OP_breg26:
- case DW_OP_breg27:
- case DW_OP_breg28:
- case DW_OP_breg29:
- case DW_OP_breg30:
- case DW_OP_breg31:
- size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
- break;
- case DW_OP_regx:
- size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
- break;
- case DW_OP_fbreg:
- size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
- break;
- case DW_OP_bregx:
- size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
- size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
- break;
- case DW_OP_piece:
- size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
- break;
- case DW_OP_bit_piece:
- size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
- size += size_of_uleb128 (loc->dw_loc_oprnd2.v.val_unsigned);
- break;
- case DW_OP_deref_size:
- case DW_OP_xderef_size:
- size += 1;
- break;
- case DW_OP_call2:
- size += 2;
- break;
- case DW_OP_call4:
- size += 4;
- break;
- case DW_OP_call_ref:
- size += DWARF_REF_SIZE;
- break;
- case DW_OP_implicit_value:
- size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
- + loc->dw_loc_oprnd1.v.val_unsigned;
- break;
- case DW_OP_GNU_implicit_pointer:
- size += DWARF_REF_SIZE + size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
- break;
- case DW_OP_GNU_entry_value:
- {
- unsigned long op_size = size_of_locs (loc->dw_loc_oprnd1.v.val_loc);
- size += size_of_uleb128 (op_size) + op_size;
- break;
- }
- case DW_OP_GNU_const_type:
- {
- unsigned long o
- = get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die);
- size += size_of_uleb128 (o) + 1;
- switch (loc->dw_loc_oprnd2.val_class)
- {
- case dw_val_class_vec:
- size += loc->dw_loc_oprnd2.v.val_vec.length
- * loc->dw_loc_oprnd2.v.val_vec.elt_size;
- break;
- case dw_val_class_const:
- size += HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT;
- break;
- case dw_val_class_const_double:
- size += HOST_BITS_PER_DOUBLE_INT / BITS_PER_UNIT;
- break;
- case dw_val_class_wide_int:
- size += (get_full_len (*loc->dw_loc_oprnd2.v.val_wide)
- * HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT);
- break;
- default:
- gcc_unreachable ();
- }
- break;
- }
- case DW_OP_GNU_regval_type:
- {
- unsigned long o
- = get_base_type_offset (loc->dw_loc_oprnd2.v.val_die_ref.die);
- size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
- + size_of_uleb128 (o);
- }
- break;
- case DW_OP_GNU_deref_type:
- {
- unsigned long o
- = get_base_type_offset (loc->dw_loc_oprnd2.v.val_die_ref.die);
- size += 1 + size_of_uleb128 (o);
- }
- break;
- case DW_OP_GNU_convert:
- case DW_OP_GNU_reinterpret:
- if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const)
- size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
- else
- {
- unsigned long o
- = get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die);
- size += size_of_uleb128 (o);
- }
- break;
- case DW_OP_GNU_parameter_ref:
- size += 4;
- break;
- default:
- break;
- }
- return size;
- }
- /* Return the size of a series of location descriptors. */
- unsigned long
- size_of_locs (dw_loc_descr_ref loc)
- {
- dw_loc_descr_ref l;
- unsigned long size;
- /* If there are no skip or bra opcodes, don't fill in the dw_loc_addr
- field, to avoid writing to a PCH file. */
- for (size = 0, l = loc; l != NULL; l = l->dw_loc_next)
- {
- if (l->dw_loc_opc == DW_OP_skip || l->dw_loc_opc == DW_OP_bra)
- break;
- size += size_of_loc_descr (l);
- }
- if (! l)
- return size;
- for (size = 0, l = loc; l != NULL; l = l->dw_loc_next)
- {
- l->dw_loc_addr = size;
- size += size_of_loc_descr (l);
- }
- return size;
- }
- static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
- static void get_ref_die_offset_label (char *, dw_die_ref);
- static unsigned long int get_ref_die_offset (dw_die_ref);
- /* Output location description stack opcode's operands (if any).
- The for_eh_or_skip parameter controls whether register numbers are
- converted using DWARF2_FRAME_REG_OUT, which is needed in the case that
- hard reg numbers have been processed via DWARF_FRAME_REGNUM (i.e. for unwind
- info). This should be suppressed for the cases that have not been converted
- (i.e. symbolic debug info), by setting the parameter < 0. See PR47324. */
- static void
- output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
- {
- dw_val_ref val1 = &loc->dw_loc_oprnd1;
- dw_val_ref val2 = &loc->dw_loc_oprnd2;
- switch (loc->dw_loc_opc)
- {
- #ifdef DWARF2_DEBUGGING_INFO
- case DW_OP_const2u:
- case DW_OP_const2s:
- dw2_asm_output_data (2, val1->v.val_int, NULL);
- break;
- case DW_OP_const4u:
- if (loc->dtprel)
- {
- gcc_assert (targetm.asm_out.output_dwarf_dtprel);
- targetm.asm_out.output_dwarf_dtprel (asm_out_file, 4,
- val1->v.val_addr);
- fputc ('\n', asm_out_file);
- break;
- }
- /* FALLTHRU */
- case DW_OP_const4s:
- dw2_asm_output_data (4, val1->v.val_int, NULL);
- break;
- case DW_OP_const8u:
- if (loc->dtprel)
- {
- gcc_assert (targetm.asm_out.output_dwarf_dtprel);
- targetm.asm_out.output_dwarf_dtprel (asm_out_file, 8,
- val1->v.val_addr);
- fputc ('\n', asm_out_file);
- break;
- }
- /* FALLTHRU */
- case DW_OP_const8s:
- gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
- dw2_asm_output_data (8, val1->v.val_int, NULL);
- break;
- case DW_OP_skip:
- case DW_OP_bra:
- {
- int offset;
- gcc_assert (val1->val_class == dw_val_class_loc);
- offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3);
- dw2_asm_output_data (2, offset, NULL);
- }
- break;
- case DW_OP_implicit_value:
- dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
- switch (val2->val_class)
- {
- case dw_val_class_const:
- dw2_asm_output_data (val1->v.val_unsigned, val2->v.val_int, NULL);
- break;
- case dw_val_class_vec:
- {
- unsigned int elt_size = val2->v.val_vec.elt_size;
- unsigned int len = val2->v.val_vec.length;
- unsigned int i;
- unsigned char *p;
- if (elt_size > sizeof (HOST_WIDE_INT))
- {
- elt_size /= 2;
- len *= 2;
- }
- for (i = 0, p = val2->v.val_vec.array;
- i < len;
- i++, p += elt_size)
- dw2_asm_output_data (elt_size, extract_int (p, elt_size),
- "fp or vector constant word %u", i);
- }
- break;
- case dw_val_class_const_double:
- {
- unsigned HOST_WIDE_INT first, second;
- if (WORDS_BIG_ENDIAN)
- {
- first = val2->v.val_double.high;
- second = val2->v.val_double.low;
- }
- else
- {
- first = val2->v.val_double.low;
- second = val2->v.val_double.high;
- }
- dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
- first, NULL);
- dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
- second, NULL);
- }
- break;
- case dw_val_class_wide_int:
- {
- int i;
- int len = get_full_len (*val2->v.val_wide);
- if (WORDS_BIG_ENDIAN)
- for (i = len - 1; i >= 0; --i)
- dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
- val2->v.val_wide->elt (i), NULL);
- else
- for (i = 0; i < len; ++i)
- dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
- val2->v.val_wide->elt (i), NULL);
- }
- break;
- case dw_val_class_addr:
- gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
- dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val2->v.val_addr, NULL);
- break;
- default:
- gcc_unreachable ();
- }
- break;
- #else
- case DW_OP_const2u:
- case DW_OP_const2s:
- case DW_OP_const4u:
- case DW_OP_const4s:
- case DW_OP_const8u:
- case DW_OP_const8s:
- case DW_OP_skip:
- case DW_OP_bra:
- case DW_OP_implicit_value:
- /* We currently don't make any attempt to make sure these are
- aligned properly like we do for the main unwind info, so
- don't support emitting things larger than a byte if we're
- only doing unwinding. */
- gcc_unreachable ();
- #endif
- case DW_OP_const1u:
- case DW_OP_const1s:
- dw2_asm_output_data (1, val1->v.val_int, NULL);
- break;
- case DW_OP_constu:
- dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
- break;
- case DW_OP_consts:
- dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
- break;
- case DW_OP_pick:
- dw2_asm_output_data (1, val1->v.val_int, NULL);
- break;
- case DW_OP_plus_uconst:
- dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
- break;
- case DW_OP_breg0:
- case DW_OP_breg1:
- case DW_OP_breg2:
- case DW_OP_breg3:
- case DW_OP_breg4:
- case DW_OP_breg5:
- case DW_OP_breg6:
- case DW_OP_breg7:
- case DW_OP_breg8:
- case DW_OP_breg9:
- case DW_OP_breg10:
- case DW_OP_breg11:
- case DW_OP_breg12:
- case DW_OP_breg13:
- case DW_OP_breg14:
- case DW_OP_breg15:
- case DW_OP_breg16:
- case DW_OP_breg17:
- case DW_OP_breg18:
- case DW_OP_breg19:
- case DW_OP_breg20:
- case DW_OP_breg21:
- case DW_OP_breg22:
- case DW_OP_breg23:
- case DW_OP_breg24:
- case DW_OP_breg25:
- case DW_OP_breg26:
- case DW_OP_breg27:
- case DW_OP_breg28:
- case DW_OP_breg29:
- case DW_OP_breg30:
- case DW_OP_breg31:
- dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
- break;
- case DW_OP_regx:
- {
- unsigned r = val1->v.val_unsigned;
- if (for_eh_or_skip >= 0)
- r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
- gcc_assert (size_of_uleb128 (r)
- == size_of_uleb128 (val1->v.val_unsigned));
- dw2_asm_output_data_uleb128 (r, NULL);
- }
- break;
- case DW_OP_fbreg:
- dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
- break;
- case DW_OP_bregx:
- {
- unsigned r = val1->v.val_unsigned;
- if (for_eh_or_skip >= 0)
- r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
- gcc_assert (size_of_uleb128 (r)
- == size_of_uleb128 (val1->v.val_unsigned));
- dw2_asm_output_data_uleb128 (r, NULL);
- dw2_asm_output_data_sleb128 (val2->v.val_int, NULL);
- }
- break;
- case DW_OP_piece:
- dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
- break;
- case DW_OP_bit_piece:
- dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
- dw2_asm_output_data_uleb128 (val2->v.val_unsigned, NULL);
- break;
- case DW_OP_deref_size:
- case DW_OP_xderef_size:
- dw2_asm_output_data (1, val1->v.val_int, NULL);
- break;
- case DW_OP_addr:
- if (loc->dtprel)
- {
- if (targetm.asm_out.output_dwarf_dtprel)
- {
- targetm.asm_out.output_dwarf_dtprel (asm_out_file,
- DWARF2_ADDR_SIZE,
- val1->v.val_addr);
- fputc ('\n', asm_out_file);
- }
- else
- gcc_unreachable ();
- }
- else
- {
- #ifdef DWARF2_DEBUGGING_INFO
- dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val1->v.val_addr, NULL);
- #else
- gcc_unreachable ();
- #endif
- }
- break;
- case DW_OP_GNU_addr_index:
- case DW_OP_GNU_const_index:
- gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED);
- dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_entry->index,
- "(index into .debug_addr)");
- break;
- case DW_OP_GNU_implicit_pointer:
- {
- char label[MAX_ARTIFICIAL_LABEL_BYTES
- + HOST_BITS_PER_WIDE_INT / 2 + 2];
- gcc_assert (val1->val_class == dw_val_class_die_ref);
- get_ref_die_offset_label (label, val1->v.val_die_ref.die);
- dw2_asm_output_offset (DWARF_REF_SIZE, label, debug_info_section, NULL);
- dw2_asm_output_data_sleb128 (val2->v.val_int, NULL);
- }
- break;
- case DW_OP_GNU_entry_value:
- dw2_asm_output_data_uleb128 (size_of_locs (val1->v.val_loc), NULL);
- output_loc_sequence (val1->v.val_loc, for_eh_or_skip);
- break;
- case DW_OP_GNU_const_type:
- {
- unsigned long o = get_base_type_offset (val1->v.val_die_ref.die), l;
- gcc_assert (o);
- dw2_asm_output_data_uleb128 (o, NULL);
- switch (val2->val_class)
- {
- case dw_val_class_const:
- l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
- dw2_asm_output_data (1, l, NULL);
- dw2_asm_output_data (l, val2->v.val_int, NULL);
- break;
- case dw_val_class_vec:
- {
- unsigned int elt_size = val2->v.val_vec.elt_size;
- unsigned int len = val2->v.val_vec.length;
- unsigned int i;
- unsigned char *p;
- l = len * elt_size;
- dw2_asm_output_data (1, l, NULL);
- if (elt_size > sizeof (HOST_WIDE_INT))
- {
- elt_size /= 2;
- len *= 2;
- }
- for (i = 0, p = val2->v.val_vec.array;
- i < len;
- i++, p += elt_size)
- dw2_asm_output_data (elt_size, extract_int (p, elt_size),
- "fp or vector constant word %u", i);
- }
- break;
- case dw_val_class_const_double:
- {
- unsigned HOST_WIDE_INT first, second;
- l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
- dw2_asm_output_data (1, 2 * l, NULL);
- if (WORDS_BIG_ENDIAN)
- {
- first = val2->v.val_double.high;
- second = val2->v.val_double.low;
- }
- else
- {
- first = val2->v.val_double.low;
- second = val2->v.val_double.high;
- }
- dw2_asm_output_data (l, first, NULL);
- dw2_asm_output_data (l, second, NULL);
- }
- break;
- case dw_val_class_wide_int:
- {
- int i;
- int len = get_full_len (*val2->v.val_wide);
- l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
- dw2_asm_output_data (1, len * l, NULL);
- if (WORDS_BIG_ENDIAN)
- for (i = len - 1; i >= 0; --i)
- dw2_asm_output_data (l, val2->v.val_wide->elt (i), NULL);
- else
- for (i = 0; i < len; ++i)
- dw2_asm_output_data (l, val2->v.val_wide->elt (i), NULL);
- }
- break;
- default:
- gcc_unreachable ();
- }
- }
- break;
- case DW_OP_GNU_regval_type:
- {
- unsigned r = val1->v.val_unsigned;
- unsigned long o = get_base_type_offset (val2->v.val_die_ref.die);
- gcc_assert (o);
- if (for_eh_or_skip >= 0)
- {
- r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
- gcc_assert (size_of_uleb128 (r)
- == size_of_uleb128 (val1->v.val_unsigned));
- }
- dw2_asm_output_data_uleb128 (r, NULL);
- dw2_asm_output_data_uleb128 (o, NULL);
- }
- break;
- case DW_OP_GNU_deref_type:
- {
- unsigned long o = get_base_type_offset (val2->v.val_die_ref.die);
- gcc_assert (o);
- dw2_asm_output_data (1, val1->v.val_int, NULL);
- dw2_asm_output_data_uleb128 (o, NULL);
- }
- break;
- case DW_OP_GNU_convert:
- case DW_OP_GNU_reinterpret:
- if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const)
- dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
- else
- {
- unsigned long o = get_base_type_offset (val1->v.val_die_ref.die);
- gcc_assert (o);
- dw2_asm_output_data_uleb128 (o, NULL);
- }
- break;
- case DW_OP_GNU_parameter_ref:
- {
- unsigned long o;
- gcc_assert (val1->val_class == dw_val_class_die_ref);
- o = get_ref_die_offset (val1->v.val_die_ref.die);
- dw2_asm_output_data (4, o, NULL);
- }
- break;
- default:
- /* Other codes have no operands. */
- break;
- }
- }
- /* Output a sequence of location operations.
- The for_eh_or_skip parameter controls whether register numbers are
- converted using DWARF2_FRAME_REG_OUT, which is needed in the case that
- hard reg numbers have been processed via DWARF_FRAME_REGNUM (i.e. for unwind
- info). This should be suppressed for the cases that have not been converted
- (i.e. symbolic debug info), by setting the parameter < 0. See PR47324. */
- void
- output_loc_sequence (dw_loc_descr_ref loc, int for_eh_or_skip)
- {
- for (; loc != NULL; loc = loc->dw_loc_next)
- {
- enum dwarf_location_atom opc = loc->dw_loc_opc;
- /* Output the opcode. */
- if (for_eh_or_skip >= 0
- && opc >= DW_OP_breg0 && opc <= DW_OP_breg31)
- {
- unsigned r = (opc - DW_OP_breg0);
- r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
- gcc_assert (r <= 31);
- opc = (enum dwarf_location_atom) (DW_OP_breg0 + r);
- }
- else if (for_eh_or_skip >= 0
- && opc >= DW_OP_reg0 && opc <= DW_OP_reg31)
- {
- unsigned r = (opc - DW_OP_reg0);
- r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
- gcc_assert (r <= 31);
- opc = (enum dwarf_location_atom) (DW_OP_reg0 + r);
- }
- dw2_asm_output_data (1, opc,
- "%s", dwarf_stack_op_name (opc));
- /* Output the operand(s) (if any). */
- output_loc_operands (loc, for_eh_or_skip);
- }
- }
- /* Output location description stack opcode's operands (if any).
- The output is single bytes on a line, suitable for .cfi_escape. */
- static void
- output_loc_operands_raw (dw_loc_descr_ref loc)
- {
- dw_val_ref val1 = &loc->dw_loc_oprnd1;
- dw_val_ref val2 = &loc->dw_loc_oprnd2;
- switch (loc->dw_loc_opc)
- {
- case DW_OP_addr:
- case DW_OP_GNU_addr_index:
- case DW_OP_GNU_const_index:
- case DW_OP_implicit_value:
- /* We cannot output addresses in .cfi_escape, only bytes. */
- gcc_unreachable ();
- case DW_OP_const1u:
- case DW_OP_const1s:
- case DW_OP_pick:
- case DW_OP_deref_size:
- case DW_OP_xderef_size:
- fputc (',', asm_out_file);
- dw2_asm_output_data_raw (1, val1->v.val_int);
- break;
- case DW_OP_const2u:
- case DW_OP_const2s:
- fputc (',', asm_out_file);
- dw2_asm_output_data_raw (2, val1->v.val_int);
- break;
- case DW_OP_const4u:
- case DW_OP_const4s:
- fputc (',', asm_out_file);
- dw2_asm_output_data_raw (4, val1->v.val_int);
- break;
- case DW_OP_const8u:
- case DW_OP_const8s:
- gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
- fputc (',', asm_out_file);
- dw2_asm_output_data_raw (8, val1->v.val_int);
- break;
- case DW_OP_skip:
- case DW_OP_bra:
- {
- int offset;
- gcc_assert (val1->val_class == dw_val_class_loc);
- offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3);
- fputc (',', asm_out_file);
- dw2_asm_output_data_raw (2, offset);
- }
- break;
- case DW_OP_regx:
- {
- unsigned r = DWARF2_FRAME_REG_OUT (val1->v.val_unsigned, 1);
- gcc_assert (size_of_uleb128 (r)
- == size_of_uleb128 (val1->v.val_unsigned));
- fputc (',', asm_out_file);
- dw2_asm_output_data_uleb128_raw (r);
- }
- break;
-
- case DW_OP_constu:
- case DW_OP_plus_uconst:
- case DW_OP_piece:
- fputc (',', asm_out_file);
- dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
- break;
- case DW_OP_bit_piece:
- fputc (',', asm_out_file);
- dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
- dw2_asm_output_data_uleb128_raw (val2->v.val_unsigned);
- break;
- case DW_OP_consts:
- case DW_OP_breg0:
- case DW_OP_breg1:
- case DW_OP_breg2:
- case DW_OP_breg3:
- case DW_OP_breg4:
- case DW_OP_breg5:
- case DW_OP_breg6:
- case DW_OP_breg7:
- case DW_OP_breg8:
- case DW_OP_breg9:
- case DW_OP_breg10:
- case DW_OP_breg11:
- case DW_OP_breg12:
- case DW_OP_breg13:
- case DW_OP_breg14:
- case DW_OP_breg15:
- case DW_OP_breg16:
- case DW_OP_breg17:
- case DW_OP_breg18:
- case DW_OP_breg19:
- case DW_OP_breg20:
- case DW_OP_breg21:
- case DW_OP_breg22:
- case DW_OP_breg23:
- case DW_OP_breg24:
- case DW_OP_breg25:
- case DW_OP_breg26:
- case DW_OP_breg27:
- case DW_OP_breg28:
- case DW_OP_breg29:
- case DW_OP_breg30:
- case DW_OP_breg31:
- case DW_OP_fbreg:
- fputc (',', asm_out_file);
- dw2_asm_output_data_sleb128_raw (val1->v.val_int);
- break;
- case DW_OP_bregx:
- {
- unsigned r = DWARF2_FRAME_REG_OUT (val1->v.val_unsigned, 1);
- gcc_assert (size_of_uleb128 (r)
- == size_of_uleb128 (val1->v.val_unsigned));
- fputc (',', asm_out_file);
- dw2_asm_output_data_uleb128_raw (r);
- fputc (',', asm_out_file);
- dw2_asm_output_data_sleb128_raw (val2->v.val_int);
- }
- break;
- case DW_OP_GNU_implicit_pointer:
- case DW_OP_GNU_entry_value:
- case DW_OP_GNU_const_type:
- case DW_OP_GNU_regval_type:
- case DW_OP_GNU_deref_type:
- case DW_OP_GNU_convert:
- case DW_OP_GNU_reinterpret:
- case DW_OP_GNU_parameter_ref:
- gcc_unreachable ();
- break;
- default:
- /* Other codes have no operands. */
- break;
- }
- }
- void
- output_loc_sequence_raw (dw_loc_descr_ref loc)
- {
- while (1)
- {
- enum dwarf_location_atom opc = loc->dw_loc_opc;
- /* Output the opcode. */
- if (opc >= DW_OP_breg0 && opc <= DW_OP_breg31)
- {
- unsigned r = (opc - DW_OP_breg0);
- r = DWARF2_FRAME_REG_OUT (r, 1);
- gcc_assert (r <= 31);
- opc = (enum dwarf_location_atom) (DW_OP_breg0 + r);
- }
- else if (opc >= DW_OP_reg0 && opc <= DW_OP_reg31)
- {
- unsigned r = (opc - DW_OP_reg0);
- r = DWARF2_FRAME_REG_OUT (r, 1);
- gcc_assert (r <= 31);
- opc = (enum dwarf_location_atom) (DW_OP_reg0 + r);
- }
- /* Output the opcode. */
- fprintf (asm_out_file, "%#x", opc);
- output_loc_operands_raw (loc);
- if (!loc->dw_loc_next)
- break;
- loc = loc->dw_loc_next;
- fputc (',', asm_out_file);
- }
- }
- /* This function builds a dwarf location descriptor sequence from a
- dw_cfa_location, adding the given OFFSET to the result of the
- expression. */
- struct dw_loc_descr_node *
- build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
- {
- struct dw_loc_descr_node *head, *tmp;
- offset += cfa->offset;
- if (cfa->indirect)
- {
- head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
- head->dw_loc_oprnd1.val_class = dw_val_class_const;
- head->dw_loc_oprnd1.val_entry = NULL;
- tmp = new_loc_descr (DW_OP_deref, 0, 0);
- add_loc_descr (&head, tmp);
- if (offset != 0)
- {
- tmp = new_loc_descr (DW_OP_plus_uconst, offset, 0);
- add_loc_descr (&head, tmp);
- }
- }
- else
- head = new_reg_loc_descr (cfa->reg, offset);
- return head;
- }
- /* This function builds a dwarf location descriptor sequence for
- the address at OFFSET from the CFA when stack is aligned to
- ALIGNMENT byte. */
- struct dw_loc_descr_node *
- build_cfa_aligned_loc (dw_cfa_location *cfa,
- HOST_WIDE_INT offset, HOST_WIDE_INT alignment)
- {
- struct dw_loc_descr_node *head;
- unsigned int dwarf_fp
- = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
- /* When CFA is defined as FP+OFFSET, emulate stack alignment. */
- if (cfa->reg == HARD_FRAME_POINTER_REGNUM && cfa->indirect == 0)
- {
- head = new_reg_loc_descr (dwarf_fp, 0);
- add_loc_descr (&head, int_loc_descriptor (alignment));
- add_loc_descr (&head, new_loc_descr (DW_OP_and, 0, 0));
- loc_descr_plus_const (&head, offset);
- }
- else
- head = new_reg_loc_descr (dwarf_fp, offset);
- return head;
- }
- /* And now, the support for symbolic debugging information. */
- /* .debug_str support. */
- static void dwarf2out_init (const char *);
- static void dwarf2out_finish (const char *);
- static void dwarf2out_assembly_start (void);
- static void dwarf2out_define (unsigned int, const char *);
- static void dwarf2out_undef (unsigned int, const char *);
- static void dwarf2out_start_source_file (unsigned, const char *);
- static void dwarf2out_end_source_file (unsigned);
- static void dwarf2out_function_decl (tree);
- static void dwarf2out_begin_block (unsigned, unsigned);
- static void dwarf2out_end_block (unsigned, unsigned);
- static bool dwarf2out_ignore_block (const_tree);
- static void dwarf2out_global_decl (tree);
- static void dwarf2out_type_decl (tree, int);
- static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool);
- static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
- dw_die_ref);
- static void dwarf2out_abstract_function (tree);
- static void dwarf2out_var_location (rtx_insn *);
- static void dwarf2out_begin_function (tree);
- static void dwarf2out_end_function (unsigned int);
- static void dwarf2out_register_main_translation_unit (tree unit);
- static void dwarf2out_set_name (tree, tree);
- /* The debug hooks structure. */
- const struct gcc_debug_hooks dwarf2_debug_hooks =
- {
- dwarf2out_init,
- dwarf2out_finish,
- dwarf2out_assembly_start,
- dwarf2out_define,
- dwarf2out_undef,
- dwarf2out_start_source_file,
- dwarf2out_end_source_file,
- dwarf2out_begin_block,
- dwarf2out_end_block,
- dwarf2out_ignore_block,
- dwarf2out_source_line,
- dwarf2out_begin_prologue,
- #if VMS_DEBUGGING_INFO
- dwarf2out_vms_end_prologue,
- dwarf2out_vms_begin_epilogue,
- #else
- debug_nothing_int_charstar,
- debug_nothing_int_charstar,
- #endif
- dwarf2out_end_epilogue,
- dwarf2out_begin_function,
- dwarf2out_end_function, /* end_function */
- dwarf2out_register_main_translation_unit,
- dwarf2out_function_decl, /* function_decl */
- dwarf2out_global_decl,
- dwarf2out_type_decl, /* type_decl */
- dwarf2out_imported_module_or_decl,
- debug_nothing_tree, /* deferred_inline_function */
- /* The DWARF 2 backend tries to reduce debugging bloat by not
- emitting the abstract description of inline functions until
- something tries to reference them. */
- dwarf2out_abstract_function, /* outlining_inline_function */
- debug_nothing_rtx_code_label, /* label */
- debug_nothing_int, /* handle_pch */
- dwarf2out_var_location,
- dwarf2out_switch_text_section,
- dwarf2out_set_name,
- 1, /* start_end_main_source_file */
- TYPE_SYMTAB_IS_DIE /* tree_type_symtab_field */
- };
- /* NOTE: In the comments in this file, many references are made to
- "Debugging Information Entries". This term is abbreviated as `DIE'
- throughout the remainder of this file. */
- /* An internal representation of the DWARF output is built, and then
- walked to generate the DWARF debugging info. The walk of the internal
- representation is done after the entire program has been compiled.
- The types below are used to describe the internal representation. */
- /* Whether to put type DIEs into their own section .debug_types instead
- of making them part of the .debug_info section. Only supported for
- Dwarf V4 or higher and the user didn't disable them through
- -fno-debug-types-section. It is more efficient to put them in a
- separate comdat sections since the linker will then be able to
- remove duplicates. But not all tools support .debug_types sections
- yet. */
- #define use_debug_types (dwarf_version >= 4 && flag_debug_types_section)
- /* Various DIE's use offsets relative to the beginning of the
- .debug_info section to refer to each other. */
- typedef long int dw_offset;
- /* Define typedefs here to avoid circular dependencies. */
- typedef struct dw_attr_struct *dw_attr_ref;
- typedef struct dw_line_info_struct *dw_line_info_ref;
- typedef struct pubname_struct *pubname_ref;
- typedef struct dw_ranges_struct *dw_ranges_ref;
- typedef struct dw_ranges_by_label_struct *dw_ranges_by_label_ref;
- typedef struct comdat_type_struct *comdat_type_node_ref;
- /* The entries in the line_info table more-or-less mirror the opcodes
- that are used in the real dwarf line table. Arrays of these entries
- are collected per section when DWARF2_ASM_LINE_DEBUG_INFO is not
- supported. */
- enum dw_line_info_opcode {
- /* Emit DW_LNE_set_address; the operand is the label index. */
- LI_set_address,
- /* Emit a row to the matrix with the given line. This may be done
- via any combination of DW_LNS_copy, DW_LNS_advance_line, and
- special opcodes. */
- LI_set_line,
- /* Emit a DW_LNS_set_file. */
- LI_set_file,
- /* Emit a DW_LNS_set_column. */
- LI_set_column,
- /* Emit a DW_LNS_negate_stmt; the operand is ignored. */
- LI_negate_stmt,
- /* Emit a DW_LNS_set_prologue_end/epilogue_begin; the operand is ignored. */
- LI_set_prologue_end,
- LI_set_epilogue_begin,
- /* Emit a DW_LNE_set_discriminator. */
- LI_set_discriminator
- };
- typedef struct GTY(()) dw_line_info_struct {
- enum dw_line_info_opcode opcode;
- unsigned int val;
- } dw_line_info_entry;
- typedef struct GTY(()) dw_line_info_table_struct {
- /* The label that marks the end of this section. */
- const char *end_label;
- /* The values for the last row of the matrix, as collected in the table.
- These are used to minimize the changes to the next row. */
- unsigned int file_num;
- unsigned int line_num;
- unsigned int column_num;
- int discrim_num;
- bool is_stmt;
- bool in_use;
- vec<dw_line_info_entry, va_gc> *entries;
- } dw_line_info_table;
- typedef dw_line_info_table *dw_line_info_table_p;
- /* Each DIE attribute has a field specifying the attribute kind,
- a link to the next attribute in the chain, and an attribute value.
- Attributes are typically linked below the DIE they modify. */
- typedef struct GTY(()) dw_attr_struct {
- enum dwarf_attribute dw_attr;
- dw_val_node dw_attr_val;
- }
- dw_attr_node;
- /* The Debugging Information Entry (DIE) structure. DIEs form a tree.
- The children of each node form a circular list linked by
- die_sib. die_child points to the node *before* the "first" child node. */
- typedef struct GTY((chain_circular ("%h.die_sib"), for_user)) die_struct {
- union die_symbol_or_type_node
- {
- const char * GTY ((tag ("0"))) die_symbol;
- comdat_type_node_ref GTY ((tag ("1"))) die_type_node;
- }
- GTY ((desc ("%0.comdat_type_p"))) die_id;
- vec<dw_attr_node, va_gc> *die_attr;
- dw_die_ref die_parent;
- dw_die_ref die_child;
- dw_die_ref die_sib;
- dw_die_ref die_definition; /* ref from a specification to its definition */
- dw_offset die_offset;
- unsigned long die_abbrev;
- int die_mark;
- unsigned int decl_id;
- enum dwarf_tag die_tag;
- /* Die is used and must not be pruned as unused. */
- BOOL_BITFIELD die_perennial_p : 1;
- BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
- /* Lots of spare bits. */
- }
- die_node;
- /* Evaluate 'expr' while 'c' is set to each child of DIE in order. */
- #define FOR_EACH_CHILD(die, c, expr) do { \
- c = die->die_child; \
- if (c) do { \
- c = c->die_sib; \
- expr; \
- } while (c != die->die_child); \
- } while (0)
- /* The pubname structure */
- typedef struct GTY(()) pubname_struct {
- dw_die_ref die;
- const char *name;
- }
- pubname_entry;
- struct GTY(()) dw_ranges_struct {
- /* If this is positive, it's a block number, otherwise it's a
- bitwise-negated index into dw_ranges_by_label. */
- int num;
- };
- /* A structure to hold a macinfo entry. */
- typedef struct GTY(()) macinfo_struct {
- unsigned char code;
- unsigned HOST_WIDE_INT lineno;
- const char *info;
- }
- macinfo_entry;
- struct GTY(()) dw_ranges_by_label_struct {
- const char *begin;
- const char *end;
- };
- /* The comdat type node structure. */
- typedef struct GTY(()) comdat_type_struct
- {
- dw_die_ref root_die;
- dw_die_ref type_die;
- dw_die_ref skeleton_die;
- char signature[DWARF_TYPE_SIGNATURE_SIZE];
- struct comdat_type_struct *next;
- }
- comdat_type_node;
- /* The limbo die list structure. */
- typedef struct GTY(()) limbo_die_struct {
- dw_die_ref die;
- tree created_for;
- struct limbo_die_struct *next;
- }
- limbo_die_node;
- typedef struct skeleton_chain_struct
- {
- dw_die_ref old_die;
- dw_die_ref new_die;
- struct skeleton_chain_struct *parent;
- }
- skeleton_chain_node;
- /* Define a macro which returns nonzero for a TYPE_DECL which was
- implicitly generated for a type.
- Note that, unlike the C front-end (which generates a NULL named
- TYPE_DECL node for each complete tagged type, each array type,
- and each function type node created) the C++ front-end generates
- a _named_ TYPE_DECL node for each tagged type node created.
- These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to
- generate a DW_TAG_typedef DIE for them. Likewise with the Ada
- front-end, but for each type, tagged or not. */
- #define TYPE_DECL_IS_STUB(decl) \
- (DECL_NAME (decl) == NULL_TREE \
- || (DECL_ARTIFICIAL (decl) \
- && ((decl == TYPE_STUB_DECL (TREE_TYPE (decl))) \
- /* This is necessary for stub decls that \
- appear in nested inline functions. */ \
- || (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE \
- && (decl_ultimate_origin (decl) \
- == TYPE_STUB_DECL (TREE_TYPE (decl)))))))
- /* Information concerning the compilation unit's programming
- language, and compiler version. */
- /* Fixed size portion of the DWARF compilation unit header. */
- #define DWARF_COMPILE_UNIT_HEADER_SIZE \
- (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 3)
- /* Fixed size portion of the DWARF comdat type unit header. */
- #define DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE \
- (DWARF_COMPILE_UNIT_HEADER_SIZE + DWARF_TYPE_SIGNATURE_SIZE \
- + DWARF_OFFSET_SIZE)
- /* Fixed size portion of public names info. */
- #define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
- /* Fixed size portion of the address range info. */
- #define DWARF_ARANGES_HEADER_SIZE \
- (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \
- DWARF2_ADDR_SIZE * 2) \
- - DWARF_INITIAL_LENGTH_SIZE)
- /* Size of padding portion in the address range info. It must be
- aligned to twice the pointer size. */
- #define DWARF_ARANGES_PAD_SIZE \
- (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \
- DWARF2_ADDR_SIZE * 2) \
- - (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4))
- /* Use assembler line directives if available. */
- #ifndef DWARF2_ASM_LINE_DEBUG_INFO
- #ifdef HAVE_AS_DWARF2_DEBUG_LINE
- #define DWARF2_ASM_LINE_DEBUG_INFO 1
- #else
- #define DWARF2_ASM_LINE_DEBUG_INFO 0
- #endif
- #endif
- /* Minimum line offset in a special line info. opcode.
- This value was chosen to give a reasonable range of values. */
- #define DWARF_LINE_BASE -10
- /* First special line opcode - leave room for the standard opcodes. */
- #define DWARF_LINE_OPCODE_BASE ((int)DW_LNS_set_isa + 1)
- /* Range of line offsets in a special line info. opcode. */
- #define DWARF_LINE_RANGE (254-DWARF_LINE_OPCODE_BASE+1)
- /* Flag that indicates the initial value of the is_stmt_start flag.
- In the present implementation, we do not mark any lines as
- the beginning of a source statement, because that information
- is not made available by the GCC front-end. */
- #define DWARF_LINE_DEFAULT_IS_STMT_START 1
- /* Maximum number of operations per instruction bundle. */
- #ifndef DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN
- #define DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN 1
- #endif
- /* This location is used by calc_die_sizes() to keep track
- the offset of each DIE within the .debug_info section. */
- static unsigned long next_die_offset;
- /* Record the root of the DIE's built for the current compilation unit. */
- static GTY(()) dw_die_ref single_comp_unit_die;
- /* A list of type DIEs that have been separated into comdat sections. */
- static GTY(()) comdat_type_node *comdat_type_list;
- /* A list of DIEs with a NULL parent waiting to be relocated. */
- static GTY(()) limbo_die_node *limbo_die_list;
- /* A list of DIEs for which we may have to generate
- DW_AT_{,MIPS_}linkage_name once their DECL_ASSEMBLER_NAMEs are set. */
- static GTY(()) limbo_die_node *deferred_asm_name;
- struct dwarf_file_hasher : ggc_hasher<dwarf_file_data *>
- {
- typedef const char *compare_type;
- static hashval_t hash (dwarf_file_data *);
- static bool equal (dwarf_file_data *, const char *);
- };
- /* Filenames referenced by this compilation unit. */
- static GTY(()) hash_table<dwarf_file_hasher> *file_table;
- struct decl_die_hasher : ggc_hasher<die_node *>
- {
- typedef tree compare_type;
- static hashval_t hash (die_node *);
- static bool equal (die_node *, tree);
- };
- /* A hash table of references to DIE's that describe declarations.
- The key is a DECL_UID() which is a unique number identifying each decl. */
- static GTY (()) hash_table<decl_die_hasher> *decl_die_table;
- struct block_die_hasher : ggc_hasher<die_struct *>
- {
- static hashval_t hash (die_struct *);
- static bool equal (die_struct *, die_struct *);
- };
- /* A hash table of references to DIE's that describe COMMON blocks.
- The key is DECL_UID() ^ die_parent. */
- static GTY (()) hash_table<block_die_hasher> *common_block_die_table;
- typedef struct GTY(()) die_arg_entry_struct {
- dw_die_ref die;
- tree arg;
- } die_arg_entry;
- /* Node of the variable location list. */
- struct GTY ((chain_next ("%h.next"))) var_loc_node {
- /* Either NOTE_INSN_VAR_LOCATION, or, for SRA optimized variables,
- EXPR_LIST chain. For small bitsizes, bitsize is encoded
- in mode of the EXPR_LIST node and first EXPR_LIST operand
- is either NOTE_INSN_VAR_LOCATION for a piece with a known
- location or NULL for padding. For larger bitsizes,
- mode is 0 and first operand is a CONCAT with bitsize
- as first CONCAT operand and NOTE_INSN_VAR_LOCATION resp.
- NULL as second operand. */
- rtx GTY (()) loc;
- const char * GTY (()) label;
- struct var_loc_node * GTY (()) next;
- };
- /* Variable location list. */
- struct GTY ((for_user)) var_loc_list_def {
- struct var_loc_node * GTY (()) first;
- /* Pointer to the last but one or last element of the
- chained list. If the list is empty, both first and
- last are NULL, if the list contains just one node
- or the last node certainly is not redundant, it points
- to the last node, otherwise points to the last but one.
- Do not mark it for GC because it is marked through the chain. */
- struct var_loc_node * GTY ((skip ("%h"))) last;
- /* Pointer to the last element before section switch,
- if NULL, either sections weren't switched or first
- is after section switch. */
- struct var_loc_node * GTY ((skip ("%h"))) last_before_switch;
- /* DECL_UID of the variable decl. */
- unsigned int decl_id;
- };
- typedef struct var_loc_list_def var_loc_list;
- /* Call argument location list. */
- struct GTY ((chain_next ("%h.next"))) call_arg_loc_node {
- rtx GTY (()) call_arg_loc_note;
- const char * GTY (()) label;
- tree GTY (()) block;
- bool tail_call_p;
- rtx GTY (()) symbol_ref;
- struct call_arg_loc_node * GTY (()) next;
- };
- struct decl_loc_hasher : ggc_hasher<var_loc_list *>
- {
- typedef const_tree compare_type;
- static hashval_t hash (var_loc_list *);
- static bool equal (var_loc_list *, const_tree);
- };
- /* Table of decl location linked lists. */
- static GTY (()) hash_table<decl_loc_hasher> *decl_loc_table;
- /* Head and tail of call_arg_loc chain. */
- static GTY (()) struct call_arg_loc_node *call_arg_locations;
- static struct call_arg_loc_node *call_arg_loc_last;
- /* Number of call sites in the current function. */
- static int call_site_count = -1;
- /* Number of tail call sites in the current function. */
- static int tail_call_site_count = -1;
- /* Vector mapping block numbers to DW_TAG_{lexical_block,inlined_subroutine}
- DIEs. */
- static vec<dw_die_ref> block_map;
- /* A cached location list. */
- struct GTY ((for_user)) cached_dw_loc_list_def {
- /* The DECL_UID of the decl that this entry describes. */
- unsigned int decl_id;
- /* The cached location list. */
- dw_loc_list_ref loc_list;
- };
- typedef struct cached_dw_loc_list_def cached_dw_loc_list;
- struct dw_loc_list_hasher : ggc_hasher<cached_dw_loc_list *>
- {
- typedef const_tree compare_type;
-
- static hashval_t hash (cached_dw_loc_list *);
- static bool equal (cached_dw_loc_list *, const_tree);
- };
- /* Table of cached location lists. */
- static GTY (()) hash_table<dw_loc_list_hasher> *cached_dw_loc_list_table;
- /* A pointer to the base of a list of references to DIE's that
- are uniquely identified by their tag, presence/absence of
- children DIE's, and list of attribute/value pairs. */
- static GTY((length ("abbrev_die_table_allocated")))
- dw_die_ref *abbrev_die_table;
- /* Number of elements currently allocated for abbrev_die_table. */
- static GTY(()) unsigned abbrev_die_table_allocated;
- /* Number of elements in type_die_table currently in use. */
- static GTY(()) unsigned abbrev_die_table_in_use;
- /* Size (in elements) of increments by which we may expand the
- abbrev_die_table. */
- #define ABBREV_DIE_TABLE_INCREMENT 256
- /* A global counter for generating labels for line number data. */
- static unsigned int line_info_label_num;
- /* The current table to which we should emit line number information
- for the current function. This will be set up at the beginning of
- assembly for the function. */
- static dw_line_info_table *cur_line_info_table;
- /* The two default tables of line number info. */
- static GTY(()) dw_line_info_table *text_section_line_info;
- static GTY(()) dw_line_info_table *cold_text_section_line_info;
- /* The set of all non-default tables of line number info. */
- static GTY(()) vec<dw_line_info_table_p, va_gc> *separate_line_info;
- /* A flag to tell pubnames/types export if there is an info section to
- refer to. */
- static bool info_section_emitted;
- /* A pointer to the base of a table that contains a list of publicly
- accessible names. */
- static GTY (()) vec<pubname_entry, va_gc> *pubname_table;
- /* A pointer to the base of a table that contains a list of publicly
- accessible types. */
- static GTY (()) vec<pubname_entry, va_gc> *pubtype_table;
- /* A pointer to the base of a table that contains a list of macro
- defines/undefines (and file start/end markers). */
- static GTY (()) vec<macinfo_entry, va_gc> *macinfo_table;
- /* True if .debug_macinfo or .debug_macros section is going to be
- emitted. */
- #define have_macinfo \
- (debug_info_level >= DINFO_LEVEL_VERBOSE \
- && !macinfo_table->is_empty ())
- /* Array of dies for which we should generate .debug_ranges info. */
- static GTY ((length ("ranges_table_allocated"))) dw_ranges_ref ranges_table;
- /* Number of elements currently allocated for ranges_table. */
- static GTY(()) unsigned ranges_table_allocated;
- /* Number of elements in ranges_table currently in use. */
- static GTY(()) unsigned ranges_table_in_use;
- /* Array of pairs of labels referenced in ranges_table. */
- static GTY ((length ("ranges_by_label_allocated")))
- dw_ranges_by_label_ref ranges_by_label;
- /* Number of elements currently allocated for ranges_by_label. */
- static GTY(()) unsigned ranges_by_label_allocated;
- /* Number of elements in ranges_by_label currently in use. */
- static GTY(()) unsigned ranges_by_label_in_use;
- /* Size (in elements) of increments by which we may expand the
- ranges_table. */
- #define RANGES_TABLE_INCREMENT 64
- /* Whether we have location lists that need outputting */
- static GTY(()) bool have_location_lists;
- /* Unique label counter. */
- static GTY(()) unsigned int loclabel_num;
- /* Unique label counter for point-of-call tables. */
- static GTY(()) unsigned int poc_label_num;
- /* The last file entry emitted by maybe_emit_file(). */
- static GTY(()) struct dwarf_file_data * last_emitted_file;
- /* Number of internal labels generated by gen_internal_sym(). */
- static GTY(()) int label_num;
- /* Cached result of previous call to lookup_filename. */
- static GTY(()) struct dwarf_file_data * file_table_last_lookup;
- static GTY(()) vec<die_arg_entry, va_gc> *tmpl_value_parm_die_table;
- /* Instances of generic types for which we need to generate debug
- info that describe their generic parameters and arguments. That
- generation needs to happen once all types are properly laid out so
- we do it at the end of compilation. */
- static GTY(()) vec<tree, va_gc> *generic_type_instances;
- /* Offset from the "steady-state frame pointer" to the frame base,
- within the current function. */
- static HOST_WIDE_INT frame_pointer_fb_offset;
- static bool frame_pointer_fb_offset_valid;
- static vec<dw_die_ref> base_types;
- /* Flags to represent a set of attribute classes for attributes that represent
- a scalar value (bounds, pointers, ...). */
- enum dw_scalar_form
- {
- dw_scalar_form_constant = 0x01,
- dw_scalar_form_exprloc = 0x02,
- dw_scalar_form_reference = 0x04
- };
- /* Forward declarations for functions defined in this file. */
- static int is_pseudo_reg (const_rtx);
- static tree type_main_variant (tree);
- static int is_tagged_type (const_tree);
- static const char *dwarf_tag_name (unsigned);
- static const char *dwarf_attr_name (unsigned);
- static const char *dwarf_form_name (unsigned);
- static tree decl_ultimate_origin (const_tree);
- static tree decl_class_context (tree);
- static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
- static inline enum dw_val_class AT_class (dw_attr_ref);
- static inline unsigned int AT_index (dw_attr_ref);
- static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned);
- static inline unsigned AT_flag (dw_attr_ref);
- static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
- static inline HOST_WIDE_INT AT_int (dw_attr_ref);
- static void add_AT_unsigned (dw_die_ref, enum dwarf_attribute, unsigned HOST_WIDE_INT);
- static inline unsigned HOST_WIDE_INT AT_unsigned (dw_attr_ref);
- static void add_AT_double (dw_die_ref, enum dwarf_attribute,
- HOST_WIDE_INT, unsigned HOST_WIDE_INT);
- static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int,
- unsigned int, unsigned char *);
- static void add_AT_data8 (dw_die_ref, enum dwarf_attribute, unsigned char *);
- static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *);
- static inline const char *AT_string (dw_attr_ref);
- static enum dwarf_form AT_string_form (dw_attr_ref);
- static void add_AT_die_ref (dw_die_ref, enum dwarf_attribute, dw_die_ref);
- static void add_AT_specification (dw_die_ref, dw_die_ref);
- static inline dw_die_ref AT_ref (dw_attr_ref);
- static inline int AT_ref_external (dw_attr_ref);
- static inline void set_AT_ref_external (dw_attr_ref, int);
- static void add_AT_fde_ref (dw_die_ref, enum dwarf_attribute, unsigned);
- static void add_AT_loc (dw_die_ref, enum dwarf_attribute, dw_loc_descr_ref);
- static inline dw_loc_descr_ref AT_loc (dw_attr_ref);
- static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
- dw_loc_list_ref);
- static inline dw_loc_list_ref AT_loc_list (dw_attr_ref);
- static addr_table_entry *add_addr_table_entry (void *, enum ate_kind);
- static void remove_addr_table_entry (addr_table_entry *);
- static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
- static inline rtx AT_addr (dw_attr_ref);
- static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
- static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
- static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
- static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
- unsigned HOST_WIDE_INT);
- static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
- unsigned long, bool);
- static inline const char *AT_lbl (dw_attr_ref);
- static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute);
- static const char *get_AT_low_pc (dw_die_ref);
- static const char *get_AT_hi_pc (dw_die_ref);
- static const char *get_AT_string (dw_die_ref, enum dwarf_attribute);
- static int get_AT_flag (dw_die_ref, enum dwarf_attribute);
- static unsigned get_AT_unsigned (dw_die_ref, enum dwarf_attribute);
- static inline dw_die_ref get_AT_ref (dw_die_ref, enum dwarf_attribute);
- static bool is_cxx (void);
- static bool is_fortran (void);
- static bool is_ada (void);
- static void remove_AT (dw_die_ref, enum dwarf_attribute);
- static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
- static void add_child_die (dw_die_ref, dw_die_ref);
- static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
- static dw_die_ref lookup_type_die (tree);
- static dw_die_ref strip_naming_typedef (tree, dw_die_ref);
- static dw_die_ref lookup_type_die_strip_naming_typedef (tree);
- static void equate_type_number_to_die (tree, dw_die_ref);
- static dw_die_ref lookup_decl_die (tree);
- static var_loc_list *lookup_decl_loc (const_tree);
- static void equate_decl_number_to_die (tree, dw_die_ref);
- static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *);
- static void print_spaces (FILE *);
- static void print_die (dw_die_ref, FILE *);
- static dw_die_ref push_new_compile_unit (dw_die_ref, dw_die_ref);
- static dw_die_ref pop_compile_unit (dw_die_ref);
- static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
- static void attr_checksum (dw_attr_ref, struct md5_ctx *, int *);
- static void die_checksum (dw_die_ref, struct md5_ctx *, int *);
- static void checksum_sleb128 (HOST_WIDE_INT, struct md5_ctx *);
- static void checksum_uleb128 (unsigned HOST_WIDE_INT, struct md5_ctx *);
- static void loc_checksum_ordered (dw_loc_descr_ref, struct md5_ctx *);
- static void attr_checksum_ordered (enum dwarf_tag, dw_attr_ref,
- struct md5_ctx *, int *);
- struct checksum_attributes;
- static void collect_checksum_attributes (struct checksum_attributes *, dw_die_ref);
- static void die_checksum_ordered (dw_die_ref, struct md5_ctx *, int *);
- static void checksum_die_context (dw_die_ref, struct md5_ctx *);
- static void generate_type_signature (dw_die_ref, comdat_type_node *);
- static int same_loc_p (dw_loc_descr_ref, dw_loc_descr_ref, int *);
- static int same_dw_val_p (const dw_val_node *, const dw_val_node *, int *);
- static int same_attr_p (dw_attr_ref, dw_attr_ref, int *);
- static int same_die_p (dw_die_ref, dw_die_ref, int *);
- static int same_die_p_wrap (dw_die_ref, dw_die_ref);
- static void compute_section_prefix (dw_die_ref);
- static int is_type_die (dw_die_ref);
- static int is_comdat_die (dw_die_ref);
- static int is_symbol_die (dw_die_ref);
- static inline bool is_template_instantiation (dw_die_ref);
- static void assign_symbol_names (dw_die_ref);
- static void break_out_includes (dw_die_ref);
- static int is_declaration_die (dw_die_ref);
- static int should_move_die_to_comdat (dw_die_ref);
- static dw_die_ref clone_as_declaration (dw_die_ref);
- static dw_die_ref clone_die (dw_die_ref);
- static dw_die_ref clone_tree (dw_die_ref);
- static dw_die_ref copy_declaration_context (dw_die_ref, dw_die_ref);
- static void generate_skeleton_ancestor_tree (skeleton_chain_node *);
- static void generate_skeleton_bottom_up (skeleton_chain_node *);
- static dw_die_ref generate_skeleton (dw_die_ref);
- static dw_die_ref remove_child_or_replace_with_skeleton (dw_die_ref,
- dw_die_ref,
- dw_die_ref);
- static void break_out_comdat_types (dw_die_ref);
- static void copy_decls_for_unworthy_types (dw_die_ref);
- static void add_sibling_attributes (dw_die_ref);
- static void output_location_lists (dw_die_ref);
- static int constant_size (unsigned HOST_WIDE_INT);
- static unsigned long size_of_die (dw_die_ref);
- static void calc_die_sizes (dw_die_ref);
- static void calc_base_type_die_sizes (void);
- static void mark_dies (dw_die_ref);
- static void unmark_dies (dw_die_ref);
- static void unmark_all_dies (dw_die_ref);
- static unsigned long size_of_pubnames (vec<pubname_entry, va_gc> *);
- static unsigned long size_of_aranges (void);
- static enum dwarf_form value_format (dw_attr_ref);
- static void output_value_format (dw_attr_ref);
- static void output_abbrev_section (void);
- static void output_die_abbrevs (unsigned long, dw_die_ref);
- static void output_die_symbol (dw_die_ref);
- static void output_die (dw_die_ref);
- static void output_compilation_unit_header (void);
- static void output_comp_unit (dw_die_ref, int);
- static void output_comdat_type_unit (comdat_type_node *);
- static const char *dwarf2_name (tree, int);
- static void add_pubname (tree, dw_die_ref);
- static void add_enumerator_pubname (const char *, dw_die_ref);
- static void add_pubname_string (const char *, dw_die_ref);
- static void add_pubtype (tree, dw_die_ref);
- static void output_pubnames (vec<pubname_entry, va_gc> *);
- static void output_aranges (unsigned long);
- static unsigned int add_ranges_num (int);
- static unsigned int add_ranges (const_tree);
- static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
- bool *, bool);
- static void output_ranges (void);
- static dw_line_info_table *new_line_info_table (void);
- static void output_line_info (bool);
- static void output_file_names (void);
- static dw_die_ref base_type_die (tree);
- static int is_base_type (tree);
- static dw_die_ref subrange_type_die (tree, tree, tree, dw_die_ref);
- static int decl_quals (const_tree);
- static dw_die_ref modified_type_die (tree, int, dw_die_ref);
- static dw_die_ref generic_parameter_die (tree, tree, bool, dw_die_ref);
- static dw_die_ref template_parameter_pack_die (tree, tree, dw_die_ref);
- static int type_is_enum (const_tree);
- static unsigned int dbx_reg_number (const_rtx);
- static void add_loc_descr_op_piece (dw_loc_descr_ref *, int);
- static dw_loc_descr_ref reg_loc_descriptor (rtx, enum var_init_status);
- static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int,
- enum var_init_status);
- static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx,
- enum var_init_status);
- static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT,
- enum var_init_status);
- static int is_based_loc (const_rtx);
- static bool resolve_one_addr (rtx *);
- static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
- enum var_init_status);
- static dw_loc_descr_ref loc_descriptor (rtx, machine_mode mode,
- enum var_init_status);
- struct loc_descr_context;
- static dw_loc_list_ref loc_list_from_tree (tree, int,
- const struct loc_descr_context *);
- static dw_loc_descr_ref loc_descriptor_from_tree (tree, int,
- const struct loc_descr_context *);
- static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
- static tree field_type (const_tree);
- static unsigned int simple_type_align_in_bits (const_tree);
- static unsigned int simple_decl_align_in_bits (const_tree);
- static unsigned HOST_WIDE_INT simple_type_size_in_bits (const_tree);
- static HOST_WIDE_INT field_byte_offset (const_tree);
- static void add_AT_location_description (dw_die_ref, enum dwarf_attribute,
- dw_loc_list_ref);
- static void add_data_member_location_attribute (dw_die_ref, tree);
- static bool add_const_value_attribute (dw_die_ref, rtx);
- static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *);
- static void insert_wide_int (const wide_int &, unsigned char *, int);
- static void insert_float (const_rtx, unsigned char *);
- static rtx rtl_for_decl_location (tree);
- static bool add_location_or_const_value_attribute (dw_die_ref, tree, bool,
- enum dwarf_attribute);
- static bool tree_add_const_value_attribute (dw_die_ref, tree);
- static bool tree_add_const_value_attribute_for_decl (dw_die_ref, tree);
- static void add_name_attribute (dw_die_ref, const char *);
- static void add_gnat_descriptive_type_attribute (dw_die_ref, tree, dw_die_ref);
- static void add_comp_dir_attribute (dw_die_ref);
- static void add_scalar_info (dw_die_ref, enum dwarf_attribute, tree, int,
- const struct loc_descr_context *);
- static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree,
- const struct loc_descr_context *);
- static void add_subscript_info (dw_die_ref, tree, bool);
- static void add_byte_size_attribute (dw_die_ref, tree);
- static void add_bit_offset_attribute (dw_die_ref, tree);
- static void add_bit_size_attribute (dw_die_ref, tree);
- static void add_prototyped_attribute (dw_die_ref, tree);
- static dw_die_ref add_abstract_origin_attribute (dw_die_ref, tree);
- static void add_pure_or_virtual_attribute (dw_die_ref, tree);
- static void add_src_coords_attributes (dw_die_ref, tree);
- static void add_name_and_src_coords_attributes (dw_die_ref, tree);
- static void push_decl_scope (tree);
- static void pop_decl_scope (void);
- static dw_die_ref scope_die_for (tree, dw_die_ref);
- static inline int local_scope_p (dw_die_ref);
- static inline int class_scope_p (dw_die_ref);
- static inline int class_or_namespace_scope_p (dw_die_ref);
- static void add_type_attribute (dw_die_ref, tree, int, dw_die_ref);
- static void add_calling_convention_attribute (dw_die_ref, tree);
- static const char *type_tag (const_tree);
- static tree member_declared_type (const_tree);
- #if 0
- static const char *decl_start_label (tree);
- #endif
- static void gen_array_type_die (tree, dw_die_ref);
- static void gen_descr_array_type_die (tree, struct array_descr_info *, dw_die_ref);
- #if 0
- static void gen_entry_point_die (tree, dw_die_ref);
- #endif
- static dw_die_ref gen_enumeration_type_die (tree, dw_die_ref);
- static dw_die_ref gen_formal_parameter_die (tree, tree, bool, dw_die_ref);
- static dw_die_ref gen_formal_parameter_pack_die (tree, tree, dw_die_ref, tree*);
- static void gen_unspecified_parameters_die (tree, dw_die_ref);
- static void gen_formal_types_die (tree, dw_die_ref);
- static void gen_subprogram_die (tree, dw_die_ref);
- static void gen_variable_die (tree, tree, dw_die_ref);
- static void gen_const_die (tree, dw_die_ref);
- static void gen_label_die (tree, dw_die_ref);
- static void gen_lexical_block_die (tree, dw_die_ref);
- static void gen_inlined_subroutine_die (tree, dw_die_ref);
- static void gen_field_die (tree, dw_die_ref);
- static void gen_ptr_to_mbr_type_die (tree, dw_die_ref);
- static dw_die_ref gen_compile_unit_die (const char *);
- static void gen_inheritance_die (tree, tree, dw_die_ref);
- static void gen_member_die (tree, dw_die_ref);
- static void gen_struct_or_union_type_die (tree, dw_die_ref,
- enum debug_info_usage);
- static void gen_subroutine_type_die (tree, dw_die_ref);
- static void gen_typedef_die (tree, dw_die_ref);
- static void gen_type_die (tree, dw_die_ref);
- static void gen_block_die (tree, dw_die_ref);
- static void decls_for_scope (tree, dw_die_ref);
- static inline int is_redundant_typedef (const_tree);
- static bool is_naming_typedef_decl (const_tree);
- static inline dw_die_ref get_context_die (tree);
- static void gen_namespace_die (tree, dw_die_ref);
- static dw_die_ref gen_namelist_decl (tree, dw_die_ref, tree);
- static dw_die_ref gen_decl_die (tree, tree, dw_die_ref);
- static dw_die_ref force_decl_die (tree);
- static dw_die_ref force_type_die (tree);
- static dw_die_ref setup_namespace_context (tree, dw_die_ref);
- static dw_die_ref declare_in_namespace (tree, dw_die_ref);
- static struct dwarf_file_data * lookup_filename (const char *);
- static void retry_incomplete_types (void);
- static void gen_type_die_for_member (tree, tree, dw_die_ref);
- static void gen_generic_params_dies (tree);
- static void gen_tagged_type_die (tree, dw_die_ref, enum debug_info_usage);
- static void gen_type_die_with_usage (tree, dw_die_ref, enum debug_info_usage);
- static void splice_child_die (dw_die_ref, dw_die_ref);
- static int file_info_cmp (const void *, const void *);
- static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
- const char *, const char *);
- static void output_loc_list (dw_loc_list_ref);
- static char *gen_internal_sym (const char *);
- static bool want_pubnames (void);
- static void prune_unmark_dies (dw_die_ref);
- static void prune_unused_types_mark_generic_parms_dies (dw_die_ref);
- static void prune_unused_types_mark (dw_die_ref, int);
- static void prune_unused_types_walk (dw_die_ref);
- static void prune_unused_types_walk_attribs (dw_die_ref);
- static void prune_unused_types_prune (dw_die_ref);
- static void prune_unused_types (void);
- static int maybe_emit_file (struct dwarf_file_data *fd);
- static inline const char *AT_vms_delta1 (dw_attr_ref);
- static inline const char *AT_vms_delta2 (dw_attr_ref);
- static inline void add_AT_vms_delta (dw_die_ref, enum dwarf_attribute,
- const char *, const char *);
- static void append_entry_to_tmpl_value_parm_die_table (dw_die_ref, tree);
- static void gen_remaining_tmpl_value_param_die_attribute (void);
- static bool generic_type_p (tree);
- static void schedule_generic_params_dies_gen (tree t);
- static void gen_scheduled_generic_parms_dies (void);
- static const char *comp_dir_string (void);
- static void hash_loc_operands (dw_loc_descr_ref, inchash::hash &);
- /* enum for tracking thread-local variables whose address is really an offset
- relative to the TLS pointer, which will need link-time relocation, but will
- not need relocation by the DWARF consumer. */
- enum dtprel_bool
- {
- dtprel_false = 0,
- dtprel_true = 1
- };
- /* Return the operator to use for an address of a variable. For dtprel_true, we
- use DW_OP_const*. For regular variables, which need both link-time
- relocation and consumer-level relocation (e.g., to account for shared objects
- loaded at a random address), we use DW_OP_addr*. */
- static inline enum dwarf_location_atom
- dw_addr_op (enum dtprel_bool dtprel)
- {
- if (dtprel == dtprel_true)
- return (dwarf_split_debug_info ? DW_OP_GNU_const_index
- : (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u));
- else
- return dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr;
- }
- /* Return a pointer to a newly allocated address location description. If
- dwarf_split_debug_info is true, then record the address with the appropriate
- relocation. */
- static inline dw_loc_descr_ref
- new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
- {
- dw_loc_descr_ref ref = new_loc_descr (dw_addr_op (dtprel), 0, 0);
- ref->dw_loc_oprnd1.val_class = dw_val_class_addr;
- ref->dw_loc_oprnd1.v.val_addr = addr;
- ref->dtprel = dtprel;
- if (dwarf_split_debug_info)
- ref->dw_loc_oprnd1.val_entry
- = add_addr_table_entry (addr,
- dtprel ? ate_kind_rtx_dtprel : ate_kind_rtx);
- else
- ref->dw_loc_oprnd1.val_entry = NULL;
- return ref;
- }
- /* Section names used to hold DWARF debugging information. */
- #ifndef DEBUG_INFO_SECTION
- #define DEBUG_INFO_SECTION ".debug_info"
- #endif
- #ifndef DEBUG_DWO_INFO_SECTION
- #define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
- #endif
- #ifndef DEBUG_ABBREV_SECTION
- #define DEBUG_ABBREV_SECTION ".debug_abbrev"
- #endif
- #ifndef DEBUG_DWO_ABBREV_SECTION
- #define DEBUG_DWO_ABBREV_SECTION ".debug_abbrev.dwo"
- #endif
- #ifndef DEBUG_ARANGES_SECTION
- #define DEBUG_ARANGES_SECTION ".debug_aranges"
- #endif
- #ifndef DEBUG_ADDR_SECTION
- #define DEBUG_ADDR_SECTION ".debug_addr"
- #endif
- #ifndef DEBUG_NORM_MACINFO_SECTION
- #define DEBUG_NORM_MACINFO_SECTION ".debug_macinfo"
- #endif
- #ifndef DEBUG_DWO_MACINFO_SECTION
- #define DEBUG_DWO_MACINFO_SECTION ".debug_macinfo.dwo"
- #endif
- #ifndef DEBUG_MACINFO_SECTION
- #define DEBUG_MACINFO_SECTION \
- (!dwarf_split_debug_info \
- ? (DEBUG_NORM_MACINFO_SECTION) : (DEBUG_DWO_MACINFO_SECTION))
- #endif
- #ifndef DEBUG_NORM_MACRO_SECTION
- #define DEBUG_NORM_MACRO_SECTION ".debug_macro"
- #endif
- #ifndef DEBUG_DWO_MACRO_SECTION
- #define DEBUG_DWO_MACRO_SECTION ".debug_macro.dwo"
- #endif
- #ifndef DEBUG_MACRO_SECTION
- #define DEBUG_MACRO_SECTION \
- (!dwarf_split_debug_info \
- ? (DEBUG_NORM_MACRO_SECTION) : (DEBUG_DWO_MACRO_SECTION))
- #endif
- #ifndef DEBUG_LINE_SECTION
- #define DEBUG_LINE_SECTION ".debug_line"
- #endif
- #ifndef DEBUG_DWO_LINE_SECTION
- #define DEBUG_DWO_LINE_SECTION ".debug_line.dwo"
- #endif
- #ifndef DEBUG_LOC_SECTION
- #define DEBUG_LOC_SECTION ".debug_loc"
- #endif
- #ifndef DEBUG_DWO_LOC_SECTION
- #define DEBUG_DWO_LOC_SECTION ".debug_loc.dwo"
- #endif
- #ifndef DEBUG_PUBNAMES_SECTION
- #define DEBUG_PUBNAMES_SECTION \
- ((debug_generate_pub_sections == 2) \
- ? ".debug_gnu_pubnames" : ".debug_pubnames")
- #endif
- #ifndef DEBUG_PUBTYPES_SECTION
- #define DEBUG_PUBTYPES_SECTION \
- ((debug_generate_pub_sections == 2) \
- ? ".debug_gnu_pubtypes" : ".debug_pubtypes")
- #endif
- #define DEBUG_NORM_STR_OFFSETS_SECTION ".debug_str_offsets"
- #define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo"
- #ifndef DEBUG_STR_OFFSETS_SECTION
- #define DEBUG_STR_OFFSETS_SECTION \
- (!dwarf_split_debug_info \
- ? (DEBUG_NORM_STR_OFFSETS_SECTION) : (DEBUG_DWO_STR_OFFSETS_SECTION))
- #endif
- #ifndef DEBUG_STR_DWO_SECTION
- #define DEBUG_STR_DWO_SECTION ".debug_str.dwo"
- #endif
- #ifndef DEBUG_STR_SECTION
- #define DEBUG_STR_SECTION ".debug_str"
- #endif
- #ifndef DEBUG_RANGES_SECTION
- #define DEBUG_RANGES_SECTION ".debug_ranges"
- #endif
- /* Standard ELF section names for compiled code and data. */
- #ifndef TEXT_SECTION_NAME
- #define TEXT_SECTION_NAME ".text"
- #endif
- /* Section flags for .debug_macinfo/.debug_macro section. */
- #define DEBUG_MACRO_SECTION_FLAGS \
- (dwarf_split_debug_info ? SECTION_DEBUG | SECTION_EXCLUDE : SECTION_DEBUG)
- /* Section flags for .debug_str section. */
- #define DEBUG_STR_SECTION_FLAGS \
- (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings \
- ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1 \
- : SECTION_DEBUG)
- /* Section flags for .debug_str.dwo section. */
- #define DEBUG_STR_DWO_SECTION_FLAGS (SECTION_DEBUG | SECTION_EXCLUDE)
- /* Labels we insert at beginning sections we can reference instead of
- the section names themselves. */
- #ifndef TEXT_SECTION_LABEL
- #define TEXT_SECTION_LABEL "Ltext"
- #endif
- #ifndef COLD_TEXT_SECTION_LABEL
- #define COLD_TEXT_SECTION_LABEL "Ltext_cold"
- #endif
- #ifndef DEBUG_LINE_SECTION_LABEL
- #define DEBUG_LINE_SECTION_LABEL "Ldebug_line"
- #endif
- #ifndef DEBUG_SKELETON_LINE_SECTION_LABEL
- #define DEBUG_SKELETON_LINE_SECTION_LABEL "Lskeleton_debug_line"
- #endif
- #ifndef DEBUG_INFO_SECTION_LABEL
- #define DEBUG_INFO_SECTION_LABEL "Ldebug_info"
- #endif
- #ifndef DEBUG_SKELETON_INFO_SECTION_LABEL
- #define DEBUG_SKELETON_INFO_SECTION_LABEL "Lskeleton_debug_info"
- #endif
- #ifndef DEBUG_ABBREV_SECTION_LABEL
- #define DEBUG_ABBREV_SECTION_LABEL "Ldebug_abbrev"
- #endif
- #ifndef DEBUG_SKELETON_ABBREV_SECTION_LABEL
- #define DEBUG_SKELETON_ABBREV_SECTION_LABEL "Lskeleton_debug_abbrev"
- #endif
- #ifndef DEBUG_ADDR_SECTION_LABEL
- #define DEBUG_ADDR_SECTION_LABEL "Ldebug_addr"
- #endif
- #ifndef DEBUG_LOC_SECTION_LABEL
- #define DEBUG_LOC_SECTION_LABEL "Ldebug_loc"
- #endif
- #ifndef DEBUG_RANGES_SECTION_LABEL
- #define DEBUG_RANGES_SECTION_LABEL "Ldebug_ranges"
- #endif
- #ifndef DEBUG_MACINFO_SECTION_LABEL
- #define DEBUG_MACINFO_SECTION_LABEL "Ldebug_macinfo"
- #endif
- #ifndef DEBUG_MACRO_SECTION_LABEL
- #define DEBUG_MACRO_SECTION_LABEL "Ldebug_macro"
- #endif
- #define SKELETON_COMP_DIE_ABBREV 1
- #define SKELETON_TYPE_DIE_ABBREV 2
- /* Definitions of defaults for formats and names of various special
- (artificial) labels which may be generated within this file (when the -g
- options is used and DWARF2_DEBUGGING_INFO is in effect.
- If necessary, these may be overridden from within the tm.h file, but
- typically, overriding these defaults is unnecessary. */
- static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char cold_text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char debug_skeleton_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char debug_skeleton_abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char debug_addr_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char debug_skeleton_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
- static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
- #ifndef TEXT_END_LABEL
- #define TEXT_END_LABEL "Letext"
- #endif
- #ifndef COLD_END_LABEL
- #define COLD_END_LABEL "Letext_cold"
- #endif
- #ifndef BLOCK_BEGIN_LABEL
- #define BLOCK_BEGIN_LABEL "LBB"
- #endif
- #ifndef BLOCK_END_LABEL
- #define BLOCK_END_LABEL "LBE"
- #endif
- #ifndef LINE_CODE_LABEL
- #define LINE_CODE_LABEL "LM"
- #endif
- /* Return the root of the DIE's built for the current compilation unit. */
- static dw_die_ref
- comp_unit_die (void)
- {
- if (!single_comp_unit_die)
- single_comp_unit_die = gen_compile_unit_die (NULL);
- return single_comp_unit_die;
- }
- /* We allow a language front-end to designate a function that is to be
- called to "demangle" any name before it is put into a DIE. */
- static const char *(*demangle_name_func) (const char *);
- void
- dwarf2out_set_demangle_name_func (const char *(*func) (const char *))
- {
- demangle_name_func = func;
- }
- /* Test if rtl node points to a pseudo register. */
- static inline int
- is_pseudo_reg (const_rtx rtl)
- {
- return ((REG_P (rtl) && REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
- || (GET_CODE (rtl) == SUBREG
- && REGNO (SUBREG_REG (rtl)) >= FIRST_PSEUDO_REGISTER));
- }
- /* Return a reference to a type, with its const and volatile qualifiers
- removed. */
- static inline tree
- type_main_variant (tree type)
- {
- type = TYPE_MAIN_VARIANT (type);
- /* ??? There really should be only one main variant among any group of
- variants of a given type (and all of the MAIN_VARIANT values for all
- members of the group should point to that one type) but sometimes the C
- front-end messes this up for array types, so we work around that bug
- here. */
- if (TREE_CODE (type) == ARRAY_TYPE)
- while (type != TYPE_MAIN_VARIANT (type))
- type = TYPE_MAIN_VARIANT (type);
- return type;
- }
- /* Return nonzero if the given type node represents a tagged type. */
- static inline int
- is_tagged_type (const_tree type)
- {
- enum tree_code code = TREE_CODE (type);
- return (code == RECORD_TYPE || code == UNION_TYPE
- || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
- }
- /* Set label to debug_info_section_label + die_offset of a DIE reference. */
- static void
- get_ref_die_offset_label (char *label, dw_die_ref ref)
- {
- sprintf (label, "%s+%ld", debug_info_section_label, ref->die_offset);
- }
- /* Return die_offset of a DIE reference to a base type. */
- static unsigned long int
- get_base_type_offset (dw_die_ref ref)
- {
- if (ref->die_offset)
- return ref->die_offset;
- if (comp_unit_die ()->die_abbrev)
- {
- calc_base_type_die_sizes ();
- gcc_assert (ref->die_offset);
- }
- return ref->die_offset;
- }
- /* Return die_offset of a DIE reference other than base type. */
- static unsigned long int
- get_ref_die_offset (dw_die_ref ref)
- {
- gcc_assert (ref->die_offset);
- return ref->die_offset;
- }
- /* Convert a DIE tag into its string name. */
- static const char *
- dwarf_tag_name (unsigned int tag)
- {
- const char *name = get_DW_TAG_name (tag);
- if (name != NULL)
- return name;
- return "DW_TAG_<unknown>";
- }
- /* Convert a DWARF attribute code into its string name. */
- static const char *
- dwarf_attr_name (unsigned int attr)
- {
- const char *name;
- switch (attr)
- {
- #if VMS_DEBUGGING_INFO
- case DW_AT_HP_prologue:
- return "DW_AT_HP_prologue";
- #else
- case DW_AT_MIPS_loop_unroll_factor:
- return "DW_AT_MIPS_loop_unroll_factor";
- #endif
- #if VMS_DEBUGGING_INFO
- case DW_AT_HP_epilogue:
- return "DW_AT_HP_epilogue";
- #else
- case DW_AT_MIPS_stride:
- return "DW_AT_MIPS_stride";
- #endif
- }
- name = get_DW_AT_name (attr);
- if (name != NULL)
- return name;
- return "DW_AT_<unknown>";
- }
- /* Convert a DWARF value form code into its string name. */
- static const char *
- dwarf_form_name (unsigned int form)
- {
- const char *name = get_DW_FORM_name (form);
- if (name != NULL)
- return name;
- return "DW_FORM_<unknown>";
- }
- /* Determine the "ultimate origin" of a decl. The decl may be an inlined
- instance of an inlined instance of a decl which is local to an inline
- function, so we have to trace all of the way back through the origin chain
- to find out what sort of node actually served as the original seed for the
- given block. */
- static tree
- decl_ultimate_origin (const_tree decl)
- {
- if (!CODE_CONTAINS_STRUCT (TREE_CODE (decl), TS_DECL_COMMON))
- return NULL_TREE;
- /* DECL_ABSTRACT_ORIGIN can point to itself; ignore that if
- we're trying to output the abstract instance of this function. */
- if (DECL_ABSTRACT_P (decl) && DECL_ABSTRACT_ORIGIN (decl) == decl)
- return NULL_TREE;
- /* Since the DECL_ABSTRACT_ORIGIN for a DECL is supposed to be the
- most distant ancestor, this should never happen. */
- gcc_assert (!DECL_FROM_INLINE (DECL_ORIGIN (decl)));
- return DECL_ABSTRACT_ORIGIN (decl);
- }
- /* Get the class to which DECL belongs, if any. In g++, the DECL_CONTEXT
- of a virtual function may refer to a base class, so we check the 'this'
- parameter. */
- static tree
- decl_class_context (tree decl)
- {
- tree context = NULL_TREE;
- if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl))
- context = DECL_CONTEXT (decl);
- else
- context = TYPE_MAIN_VARIANT
- (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
- if (context && !TYPE_P (context))
- context = NULL_TREE;
- return context;
- }
- /* Add an attribute/value pair to a DIE. */
- static inline void
- add_dwarf_attr (dw_die_ref die, dw_attr_ref attr)
- {
- /* Maybe this should be an assert? */
- if (die == NULL)
- return;
- vec_safe_reserve (die->die_attr, 1);
- vec_safe_push (die->die_attr, *attr);
- }
- static inline enum dw_val_class
- AT_class (dw_attr_ref a)
- {
- return a->dw_attr_val.val_class;
- }
- /* Return the index for any attribute that will be referenced with a
- DW_FORM_GNU_addr_index or DW_FORM_GNU_str_index. String indices
- are stored in dw_attr_val.v.val_str for reference counting
- pruning. */
- static inline unsigned int
- AT_index (dw_attr_ref a)
- {
- if (AT_class (a) == dw_val_class_str)
- return a->dw_attr_val.v.val_str->index;
- else if (a->dw_attr_val.val_entry != NULL)
- return a->dw_attr_val.val_entry->index;
- return NOT_INDEXED;
- }
- /* Add a flag value attribute to a DIE. */
- static inline void
- add_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int flag)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_flag;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_flag = flag;
- add_dwarf_attr (die, &attr);
- }
- static inline unsigned
- AT_flag (dw_attr_ref a)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_flag);
- return a->dw_attr_val.v.val_flag;
- }
- /* Add a signed integer attribute value to a DIE. */
- static inline void
- add_AT_int (dw_die_ref die, enum dwarf_attribute attr_kind, HOST_WIDE_INT int_val)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_const;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_int = int_val;
- add_dwarf_attr (die, &attr);
- }
- static inline HOST_WIDE_INT
- AT_int (dw_attr_ref a)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_const);
- return a->dw_attr_val.v.val_int;
- }
- /* Add an unsigned integer attribute value to a DIE. */
- static inline void
- add_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind,
- unsigned HOST_WIDE_INT unsigned_val)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_unsigned = unsigned_val;
- add_dwarf_attr (die, &attr);
- }
- static inline unsigned HOST_WIDE_INT
- AT_unsigned (dw_attr_ref a)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_unsigned_const);
- return a->dw_attr_val.v.val_unsigned;
- }
- /* Add an unsigned wide integer attribute value to a DIE. */
- static inline void
- add_AT_wide (dw_die_ref die, enum dwarf_attribute attr_kind,
- const wide_int& w)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_wide_int;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_wide = ggc_alloc<wide_int> ();
- *attr.dw_attr_val.v.val_wide = w;
- add_dwarf_attr (die, &attr);
- }
- /* Add an unsigned double integer attribute value to a DIE. */
- static inline void
- add_AT_double (dw_die_ref die, enum dwarf_attribute attr_kind,
- HOST_WIDE_INT high, unsigned HOST_WIDE_INT low)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_const_double;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_double.high = high;
- attr.dw_attr_val.v.val_double.low = low;
- add_dwarf_attr (die, &attr);
- }
- /* Add a floating point attribute value to a DIE and return it. */
- static inline void
- add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind,
- unsigned int length, unsigned int elt_size, unsigned char *array)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_vec;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_vec.length = length;
- attr.dw_attr_val.v.val_vec.elt_size = elt_size;
- attr.dw_attr_val.v.val_vec.array = array;
- add_dwarf_attr (die, &attr);
- }
- /* Add an 8-byte data attribute value to a DIE. */
- static inline void
- add_AT_data8 (dw_die_ref die, enum dwarf_attribute attr_kind,
- unsigned char data8[8])
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_data8;
- attr.dw_attr_val.val_entry = NULL;
- memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
- add_dwarf_attr (die, &attr);
- }
- /* Add DW_AT_low_pc and DW_AT_high_pc to a DIE. When using
- dwarf_split_debug_info, address attributes in dies destined for the
- final executable have force_direct set to avoid using indexed
- references. */
- static inline void
- add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high,
- bool force_direct)
- {
- dw_attr_node attr;
- char * lbl_id;
- lbl_id = xstrdup (lbl_low);
- attr.dw_attr = DW_AT_low_pc;
- attr.dw_attr_val.val_class = dw_val_class_lbl_id;
- attr.dw_attr_val.v.val_lbl_id = lbl_id;
- if (dwarf_split_debug_info && !force_direct)
- attr.dw_attr_val.val_entry
- = add_addr_table_entry (lbl_id, ate_kind_label);
- else
- attr.dw_attr_val.val_entry = NULL;
- add_dwarf_attr (die, &attr);
- attr.dw_attr = DW_AT_high_pc;
- if (dwarf_version < 4)
- attr.dw_attr_val.val_class = dw_val_class_lbl_id;
- else
- attr.dw_attr_val.val_class = dw_val_class_high_pc;
- lbl_id = xstrdup (lbl_high);
- attr.dw_attr_val.v.val_lbl_id = lbl_id;
- if (attr.dw_attr_val.val_class == dw_val_class_lbl_id
- && dwarf_split_debug_info && !force_direct)
- attr.dw_attr_val.val_entry
- = add_addr_table_entry (lbl_id, ate_kind_label);
- else
- attr.dw_attr_val.val_entry = NULL;
- add_dwarf_attr (die, &attr);
- }
- /* Hash and equality functions for debug_str_hash. */
- hashval_t
- indirect_string_hasher::hash (indirect_string_node *x)
- {
- return htab_hash_string (x->str);
- }
- bool
- indirect_string_hasher::equal (indirect_string_node *x1, const char *x2)
- {
- return strcmp (x1->str, x2) == 0;
- }
- /* Add STR to the given string hash table. */
- static struct indirect_string_node *
- find_AT_string_in_table (const char *str,
- hash_table<indirect_string_hasher> *table)
- {
- struct indirect_string_node *node;
- indirect_string_node **slot
- = table->find_slot_with_hash (str, htab_hash_string (str), INSERT);
- if (*slot == NULL)
- {
- node = ggc_cleared_alloc<indirect_string_node> ();
- node->str = ggc_strdup (str);
- *slot = node;
- }
- else
- node = *slot;
- node->refcount++;
- return node;
- }
- /* Add STR to the indirect string hash table. */
- static struct indirect_string_node *
- find_AT_string (const char *str)
- {
- if (! debug_str_hash)
- debug_str_hash = hash_table<indirect_string_hasher>::create_ggc (10);
- return find_AT_string_in_table (str, debug_str_hash);
- }
- /* Add a string attribute value to a DIE. */
- static inline void
- add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
- {
- dw_attr_node attr;
- struct indirect_string_node *node;
- node = find_AT_string (str);
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_str;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_str = node;
- add_dwarf_attr (die, &attr);
- }
- static inline const char *
- AT_string (dw_attr_ref a)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_str);
- return a->dw_attr_val.v.val_str->str;
- }
- /* Call this function directly to bypass AT_string_form's logic to put
- the string inline in the die. */
- static void
- set_indirect_string (struct indirect_string_node *node)
- {
- char label[32];
- /* Already indirect is a no op. */
- if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index)
- {
- gcc_assert (node->label);
- return;
- }
- ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
- ++dw2_string_counter;
- node->label = xstrdup (label);
- if (!dwarf_split_debug_info)
- {
- node->form = DW_FORM_strp;
- node->index = NOT_INDEXED;
- }
- else
- {
- node->form = DW_FORM_GNU_str_index;
- node->index = NO_INDEX_ASSIGNED;
- }
- }
- /* Find out whether a string should be output inline in DIE
- or out-of-line in .debug_str section. */
- static enum dwarf_form
- find_string_form (struct indirect_string_node *node)
- {
- unsigned int len;
- if (node->form)
- return node->form;
- len = strlen (node->str) + 1;
- /* If the string is shorter or equal to the size of the reference, it is
- always better to put it inline. */
- if (len <= DWARF_OFFSET_SIZE || node->refcount == 0)
- return node->form = DW_FORM_string;
- /* If we cannot expect the linker to merge strings in .debug_str
- section, only put it into .debug_str if it is worth even in this
- single module. */
- if (DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
- || ((debug_str_section->common.flags & SECTION_MERGE) == 0
- && (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
- return node->form = DW_FORM_string;
- set_indirect_string (node);
- return node->form;
- }
- /* Find out whether the string referenced from the attribute should be
- output inline in DIE or out-of-line in .debug_str section. */
- static enum dwarf_form
- AT_string_form (dw_attr_ref a)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_str);
- return find_string_form (a->dw_attr_val.v.val_str);
- }
- /* Add a DIE reference attribute value to a DIE. */
- static inline void
- add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_die)
- {
- dw_attr_node attr;
- #ifdef ENABLE_CHECKING
- gcc_assert (targ_die != NULL);
- #else
- /* With LTO we can end up trying to reference something we didn't create
- a DIE for. Avoid crashing later on a NULL referenced DIE. */
- if (targ_die == NULL)
- return;
- #endif
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_die_ref;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_die_ref.die = targ_die;
- attr.dw_attr_val.v.val_die_ref.external = 0;
- add_dwarf_attr (die, &attr);
- }
- /* Change DIE reference REF to point to NEW_DIE instead. */
- static inline void
- change_AT_die_ref (dw_attr_ref ref, dw_die_ref new_die)
- {
- gcc_assert (ref->dw_attr_val.val_class == dw_val_class_die_ref);
- ref->dw_attr_val.v.val_die_ref.die = new_die;
- ref->dw_attr_val.v.val_die_ref.external = 0;
- }
- /* Add an AT_specification attribute to a DIE, and also make the back
- pointer from the specification to the definition. */
- static inline void
- add_AT_specification (dw_die_ref die, dw_die_ref targ_die)
- {
- add_AT_die_ref (die, DW_AT_specification, targ_die);
- gcc_assert (!targ_die->die_definition);
- targ_die->die_definition = die;
- }
- static inline dw_die_ref
- AT_ref (dw_attr_ref a)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_die_ref);
- return a->dw_attr_val.v.val_die_ref.die;
- }
- static inline int
- AT_ref_external (dw_attr_ref a)
- {
- if (a && AT_class (a) == dw_val_class_die_ref)
- return a->dw_attr_val.v.val_die_ref.external;
- return 0;
- }
- static inline void
- set_AT_ref_external (dw_attr_ref a, int i)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_die_ref);
- a->dw_attr_val.v.val_die_ref.external = i;
- }
- /* Add an FDE reference attribute value to a DIE. */
- static inline void
- add_AT_fde_ref (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int targ_fde)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_fde_ref;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_fde_index = targ_fde;
- add_dwarf_attr (die, &attr);
- }
- /* Add a location description attribute value to a DIE. */
- static inline void
- add_AT_loc (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_descr_ref loc)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_loc;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_loc = loc;
- add_dwarf_attr (die, &attr);
- }
- static inline dw_loc_descr_ref
- AT_loc (dw_attr_ref a)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_loc);
- return a->dw_attr_val.v.val_loc;
- }
- static inline void
- add_AT_loc_list (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_list_ref loc_list)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_loc_list;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_loc_list = loc_list;
- add_dwarf_attr (die, &attr);
- have_location_lists = true;
- }
- static inline dw_loc_list_ref
- AT_loc_list (dw_attr_ref a)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
- return a->dw_attr_val.v.val_loc_list;
- }
- static inline dw_loc_list_ref *
- AT_loc_list_ptr (dw_attr_ref a)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
- return &a->dw_attr_val.v.val_loc_list;
- }
- struct addr_hasher : ggc_hasher<addr_table_entry *>
- {
- static hashval_t hash (addr_table_entry *);
- static bool equal (addr_table_entry *, addr_table_entry *);
- };
- /* Table of entries into the .debug_addr section. */
- static GTY (()) hash_table<addr_hasher> *addr_index_table;
- /* Hash an address_table_entry. */
- hashval_t
- addr_hasher::hash (addr_table_entry *a)
- {
- inchash::hash hstate;
- switch (a->kind)
- {
- case ate_kind_rtx:
- hstate.add_int (0);
- break;
- case ate_kind_rtx_dtprel:
- hstate.add_int (1);
- break;
- case ate_kind_label:
- return htab_hash_string (a->addr.label);
- default:
- gcc_unreachable ();
- }
- inchash::add_rtx (a->addr.rtl, hstate);
- return hstate.end ();
- }
- /* Determine equality for two address_table_entries. */
- bool
- addr_hasher::equal (addr_table_entry *a1, addr_table_entry *a2)
- {
- if (a1->kind != a2->kind)
- return 0;
- switch (a1->kind)
- {
- case ate_kind_rtx:
- case ate_kind_rtx_dtprel:
- return rtx_equal_p (a1->addr.rtl, a2->addr.rtl);
- case ate_kind_label:
- return strcmp (a1->addr.label, a2->addr.label) == 0;
- default:
- gcc_unreachable ();
- }
- }
- /* Initialize an addr_table_entry. */
- void
- init_addr_table_entry (addr_table_entry *e, enum ate_kind kind, void *addr)
- {
- e->kind = kind;
- switch (kind)
- {
- case ate_kind_rtx:
- case ate_kind_rtx_dtprel:
- e->addr.rtl = (rtx) addr;
- break;
- case ate_kind_label:
- e->addr.label = (char *) addr;
- break;
- }
- e->refcount = 0;
- e->index = NO_INDEX_ASSIGNED;
- }
- /* Add attr to the address table entry to the table. Defer setting an
- index until output time. */
- static addr_table_entry *
- add_addr_table_entry (void *addr, enum ate_kind kind)
- {
- addr_table_entry *node;
- addr_table_entry finder;
- gcc_assert (dwarf_split_debug_info);
- if (! addr_index_table)
- addr_index_table = hash_table<addr_hasher>::create_ggc (10);
- init_addr_table_entry (&finder, kind, addr);
- addr_table_entry **slot = addr_index_table->find_slot (&finder, INSERT);
- if (*slot == HTAB_EMPTY_ENTRY)
- {
- node = ggc_cleared_alloc<addr_table_entry> ();
- init_addr_table_entry (node, kind, addr);
- *slot = node;
- }
- else
- node = *slot;
- node->refcount++;
- return node;
- }
- /* Remove an entry from the addr table by decrementing its refcount.
- Strictly, decrementing the refcount would be enough, but the
- assertion that the entry is actually in the table has found
- bugs. */
- static void
- remove_addr_table_entry (addr_table_entry *entry)
- {
- gcc_assert (dwarf_split_debug_info && addr_index_table);
- /* After an index is assigned, the table is frozen. */
- gcc_assert (entry->refcount > 0 && entry->index == NO_INDEX_ASSIGNED);
- entry->refcount--;
- }
- /* Given a location list, remove all addresses it refers to from the
- address_table. */
- static void
- remove_loc_list_addr_table_entries (dw_loc_descr_ref descr)
- {
- for (; descr; descr = descr->dw_loc_next)
- if (descr->dw_loc_oprnd1.val_entry != NULL)
- {
- gcc_assert (descr->dw_loc_oprnd1.val_entry->index == NO_INDEX_ASSIGNED);
- remove_addr_table_entry (descr->dw_loc_oprnd1.val_entry);
- }
- }
- /* A helper function for dwarf2out_finish called through
- htab_traverse. Assign an addr_table_entry its index. All entries
- must be collected into the table when this function is called,
- because the indexing code relies on htab_traverse to traverse nodes
- in the same order for each run. */
- int
- index_addr_table_entry (addr_table_entry **h, unsigned int *index)
- {
- addr_table_entry *node = *h;
- /* Don't index unreferenced nodes. */
- if (node->refcount == 0)
- return 1;
- gcc_assert (node->index == NO_INDEX_ASSIGNED);
- node->index = *index;
- *index += 1;
- return 1;
- }
- /* Add an address constant attribute value to a DIE. When using
- dwarf_split_debug_info, address attributes in dies destined for the
- final executable should be direct references--setting the parameter
- force_direct ensures this behavior. */
- static inline void
- add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr,
- bool force_direct)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_addr;
- attr.dw_attr_val.v.val_addr = addr;
- if (dwarf_split_debug_info && !force_direct)
- attr.dw_attr_val.val_entry = add_addr_table_entry (addr, ate_kind_rtx);
- else
- attr.dw_attr_val.val_entry = NULL;
- add_dwarf_attr (die, &attr);
- }
- /* Get the RTX from to an address DIE attribute. */
- static inline rtx
- AT_addr (dw_attr_ref a)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_addr);
- return a->dw_attr_val.v.val_addr;
- }
- /* Add a file attribute value to a DIE. */
- static inline void
- add_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind,
- struct dwarf_file_data *fd)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_file;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_file = fd;
- add_dwarf_attr (die, &attr);
- }
- /* Get the dwarf_file_data from a file DIE attribute. */
- static inline struct dwarf_file_data *
- AT_file (dw_attr_ref a)
- {
- gcc_assert (a && AT_class (a) == dw_val_class_file);
- return a->dw_attr_val.v.val_file;
- }
- /* Add a vms delta attribute value to a DIE. */
- static inline void
- add_AT_vms_delta (dw_die_ref die, enum dwarf_attribute attr_kind,
- const char *lbl1, const char *lbl2)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_vms_delta;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1);
- attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2);
- add_dwarf_attr (die, &attr);
- }
- /* Add a label identifier attribute value to a DIE. */
- static inline void
- add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind,
- const char *lbl_id)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_lbl_id;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
- if (dwarf_split_debug_info)
- attr.dw_attr_val.val_entry
- = add_addr_table_entry (attr.dw_attr_val.v.val_lbl_id,
- ate_kind_label);
- add_dwarf_attr (die, &attr);
- }
- /* Add a section offset attribute value to a DIE, an offset into the
- debug_line section. */
- static inline void
- add_AT_lineptr (dw_die_ref die, enum dwarf_attribute attr_kind,
- const char *label)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_lineptr;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
- add_dwarf_attr (die, &attr);
- }
- /* Add a section offset attribute value to a DIE, an offset into the
- debug_macinfo section. */
- static inline void
- add_AT_macptr (dw_die_ref die, enum dwarf_attribute attr_kind,
- const char *label)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_macptr;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
- add_dwarf_attr (die, &attr);
- }
- /* Add an offset attribute value to a DIE. */
- static inline void
- add_AT_offset (dw_die_ref die, enum dwarf_attribute attr_kind,
- unsigned HOST_WIDE_INT offset)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_offset;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_offset = offset;
- add_dwarf_attr (die, &attr);
- }
- /* Add a range_list attribute value to a DIE. When using
- dwarf_split_debug_info, address attributes in dies destined for the
- final executable should be direct references--setting the parameter
- force_direct ensures this behavior. */
- #define UNRELOCATED_OFFSET ((addr_table_entry *) 1)
- #define RELOCATED_OFFSET (NULL)
- static void
- add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
- long unsigned int offset, bool force_direct)
- {
- dw_attr_node attr;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_range_list;
- /* For the range_list attribute, use val_entry to store whether the
- offset should follow split-debug-info or normal semantics. This
- value is read in output_range_list_offset. */
- if (dwarf_split_debug_info && !force_direct)
- attr.dw_attr_val.val_entry = UNRELOCATED_OFFSET;
- else
- attr.dw_attr_val.val_entry = RELOCATED_OFFSET;
- attr.dw_attr_val.v.val_offset = offset;
- add_dwarf_attr (die, &attr);
- }
- /* Return the start label of a delta attribute. */
- static inline const char *
- AT_vms_delta1 (dw_attr_ref a)
- {
- gcc_assert (a && (AT_class (a) == dw_val_class_vms_delta));
- return a->dw_attr_val.v.val_vms_delta.lbl1;
- }
- /* Return the end label of a delta attribute. */
- static inline const char *
- AT_vms_delta2 (dw_attr_ref a)
- {
- gcc_assert (a && (AT_class (a) == dw_val_class_vms_delta));
- return a->dw_attr_val.v.val_vms_delta.lbl2;
- }
- static inline const char *
- AT_lbl (dw_attr_ref a)
- {
- gcc_assert (a && (AT_class (a) == dw_val_class_lbl_id
- || AT_class (a) == dw_val_class_lineptr
- || AT_class (a) == dw_val_class_macptr
- || AT_class (a) == dw_val_class_high_pc));
- return a->dw_attr_val.v.val_lbl_id;
- }
- /* Get the attribute of type attr_kind. */
- static dw_attr_ref
- get_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
- {
- dw_attr_ref a;
- unsigned ix;
- dw_die_ref spec = NULL;
- if (! die)
- return NULL;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- if (a->dw_attr == attr_kind)
- return a;
- else if (a->dw_attr == DW_AT_specification
- || a->dw_attr == DW_AT_abstract_origin)
- spec = AT_ref (a);
- if (spec)
- return get_AT (spec, attr_kind);
- return NULL;
- }
- /* Returns the parent of the declaration of DIE. */
- static dw_die_ref
- get_die_parent (dw_die_ref die)
- {
- dw_die_ref t;
- if (!die)
- return NULL;
- if ((t = get_AT_ref (die, DW_AT_abstract_origin))
- || (t = get_AT_ref (die, DW_AT_specification)))
- die = t;
- return die->die_parent;
- }
- /* Return the "low pc" attribute value, typically associated with a subprogram
- DIE. Return null if the "low pc" attribute is either not present, or if it
- cannot be represented as an assembler label identifier. */
- static inline const char *
- get_AT_low_pc (dw_die_ref die)
- {
- dw_attr_ref a = get_AT (die, DW_AT_low_pc);
- return a ? AT_lbl (a) : NULL;
- }
- /* Return the "high pc" attribute value, typically associated with a subprogram
- DIE. Return null if the "high pc" attribute is either not present, or if it
- cannot be represented as an assembler label identifier. */
- static inline const char *
- get_AT_hi_pc (dw_die_ref die)
- {
- dw_attr_ref a = get_AT (die, DW_AT_high_pc);
- return a ? AT_lbl (a) : NULL;
- }
- /* Return the value of the string attribute designated by ATTR_KIND, or
- NULL if it is not present. */
- static inline const char *
- get_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind)
- {
- dw_attr_ref a = get_AT (die, attr_kind);
- return a ? AT_string (a) : NULL;
- }
- /* Return the value of the flag attribute designated by ATTR_KIND, or -1
- if it is not present. */
- static inline int
- get_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind)
- {
- dw_attr_ref a = get_AT (die, attr_kind);
- return a ? AT_flag (a) : 0;
- }
- /* Return the value of the unsigned attribute designated by ATTR_KIND, or 0
- if it is not present. */
- static inline unsigned
- get_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind)
- {
- dw_attr_ref a = get_AT (die, attr_kind);
- return a ? AT_unsigned (a) : 0;
- }
- static inline dw_die_ref
- get_AT_ref (dw_die_ref die, enum dwarf_attribute attr_kind)
- {
- dw_attr_ref a = get_AT (die, attr_kind);
- return a ? AT_ref (a) : NULL;
- }
- static inline struct dwarf_file_data *
- get_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind)
- {
- dw_attr_ref a = get_AT (die, attr_kind);
- return a ? AT_file (a) : NULL;
- }
- /* Return TRUE if the language is C++. */
- static inline bool
- is_cxx (void)
- {
- unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
- return (lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus
- || lang == DW_LANG_C_plus_plus_11 || lang == DW_LANG_C_plus_plus_14);
- }
- /* Return TRUE if the language is Java. */
- static inline bool
- is_java (void)
- {
- unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
- return lang == DW_LANG_Java;
- }
- /* Return TRUE if the language is Fortran. */
- static inline bool
- is_fortran (void)
- {
- unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
- return (lang == DW_LANG_Fortran77
- || lang == DW_LANG_Fortran90
- || lang == DW_LANG_Fortran95
- || lang == DW_LANG_Fortran03
- || lang == DW_LANG_Fortran08);
- }
- /* Return TRUE if the language is Ada. */
- static inline bool
- is_ada (void)
- {
- unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
- return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
- }
- /* Remove the specified attribute if present. */
- static void
- remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
- {
- dw_attr_ref a;
- unsigned ix;
- if (! die)
- return;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- if (a->dw_attr == attr_kind)
- {
- if (AT_class (a) == dw_val_class_str)
- if (a->dw_attr_val.v.val_str->refcount)
- a->dw_attr_val.v.val_str->refcount--;
- /* vec::ordered_remove should help reduce the number of abbrevs
- that are needed. */
- die->die_attr->ordered_remove (ix);
- return;
- }
- }
- /* Remove CHILD from its parent. PREV must have the property that
- PREV->DIE_SIB == CHILD. Does not alter CHILD. */
- static void
- remove_child_with_prev (dw_die_ref child, dw_die_ref prev)
- {
- gcc_assert (child->die_parent == prev->die_parent);
- gcc_assert (prev->die_sib == child);
- if (prev == child)
- {
- gcc_assert (child->die_parent->die_child == child);
- prev = NULL;
- }
- else
- prev->die_sib = child->die_sib;
- if (child->die_parent->die_child == child)
- child->die_parent->die_child = prev;
- }
- /* Replace OLD_CHILD with NEW_CHILD. PREV must have the property that
- PREV->DIE_SIB == OLD_CHILD. Does not alter OLD_CHILD. */
- static void
- replace_child (dw_die_ref old_child, dw_die_ref new_child, dw_die_ref prev)
- {
- dw_die_ref parent = old_child->die_parent;
- gcc_assert (parent == prev->die_parent);
- gcc_assert (prev->die_sib == old_child);
- new_child->die_parent = parent;
- if (prev == old_child)
- {
- gcc_assert (parent->die_child == old_child);
- new_child->die_sib = new_child;
- }
- else
- {
- prev->die_sib = new_child;
- new_child->die_sib = old_child->die_sib;
- }
- if (old_child->die_parent->die_child == old_child)
- old_child->die_parent->die_child = new_child;
- }
- /* Move all children from OLD_PARENT to NEW_PARENT. */
- static void
- move_all_children (dw_die_ref old_parent, dw_die_ref new_parent)
- {
- dw_die_ref c;
- new_parent->die_child = old_parent->die_child;
- old_parent->die_child = NULL;
- FOR_EACH_CHILD (new_parent, c, c->die_parent = new_parent);
- }
- /* Remove child DIE whose die_tag is TAG. Do nothing if no child
- matches TAG. */
- static void
- remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
- {
- dw_die_ref c;
- c = die->die_child;
- if (c) do {
- dw_die_ref prev = c;
- c = c->die_sib;
- while (c->die_tag == tag)
- {
- remove_child_with_prev (c, prev);
- /* Might have removed every child. */
- if (c == c->die_sib)
- return;
- c = c->die_sib;
- }
- } while (c != die->die_child);
- }
- /* Add a CHILD_DIE as the last child of DIE. */
- static void
- add_child_die (dw_die_ref die, dw_die_ref child_die)
- {
- /* FIXME this should probably be an assert. */
- if (! die || ! child_die)
- return;
- gcc_assert (die != child_die);
- child_die->die_parent = die;
- if (die->die_child)
- {
- child_die->die_sib = die->die_child->die_sib;
- die->die_child->die_sib = child_die;
- }
- else
- child_die->die_sib = child_die;
- die->die_child = child_die;
- }
- /* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
- is the specification, to the end of PARENT's list of children.
- This is done by removing and re-adding it. */
- static void
- splice_child_die (dw_die_ref parent, dw_die_ref child)
- {
- dw_die_ref p;
- /* We want the declaration DIE from inside the class, not the
- specification DIE at toplevel. */
- if (child->die_parent != parent)
- {
- dw_die_ref tmp = get_AT_ref (child, DW_AT_specification);
- if (tmp)
- child = tmp;
- }
- gcc_assert (child->die_parent == parent
- || (child->die_parent
- == get_AT_ref (parent, DW_AT_specification)));
- for (p = child->die_parent->die_child; ; p = p->die_sib)
- if (p->die_sib == child)
- {
- remove_child_with_prev (child, p);
- break;
- }
- add_child_die (parent, child);
- }
- /* Return a pointer to a newly created DIE node. */
- static inline dw_die_ref
- new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
- {
- dw_die_ref die = ggc_cleared_alloc<die_node> ();
- die->die_tag = tag_value;
- if (parent_die != NULL)
- add_child_die (parent_die, die);
- else
- {
- limbo_die_node *limbo_node;
- limbo_node = ggc_cleared_alloc<limbo_die_node> ();
- limbo_node->die = die;
- limbo_node->created_for = t;
- limbo_node->next = limbo_die_list;
- limbo_die_list = limbo_node;
- }
- return die;
- }
- /* Return the DIE associated with the given type specifier. */
- static inline dw_die_ref
- lookup_type_die (tree type)
- {
- return TYPE_SYMTAB_DIE (type);
- }
- /* Given a TYPE_DIE representing the type TYPE, if TYPE is an
- anonymous type named by the typedef TYPE_DIE, return the DIE of the
- anonymous type instead the one of the naming typedef. */
- static inline dw_die_ref
- strip_naming_typedef (tree type, dw_die_ref type_die)
- {
- if (type
- && TREE_CODE (type) == RECORD_TYPE
- && type_die
- && type_die->die_tag == DW_TAG_typedef
- && is_naming_typedef_decl (TYPE_NAME (type)))
- type_die = get_AT_ref (type_die, DW_AT_type);
- return type_die;
- }
- /* Like lookup_type_die, but if type is an anonymous type named by a
- typedef[1], return the DIE of the anonymous type instead the one of
- the naming typedef. This is because in gen_typedef_die, we did
- equate the anonymous struct named by the typedef with the DIE of
- the naming typedef. So by default, lookup_type_die on an anonymous
- struct yields the DIE of the naming typedef.
- [1]: Read the comment of is_naming_typedef_decl to learn about what
- a naming typedef is. */
- static inline dw_die_ref
- lookup_type_die_strip_naming_typedef (tree type)
- {
- dw_die_ref die = lookup_type_die (type);
- return strip_naming_typedef (type, die);
- }
- /* Equate a DIE to a given type specifier. */
- static inline void
- equate_type_number_to_die (tree type, dw_die_ref type_die)
- {
- TYPE_SYMTAB_DIE (type) = type_die;
- }
- /* Returns a hash value for X (which really is a die_struct). */
- inline hashval_t
- decl_die_hasher::hash (die_node *x)
- {
- return (hashval_t) x->decl_id;
- }
- /* Return nonzero if decl_id of die_struct X is the same as UID of decl *Y. */
- inline bool
- decl_die_hasher::equal (die_node *x, tree y)
- {
- return (x->decl_id == DECL_UID (y));
- }
- /* Return the DIE associated with a given declaration. */
- static inline dw_die_ref
- lookup_decl_die (tree decl)
- {
- return decl_die_table->find_with_hash (decl, DECL_UID (decl));
- }
- /* Returns a hash value for X (which really is a var_loc_list). */
- inline hashval_t
- decl_loc_hasher::hash (var_loc_list *x)
- {
- return (hashval_t) x->decl_id;
- }
- /* Return nonzero if decl_id of var_loc_list X is the same as
- UID of decl *Y. */
- inline bool
- decl_loc_hasher::equal (var_loc_list *x, const_tree y)
- {
- return (x->decl_id == DECL_UID (y));
- }
- /* Return the var_loc list associated with a given declaration. */
- static inline var_loc_list *
- lookup_decl_loc (const_tree decl)
- {
- if (!decl_loc_table)
- return NULL;
- return decl_loc_table->find_with_hash (decl, DECL_UID (decl));
- }
- /* Returns a hash value for X (which really is a cached_dw_loc_list_list). */
- inline hashval_t
- dw_loc_list_hasher::hash (cached_dw_loc_list *x)
- {
- return (hashval_t) x->decl_id;
- }
- /* Return nonzero if decl_id of cached_dw_loc_list X is the same as
- UID of decl *Y. */
- inline bool
- dw_loc_list_hasher::equal (cached_dw_loc_list *x, const_tree y)
- {
- return (x->decl_id == DECL_UID (y));
- }
- /* Equate a DIE to a particular declaration. */
- static void
- equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
- {
- unsigned int decl_id = DECL_UID (decl);
- *decl_die_table->find_slot_with_hash (decl, decl_id, INSERT) = decl_die;
- decl_die->decl_id = decl_id;
- }
- /* Return how many bits covers PIECE EXPR_LIST. */
- static HOST_WIDE_INT
- decl_piece_bitsize (rtx piece)
- {
- int ret = (int) GET_MODE (piece);
- if (ret)
- return ret;
- gcc_assert (GET_CODE (XEXP (piece, 0)) == CONCAT
- && CONST_INT_P (XEXP (XEXP (piece, 0), 0)));
- return INTVAL (XEXP (XEXP (piece, 0), 0));
- }
- /* Return pointer to the location of location note in PIECE EXPR_LIST. */
- static rtx *
- decl_piece_varloc_ptr (rtx piece)
- {
- if ((int) GET_MODE (piece))
- return &XEXP (piece, 0);
- else
- return &XEXP (XEXP (piece, 0), 1);
- }
- /* Create an EXPR_LIST for location note LOC_NOTE covering BITSIZE bits.
- Next is the chain of following piece nodes. */
- static rtx_expr_list *
- decl_piece_node (rtx loc_note, HOST_WIDE_INT bitsize, rtx next)
- {
- if (bitsize > 0 && bitsize <= (int) MAX_MACHINE_MODE)
- return alloc_EXPR_LIST (bitsize, loc_note, next);
- else
- return alloc_EXPR_LIST (0, gen_rtx_CONCAT (VOIDmode,
- GEN_INT (bitsize),
- loc_note), next);
- }
- /* Return rtx that should be stored into loc field for
- LOC_NOTE and BITPOS/BITSIZE. */
- static rtx
- construct_piece_list (rtx loc_note, HOST_WIDE_INT bitpos,
- HOST_WIDE_INT bitsize)
- {
- if (bitsize != -1)
- {
- loc_note = decl_piece_node (loc_note, bitsize, NULL_RTX);
- if (bitpos != 0)
- loc_note = decl_piece_node (NULL_RTX, bitpos, loc_note);
- }
- return loc_note;
- }
- /* This function either modifies location piece list *DEST in
- place (if SRC and INNER is NULL), or copies location piece list
- *SRC to *DEST while modifying it. Location BITPOS is modified
- to contain LOC_NOTE, any pieces overlapping it are removed resp.
- not copied and if needed some padding around it is added.
- When modifying in place, DEST should point to EXPR_LIST where
- earlier pieces cover PIECE_BITPOS bits, when copying SRC points
- to the start of the whole list and INNER points to the EXPR_LIST
- where earlier pieces cover PIECE_BITPOS bits. */
- static void
- adjust_piece_list (rtx *dest, rtx *src, rtx *inner,
- HOST_WIDE_INT bitpos, HOST_WIDE_INT piece_bitpos,
- HOST_WIDE_INT bitsize, rtx loc_note)
- {
- HOST_WIDE_INT diff;
- bool copy = inner != NULL;
- if (copy)
- {
- /* First copy all nodes preceding the current bitpos. */
- while (src != inner)
- {
- *dest = decl_piece_node (*decl_piece_varloc_ptr (*src),
- decl_piece_bitsize (*src), NULL_RTX);
- dest = &XEXP (*dest, 1);
- src = &XEXP (*src, 1);
- }
- }
- /* Add padding if needed. */
- if (bitpos != piece_bitpos)
- {
- *dest = decl_piece_node (NULL_RTX, bitpos - piece_bitpos,
- copy ? NULL_RTX : *dest);
- dest = &XEXP (*dest, 1);
- }
- else if (*dest && decl_piece_bitsize (*dest) == bitsize)
- {
- gcc_assert (!copy);
- /* A piece with correct bitpos and bitsize already exist,
- just update the location for it and return. */
- *decl_piece_varloc_ptr (*dest) = loc_note;
- return;
- }
- /* Add the piece that changed. */
- *dest = decl_piece_node (loc_note, bitsize, copy ? NULL_RTX : *dest);
- dest = &XEXP (*dest, 1);
- /* Skip over pieces that overlap it. */
- diff = bitpos - piece_bitpos + bitsize;
- if (!copy)
- src = dest;
- while (diff > 0 && *src)
- {
- rtx piece = *src;
- diff -= decl_piece_bitsize (piece);
- if (copy)
- src = &XEXP (piece, 1);
- else
- {
- *src = XEXP (piece, 1);
- free_EXPR_LIST_node (piece);
- }
- }
- /* Add padding if needed. */
- if (diff < 0 && *src)
- {
- if (!copy)
- dest = src;
- *dest = decl_piece_node (NULL_RTX, -diff, copy ? NULL_RTX : *dest);
- dest = &XEXP (*dest, 1);
- }
- if (!copy)
- return;
- /* Finally copy all nodes following it. */
- while (*src)
- {
- *dest = decl_piece_node (*decl_piece_varloc_ptr (*src),
- decl_piece_bitsize (*src), NULL_RTX);
- dest = &XEXP (*dest, 1);
- src = &XEXP (*src, 1);
- }
- }
- /* Add a variable location node to the linked list for DECL. */
- static struct var_loc_node *
- add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
- {
- unsigned int decl_id;
- var_loc_list *temp;
- struct var_loc_node *loc = NULL;
- HOST_WIDE_INT bitsize = -1, bitpos = -1;
- if (TREE_CODE (decl) == VAR_DECL
- && DECL_HAS_DEBUG_EXPR_P (decl))
- {
- tree realdecl = DECL_DEBUG_EXPR (decl);
- if (handled_component_p (realdecl)
- || (TREE_CODE (realdecl) == MEM_REF
- && TREE_CODE (TREE_OPERAND (realdecl, 0)) == ADDR_EXPR))
- {
- HOST_WIDE_INT maxsize;
- tree innerdecl;
- innerdecl
- = get_ref_base_and_extent (realdecl, &bitpos, &bitsize, &maxsize);
- if (!DECL_P (innerdecl)
- || DECL_IGNORED_P (innerdecl)
- || TREE_STATIC (innerdecl)
- || bitsize <= 0
- || bitpos + bitsize > 256
- || bitsize != maxsize)
- return NULL;
- decl = innerdecl;
- }
- }
- decl_id = DECL_UID (decl);
- var_loc_list **slot
- = decl_loc_table->find_slot_with_hash (decl, decl_id, INSERT);
- if (*slot == NULL)
- {
- temp = ggc_cleared_alloc<var_loc_list> ();
- temp->decl_id = decl_id;
- *slot = temp;
- }
- else
- temp = *slot;
- /* For PARM_DECLs try to keep around the original incoming value,
- even if that means we'll emit a zero-range .debug_loc entry. */
- if (temp->last
- && temp->first == temp->last
- && TREE_CODE (decl) == PARM_DECL
- && NOTE_P (temp->first->loc)
- && NOTE_VAR_LOCATION_DECL (temp->first->loc) == decl
- && DECL_INCOMING_RTL (decl)
- && NOTE_VAR_LOCATION_LOC (temp->first->loc)
- && GET_CODE (NOTE_VAR_LOCATION_LOC (temp->first->loc))
- == GET_CODE (DECL_INCOMING_RTL (decl))
- && prev_real_insn (temp->first->loc) == NULL_RTX
- && (bitsize != -1
- || !rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->first->loc),
- NOTE_VAR_LOCATION_LOC (loc_note))
- || (NOTE_VAR_LOCATION_STATUS (temp->first->loc)
- != NOTE_VAR_LOCATION_STATUS (loc_note))))
- {
- loc = ggc_cleared_alloc<var_loc_node> ();
- temp->first->next = loc;
- temp->last = loc;
- loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
- }
- else if (temp->last)
- {
- struct var_loc_node *last = temp->last, *unused = NULL;
- rtx *piece_loc = NULL, last_loc_note;
- HOST_WIDE_INT piece_bitpos = 0;
- if (last->next)
- {
- last = last->next;
- gcc_assert (last->next == NULL);
- }
- if (bitsize != -1 && GET_CODE (last->loc) == EXPR_LIST)
- {
- piece_loc = &last->loc;
- do
- {
- HOST_WIDE_INT cur_bitsize = decl_piece_bitsize (*piece_loc);
- if (piece_bitpos + cur_bitsize > bitpos)
- break;
- piece_bitpos += cur_bitsize;
- piece_loc = &XEXP (*piece_loc, 1);
- }
- while (*piece_loc);
- }
- /* TEMP->LAST here is either pointer to the last but one or
- last element in the chained list, LAST is pointer to the
- last element. */
- if (label && strcmp (last->label, label) == 0)
- {
- /* For SRA optimized variables if there weren't any real
- insns since last note, just modify the last node. */
- if (piece_loc != NULL)
- {
- adjust_piece_list (piece_loc, NULL, NULL,
- bitpos, piece_bitpos, bitsize, loc_note);
- return NULL;
- }
- /* If the last note doesn't cover any instructions, remove it. */
- if (temp->last != last)
- {
- temp->last->next = NULL;
- unused = last;
- last = temp->last;
- gcc_assert (strcmp (last->label, label) != 0);
- }
- else
- {
- gcc_assert (temp->first == temp->last
- || (temp->first->next == temp->last
- && TREE_CODE (decl) == PARM_DECL));
- memset (temp->last, '\0', sizeof (*temp->last));
- temp->last->loc = construct_piece_list (loc_note, bitpos, bitsize);
- return temp->last;
- }
- }
- if (bitsize == -1 && NOTE_P (last->loc))
- last_loc_note = last->loc;
- else if (piece_loc != NULL
- && *piece_loc != NULL_RTX
- && piece_bitpos == bitpos
- && decl_piece_bitsize (*piece_loc) == bitsize)
- last_loc_note = *decl_piece_varloc_ptr (*piece_loc);
- else
- last_loc_note = NULL_RTX;
- /* If the current location is the same as the end of the list,
- and either both or neither of the locations is uninitialized,
- we have nothing to do. */
- if (last_loc_note == NULL_RTX
- || (!rtx_equal_p (NOTE_VAR_LOCATION_LOC (last_loc_note),
- NOTE_VAR_LOCATION_LOC (loc_note)))
- || ((NOTE_VAR_LOCATION_STATUS (last_loc_note)
- != NOTE_VAR_LOCATION_STATUS (loc_note))
- && ((NOTE_VAR_LOCATION_STATUS (last_loc_note)
- == VAR_INIT_STATUS_UNINITIALIZED)
- || (NOTE_VAR_LOCATION_STATUS (loc_note)
- == VAR_INIT_STATUS_UNINITIALIZED))))
- {
- /* Add LOC to the end of list and update LAST. If the last
- element of the list has been removed above, reuse its
- memory for the new node, otherwise allocate a new one. */
- if (unused)
- {
- loc = unused;
- memset (loc, '\0', sizeof (*loc));
- }
- else
- loc = ggc_cleared_alloc<var_loc_node> ();
- if (bitsize == -1 || piece_loc == NULL)
- loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
- else
- adjust_piece_list (&loc->loc, &last->loc, piece_loc,
- bitpos, piece_bitpos, bitsize, loc_note);
- last->next = loc;
- /* Ensure TEMP->LAST will point either to the new last but one
- element of the chain, or to the last element in it. */
- if (last != temp->last)
- temp->last = last;
- }
- else if (unused)
- ggc_free (unused);
- }
- else
- {
- loc = ggc_cleared_alloc<var_loc_node> ();
- temp->first = loc;
- temp->last = loc;
- loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
- }
- return loc;
- }
- /* Keep track of the number of spaces used to indent the
- output of the debugging routines that print the structure of
- the DIE internal representation. */
- static int print_indent;
- /* Indent the line the number of spaces given by print_indent. */
- static inline void
- print_spaces (FILE *outfile)
- {
- fprintf (outfile, "%*s", print_indent, "");
- }
- /* Print a type signature in hex. */
- static inline void
- print_signature (FILE *outfile, char *sig)
- {
- int i;
- for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
- fprintf (outfile, "%02x", sig[i] & 0xff);
- }
- static void print_loc_descr (dw_loc_descr_ref, FILE *);
- /* Print the value associated to the VAL DWARF value node to OUTFILE. If
- RECURSE, output location descriptor operations. */
- static void
- print_dw_val (dw_val_node *val, bool recurse, FILE *outfile)
- {
- switch (val->val_class)
- {
- case dw_val_class_addr:
- fprintf (outfile, "address");
- break;
- case dw_val_class_offset:
- fprintf (outfile, "offset");
- break;
- case dw_val_class_loc:
- fprintf (outfile, "location descriptor");
- if (val->v.val_loc == NULL)
- fprintf (outfile, " -> <null>\n");
- else if (recurse)
- {
- fprintf (outfile, ":\n");
- print_indent += 4;
- print_loc_descr (val->v.val_loc, outfile);
- print_indent -= 4;
- }
- else
- fprintf (outfile, " (%p)\n", (void *) val->v.val_loc);
- break;
- case dw_val_class_loc_list:
- fprintf (outfile, "location list -> label:%s",
- val->v.val_loc_list->ll_symbol);
- break;
- case dw_val_class_range_list:
- fprintf (outfile, "range list");
- break;
- case dw_val_class_const:
- fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, val->v.val_int);
- break;
- case dw_val_class_unsigned_const:
- fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, val->v.val_unsigned);
- break;
- case dw_val_class_const_double:
- fprintf (outfile, "constant ("HOST_WIDE_INT_PRINT_DEC","\
- HOST_WIDE_INT_PRINT_UNSIGNED")",
- val->v.val_double.high,
- val->v.val_double.low);
- break;
- case dw_val_class_wide_int:
- {
- int i = val->v.val_wide->get_len ();
- fprintf (outfile, "constant (");
- gcc_assert (i > 0);
- if (val->v.val_wide->elt (i - 1) == 0)
- fprintf (outfile, "0x");
- fprintf (outfile, HOST_WIDE_INT_PRINT_HEX,
- val->v.val_wide->elt (--i));
- while (--i >= 0)
- fprintf (outfile, HOST_WIDE_INT_PRINT_PADDED_HEX,
- val->v.val_wide->elt (i));
- fprintf (outfile, ")");
- break;
- }
- case dw_val_class_vec:
- fprintf (outfile, "floating-point or vector constant");
- break;
- case dw_val_class_flag:
- fprintf (outfile, "%u", val->v.val_flag);
- break;
- case dw_val_class_die_ref:
- if (val->v.val_die_ref.die != NULL)
- {
- dw_die_ref die = val->v.val_die_ref.die;
- if (die->comdat_type_p)
- {
- fprintf (outfile, "die -> signature: ");
- print_signature (outfile,
- die->die_id.die_type_node->signature);
- }
- else if (die->die_id.die_symbol)
- fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
- else
- fprintf (outfile, "die -> %ld", die->die_offset);
- fprintf (outfile, " (%p)", (void *) die);
- }
- else
- fprintf (outfile, "die -> <null>");
- break;
- case dw_val_class_vms_delta:
- fprintf (outfile, "delta: @slotcount(%s-%s)",
- val->v.val_vms_delta.lbl2, val->v.val_vms_delta.lbl1);
- break;
- case dw_val_class_lbl_id:
- case dw_val_class_lineptr:
- case dw_val_class_macptr:
- case dw_val_class_high_pc:
- fprintf (outfile, "label: %s", val->v.val_lbl_id);
- break;
- case dw_val_class_str:
- if (val->v.val_str->str != NULL)
- fprintf (outfile, "\"%s\"", val->v.val_str->str);
- else
- fprintf (outfile, "<null>");
- break;
- case dw_val_class_file:
- fprintf (outfile, "\"%s\" (%d)", val->v.val_file->filename,
- val->v.val_file->emitted_number);
- break;
- case dw_val_class_data8:
- {
- int i;
- for (i = 0; i < 8; i++)
- fprintf (outfile, "%02x", val->v.val_data8[i]);
- break;
- }
- default:
- break;
- }
- }
- /* Likewise, for a DIE attribute. */
- static void
- print_attribute (dw_attr_ref a, bool recurse, FILE *outfile)
- {
- print_dw_val (&a->dw_attr_val, recurse, outfile);
- }
- /* Print the list of operands in the LOC location description to OUTFILE. This
- routine is a debugging aid only. */
- static void
- print_loc_descr (dw_loc_descr_ref loc, FILE *outfile)
- {
- dw_loc_descr_ref l = loc;
- if (loc == NULL)
- {
- print_spaces (outfile);
- fprintf (outfile, "<null>\n");
- return;
- }
- for (l = loc; l != NULL; l = l->dw_loc_next)
- {
- print_spaces (outfile);
- fprintf (outfile, "(%p) %s",
- (void *) l,
- dwarf_stack_op_name (l->dw_loc_opc));
- if (l->dw_loc_oprnd1.val_class != dw_val_class_none)
- {
- fprintf (outfile, " ");
- print_dw_val (&l->dw_loc_oprnd1, false, outfile);
- }
- if (l->dw_loc_oprnd2.val_class != dw_val_class_none)
- {
- fprintf (outfile, ", ");
- print_dw_val (&l->dw_loc_oprnd2, false, outfile);
- }
- fprintf (outfile, "\n");
- }
- }
- /* Print the information associated with a given DIE, and its children.
- This routine is a debugging aid only. */
- static void
- print_die (dw_die_ref die, FILE *outfile)
- {
- dw_attr_ref a;
- dw_die_ref c;
- unsigned ix;
- print_spaces (outfile);
- fprintf (outfile, "DIE %4ld: %s (%p)\n",
- die->die_offset, dwarf_tag_name (die->die_tag),
- (void*) die);
- print_spaces (outfile);
- fprintf (outfile, " abbrev id: %lu", die->die_abbrev);
- fprintf (outfile, " offset: %ld", die->die_offset);
- fprintf (outfile, " mark: %d\n", die->die_mark);
- if (die->comdat_type_p)
- {
- print_spaces (outfile);
- fprintf (outfile, " signature: ");
- print_signature (outfile, die->die_id.die_type_node->signature);
- fprintf (outfile, "\n");
- }
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- {
- print_spaces (outfile);
- fprintf (outfile, " %s: ", dwarf_attr_name (a->dw_attr));
- print_attribute (a, true, outfile);
- fprintf (outfile, "\n");
- }
- if (die->die_child != NULL)
- {
- print_indent += 4;
- FOR_EACH_CHILD (die, c, print_die (c, outfile));
- print_indent -= 4;
- }
- if (print_indent == 0)
- fprintf (outfile, "\n");
- }
- /* Print the list of operations in the LOC location description. */
- DEBUG_FUNCTION void
- debug_dwarf_loc_descr (dw_loc_descr_ref loc)
- {
- print_loc_descr (loc, stderr);
- }
- /* Print the information collected for a given DIE. */
- DEBUG_FUNCTION void
- debug_dwarf_die (dw_die_ref die)
- {
- print_die (die, stderr);
- }
- DEBUG_FUNCTION void
- debug (die_struct &ref)
- {
- print_die (&ref, stderr);
- }
- DEBUG_FUNCTION void
- debug (die_struct *ptr)
- {
- if (ptr)
- debug (*ptr);
- else
- fprintf (stderr, "<nil>\n");
- }
- /* Print all DWARF information collected for the compilation unit.
- This routine is a debugging aid only. */
- DEBUG_FUNCTION void
- debug_dwarf (void)
- {
- print_indent = 0;
- print_die (comp_unit_die (), stderr);
- }
- /* Start a new compilation unit DIE for an include file. OLD_UNIT is the CU
- for the enclosing include file, if any. BINCL_DIE is the DW_TAG_GNU_BINCL
- DIE that marks the start of the DIEs for this include file. */
- static dw_die_ref
- push_new_compile_unit (dw_die_ref old_unit, dw_die_ref bincl_die)
- {
- const char *filename = get_AT_string (bincl_die, DW_AT_name);
- dw_die_ref new_unit = gen_compile_unit_die (filename);
- new_unit->die_sib = old_unit;
- return new_unit;
- }
- /* Close an include-file CU and reopen the enclosing one. */
- static dw_die_ref
- pop_compile_unit (dw_die_ref old_unit)
- {
- dw_die_ref new_unit = old_unit->die_sib;
- old_unit->die_sib = NULL;
- return new_unit;
- }
- #define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx)
- #define CHECKSUM_BLOCK(FOO, SIZE) md5_process_bytes ((FOO), (SIZE), ctx)
- #define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO), ctx)
- /* Calculate the checksum of a location expression. */
- static inline void
- loc_checksum (dw_loc_descr_ref loc, struct md5_ctx *ctx)
- {
- int tem;
- inchash::hash hstate;
- hashval_t hash;
- tem = (loc->dtprel << 8) | ((unsigned int) loc->dw_loc_opc);
- CHECKSUM (tem);
- hash_loc_operands (loc, hstate);
- hash = hstate.end();
- CHECKSUM (hash);
- }
- /* Calculate the checksum of an attribute. */
- static void
- attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
- {
- dw_loc_descr_ref loc;
- rtx r;
- CHECKSUM (at->dw_attr);
- /* We don't care that this was compiled with a different compiler
- snapshot; if the output is the same, that's what matters. */
- if (at->dw_attr == DW_AT_producer)
- return;
- switch (AT_class (at))
- {
- case dw_val_class_const:
- CHECKSUM (at->dw_attr_val.v.val_int);
- break;
- case dw_val_class_unsigned_const:
- CHECKSUM (at->dw_attr_val.v.val_unsigned);
- break;
- case dw_val_class_const_double:
- CHECKSUM (at->dw_attr_val.v.val_double);
- break;
- case dw_val_class_wide_int:
- CHECKSUM_BLOCK (at->dw_attr_val.v.val_wide->get_val (),
- get_full_len (*at->dw_attr_val.v.val_wide)
- * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
- break;
- case dw_val_class_vec:
- CHECKSUM_BLOCK (at->dw_attr_val.v.val_vec.array,
- (at->dw_attr_val.v.val_vec.length
- * at->dw_attr_val.v.val_vec.elt_size));
- break;
- case dw_val_class_flag:
- CHECKSUM (at->dw_attr_val.v.val_flag);
- break;
- case dw_val_class_str:
- CHECKSUM_STRING (AT_string (at));
- break;
- case dw_val_class_addr:
- r = AT_addr (at);
- gcc_assert (GET_CODE (r) == SYMBOL_REF);
- CHECKSUM_STRING (XSTR (r, 0));
- break;
- case dw_val_class_offset:
- CHECKSUM (at->dw_attr_val.v.val_offset);
- break;
- case dw_val_class_loc:
- for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
- loc_checksum (loc, ctx);
- break;
- case dw_val_class_die_ref:
- die_checksum (AT_ref (at), ctx, mark);
- break;
- case dw_val_class_fde_ref:
- case dw_val_class_vms_delta:
- case dw_val_class_lbl_id:
- case dw_val_class_lineptr:
- case dw_val_class_macptr:
- case dw_val_class_high_pc:
- break;
- case dw_val_class_file:
- CHECKSUM_STRING (AT_file (at)->filename);
- break;
- case dw_val_class_data8:
- CHECKSUM (at->dw_attr_val.v.val_data8);
- break;
- default:
- break;
- }
- }
- /* Calculate the checksum of a DIE. */
- static void
- die_checksum (dw_die_ref die, struct md5_ctx *ctx, int *mark)
- {
- dw_die_ref c;
- dw_attr_ref a;
- unsigned ix;
- /* To avoid infinite recursion. */
- if (die->die_mark)
- {
- CHECKSUM (die->die_mark);
- return;
- }
- die->die_mark = ++(*mark);
- CHECKSUM (die->die_tag);
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- attr_checksum (a, ctx, mark);
- FOR_EACH_CHILD (die, c, die_checksum (c, ctx, mark));
- }
- #undef CHECKSUM
- #undef CHECKSUM_BLOCK
- #undef CHECKSUM_STRING
- /* For DWARF-4 types, include the trailing NULL when checksumming strings. */
- #define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx)
- #define CHECKSUM_BLOCK(FOO, SIZE) md5_process_bytes ((FOO), (SIZE), ctx)
- #define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO) + 1, ctx)
- #define CHECKSUM_SLEB128(FOO) checksum_sleb128 ((FOO), ctx)
- #define CHECKSUM_ULEB128(FOO) checksum_uleb128 ((FOO), ctx)
- #define CHECKSUM_ATTR(FOO) \
- if (FOO) attr_checksum_ordered (die->die_tag, (FOO), ctx, mark)
- /* Calculate the checksum of a number in signed LEB128 format. */
- static void
- checksum_sleb128 (HOST_WIDE_INT value, struct md5_ctx *ctx)
- {
- unsigned char byte;
- bool more;
- while (1)
- {
- byte = (value & 0x7f);
- value >>= 7;
- more = !((value == 0 && (byte & 0x40) == 0)
- || (value == -1 && (byte & 0x40) != 0));
- if (more)
- byte |= 0x80;
- CHECKSUM (byte);
- if (!more)
- break;
- }
- }
- /* Calculate the checksum of a number in unsigned LEB128 format. */
- static void
- checksum_uleb128 (unsigned HOST_WIDE_INT value, struct md5_ctx *ctx)
- {
- while (1)
- {
- unsigned char byte = (value & 0x7f);
- value >>= 7;
- if (value != 0)
- /* More bytes to follow. */
- byte |= 0x80;
- CHECKSUM (byte);
- if (value == 0)
- break;
- }
- }
- /* Checksum the context of the DIE. This adds the names of any
- surrounding namespaces or structures to the checksum. */
- static void
- checksum_die_context (dw_die_ref die, struct md5_ctx *ctx)
- {
- const char *name;
- dw_die_ref spec;
- int tag = die->die_tag;
- if (tag != DW_TAG_namespace
- && tag != DW_TAG_structure_type
- && tag != DW_TAG_class_type)
- return;
- name = get_AT_string (die, DW_AT_name);
- spec = get_AT_ref (die, DW_AT_specification);
- if (spec != NULL)
- die = spec;
- if (die->die_parent != NULL)
- checksum_die_context (die->die_parent, ctx);
- CHECKSUM_ULEB128 ('C');
- CHECKSUM_ULEB128 (tag);
- if (name != NULL)
- CHECKSUM_STRING (name);
- }
- /* Calculate the checksum of a location expression. */
- static inline void
- loc_checksum_ordered (dw_loc_descr_ref loc, struct md5_ctx *ctx)
- {
- /* Special case for lone DW_OP_plus_uconst: checksum as if the location
- were emitted as a DW_FORM_sdata instead of a location expression. */
- if (loc->dw_loc_opc == DW_OP_plus_uconst && loc->dw_loc_next == NULL)
- {
- CHECKSUM_ULEB128 (DW_FORM_sdata);
- CHECKSUM_SLEB128 ((HOST_WIDE_INT) loc->dw_loc_oprnd1.v.val_unsigned);
- return;
- }
- /* Otherwise, just checksum the raw location expression. */
- while (loc != NULL)
- {
- inchash::hash hstate;
- hashval_t hash;
- CHECKSUM_ULEB128 (loc->dtprel);
- CHECKSUM_ULEB128 (loc->dw_loc_opc);
- hash_loc_operands (loc, hstate);
- hash = hstate.end ();
- CHECKSUM (hash);
- loc = loc->dw_loc_next;
- }
- }
- /* Calculate the checksum of an attribute. */
- static void
- attr_checksum_ordered (enum dwarf_tag tag, dw_attr_ref at,
- struct md5_ctx *ctx, int *mark)
- {
- dw_loc_descr_ref loc;
- rtx r;
- if (AT_class (at) == dw_val_class_die_ref)
- {
- dw_die_ref target_die = AT_ref (at);
- /* For pointer and reference types, we checksum only the (qualified)
- name of the target type (if there is a name). For friend entries,
- we checksum only the (qualified) name of the target type or function.
- This allows the checksum to remain the same whether the target type
- is complete or not. */
- if ((at->dw_attr == DW_AT_type
- && (tag == DW_TAG_pointer_type
- || tag == DW_TAG_reference_type
- || tag == DW_TAG_rvalue_reference_type
- || tag == DW_TAG_ptr_to_member_type))
- || (at->dw_attr == DW_AT_friend
- && tag == DW_TAG_friend))
- {
- dw_attr_ref name_attr = get_AT (target_die, DW_AT_name);
- if (name_attr != NULL)
- {
- dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification);
- if (decl == NULL)
- decl = target_die;
- CHECKSUM_ULEB128 ('N');
- CHECKSUM_ULEB128 (at->dw_attr);
- if (decl->die_parent != NULL)
- checksum_die_context (decl->die_parent, ctx);
- CHECKSUM_ULEB128 ('E');
- CHECKSUM_STRING (AT_string (name_attr));
- return;
- }
- }
- /* For all other references to another DIE, we check to see if the
- target DIE has already been visited. If it has, we emit a
- backward reference; if not, we descend recursively. */
- if (target_die->die_mark > 0)
- {
- CHECKSUM_ULEB128 ('R');
- CHECKSUM_ULEB128 (at->dw_attr);
- CHECKSUM_ULEB128 (target_die->die_mark);
- }
- else
- {
- dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification);
- if (decl == NULL)
- decl = target_die;
- target_die->die_mark = ++(*mark);
- CHECKSUM_ULEB128 ('T');
- CHECKSUM_ULEB128 (at->dw_attr);
- if (decl->die_parent != NULL)
- checksum_die_context (decl->die_parent, ctx);
- die_checksum_ordered (target_die, ctx, mark);
- }
- return;
- }
- CHECKSUM_ULEB128 ('A');
- CHECKSUM_ULEB128 (at->dw_attr);
- switch (AT_class (at))
- {
- case dw_val_class_const:
- CHECKSUM_ULEB128 (DW_FORM_sdata);
- CHECKSUM_SLEB128 (at->dw_attr_val.v.val_int);
- break;
- case dw_val_class_unsigned_const:
- CHECKSUM_ULEB128 (DW_FORM_sdata);
- CHECKSUM_SLEB128 ((int) at->dw_attr_val.v.val_unsigned);
- break;
- case dw_val_class_const_double:
- CHECKSUM_ULEB128 (DW_FORM_block);
- CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_double));
- CHECKSUM (at->dw_attr_val.v.val_double);
- break;
- case dw_val_class_wide_int:
- CHECKSUM_ULEB128 (DW_FORM_block);
- CHECKSUM_ULEB128 (get_full_len (*at->dw_attr_val.v.val_wide)
- * HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT);
- CHECKSUM_BLOCK (at->dw_attr_val.v.val_wide->get_val (),
- get_full_len (*at->dw_attr_val.v.val_wide)
- * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
- break;
- case dw_val_class_vec:
- CHECKSUM_ULEB128 (DW_FORM_block);
- CHECKSUM_ULEB128 (at->dw_attr_val.v.val_vec.length
- * at->dw_attr_val.v.val_vec.elt_size);
- CHECKSUM_BLOCK (at->dw_attr_val.v.val_vec.array,
- (at->dw_attr_val.v.val_vec.length
- * at->dw_attr_val.v.val_vec.elt_size));
- break;
- case dw_val_class_flag:
- CHECKSUM_ULEB128 (DW_FORM_flag);
- CHECKSUM_ULEB128 (at->dw_attr_val.v.val_flag ? 1 : 0);
- break;
- case dw_val_class_str:
- CHECKSUM_ULEB128 (DW_FORM_string);
- CHECKSUM_STRING (AT_string (at));
- break;
- case dw_val_class_addr:
- r = AT_addr (at);
- gcc_assert (GET_CODE (r) == SYMBOL_REF);
- CHECKSUM_ULEB128 (DW_FORM_string);
- CHECKSUM_STRING (XSTR (r, 0));
- break;
- case dw_val_class_offset:
- CHECKSUM_ULEB128 (DW_FORM_sdata);
- CHECKSUM_ULEB128 (at->dw_attr_val.v.val_offset);
- break;
- case dw_val_class_loc:
- for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
- loc_checksum_ordered (loc, ctx);
- break;
- case dw_val_class_fde_ref:
- case dw_val_class_lbl_id:
- case dw_val_class_lineptr:
- case dw_val_class_macptr:
- case dw_val_class_high_pc:
- break;
- case dw_val_class_file:
- CHECKSUM_ULEB128 (DW_FORM_string);
- CHECKSUM_STRING (AT_file (at)->filename);
- break;
- case dw_val_class_data8:
- CHECKSUM (at->dw_attr_val.v.val_data8);
- break;
- default:
- break;
- }
- }
- struct checksum_attributes
- {
- dw_attr_ref at_name;
- dw_attr_ref at_type;
- dw_attr_ref at_friend;
- dw_attr_ref at_accessibility;
- dw_attr_ref at_address_class;
- dw_attr_ref at_allocated;
- dw_attr_ref at_artificial;
- dw_attr_ref at_associated;
- dw_attr_ref at_binary_scale;
- dw_attr_ref at_bit_offset;
- dw_attr_ref at_bit_size;
- dw_attr_ref at_bit_stride;
- dw_attr_ref at_byte_size;
- dw_attr_ref at_byte_stride;
- dw_attr_ref at_const_value;
- dw_attr_ref at_containing_type;
- dw_attr_ref at_count;
- dw_attr_ref at_data_location;
- dw_attr_ref at_data_member_location;
- dw_attr_ref at_decimal_scale;
- dw_attr_ref at_decimal_sign;
- dw_attr_ref at_default_value;
- dw_attr_ref at_digit_count;
- dw_attr_ref at_discr;
- dw_attr_ref at_discr_list;
- dw_attr_ref at_discr_value;
- dw_attr_ref at_encoding;
- dw_attr_ref at_endianity;
- dw_attr_ref at_explicit;
- dw_attr_ref at_is_optional;
- dw_attr_ref at_location;
- dw_attr_ref at_lower_bound;
- dw_attr_ref at_mutable;
- dw_attr_ref at_ordering;
- dw_attr_ref at_picture_string;
- dw_attr_ref at_prototyped;
- dw_attr_ref at_small;
- dw_attr_ref at_segment;
- dw_attr_ref at_string_length;
- dw_attr_ref at_threads_scaled;
- dw_attr_ref at_upper_bound;
- dw_attr_ref at_use_location;
- dw_attr_ref at_use_UTF8;
- dw_attr_ref at_variable_parameter;
- dw_attr_ref at_virtuality;
- dw_attr_ref at_visibility;
- dw_attr_ref at_vtable_elem_location;
- };
- /* Collect the attributes that we will want to use for the checksum. */
- static void
- collect_checksum_attributes (struct checksum_attributes *attrs, dw_die_ref die)
- {
- dw_attr_ref a;
- unsigned ix;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- {
- switch (a->dw_attr)
- {
- case DW_AT_name:
- attrs->at_name = a;
- break;
- case DW_AT_type:
- attrs->at_type = a;
- break;
- case DW_AT_friend:
- attrs->at_friend = a;
- break;
- case DW_AT_accessibility:
- attrs->at_accessibility = a;
- break;
- case DW_AT_address_class:
- attrs->at_address_class = a;
- break;
- case DW_AT_allocated:
- attrs->at_allocated = a;
- break;
- case DW_AT_artificial:
- attrs->at_artificial = a;
- break;
- case DW_AT_associated:
- attrs->at_associated = a;
- break;
- case DW_AT_binary_scale:
- attrs->at_binary_scale = a;
- break;
- case DW_AT_bit_offset:
- attrs->at_bit_offset = a;
- break;
- case DW_AT_bit_size:
- attrs->at_bit_size = a;
- break;
- case DW_AT_bit_stride:
- attrs->at_bit_stride = a;
- break;
- case DW_AT_byte_size:
- attrs->at_byte_size = a;
- break;
- case DW_AT_byte_stride:
- attrs->at_byte_stride = a;
- break;
- case DW_AT_const_value:
- attrs->at_const_value = a;
- break;
- case DW_AT_containing_type:
- attrs->at_containing_type = a;
- break;
- case DW_AT_count:
- attrs->at_count = a;
- break;
- case DW_AT_data_location:
- attrs->at_data_location = a;
- break;
- case DW_AT_data_member_location:
- attrs->at_data_member_location = a;
- break;
- case DW_AT_decimal_scale:
- attrs->at_decimal_scale = a;
- break;
- case DW_AT_decimal_sign:
- attrs->at_decimal_sign = a;
- break;
- case DW_AT_default_value:
- attrs->at_default_value = a;
- break;
- case DW_AT_digit_count:
- attrs->at_digit_count = a;
- break;
- case DW_AT_discr:
- attrs->at_discr = a;
- break;
- case DW_AT_discr_list:
- attrs->at_discr_list = a;
- break;
- case DW_AT_discr_value:
- attrs->at_discr_value = a;
- break;
- case DW_AT_encoding:
- attrs->at_encoding = a;
- break;
- case DW_AT_endianity:
- attrs->at_endianity = a;
- break;
- case DW_AT_explicit:
- attrs->at_explicit = a;
- break;
- case DW_AT_is_optional:
- attrs->at_is_optional = a;
- break;
- case DW_AT_location:
- attrs->at_location = a;
- break;
- case DW_AT_lower_bound:
- attrs->at_lower_bound = a;
- break;
- case DW_AT_mutable:
- attrs->at_mutable = a;
- break;
- case DW_AT_ordering:
- attrs->at_ordering = a;
- break;
- case DW_AT_picture_string:
- attrs->at_picture_string = a;
- break;
- case DW_AT_prototyped:
- attrs->at_prototyped = a;
- break;
- case DW_AT_small:
- attrs->at_small = a;
- break;
- case DW_AT_segment:
- attrs->at_segment = a;
- break;
- case DW_AT_string_length:
- attrs->at_string_length = a;
- break;
- case DW_AT_threads_scaled:
- attrs->at_threads_scaled = a;
- break;
- case DW_AT_upper_bound:
- attrs->at_upper_bound = a;
- break;
- case DW_AT_use_location:
- attrs->at_use_location = a;
- break;
- case DW_AT_use_UTF8:
- attrs->at_use_UTF8 = a;
- break;
- case DW_AT_variable_parameter:
- attrs->at_variable_parameter = a;
- break;
- case DW_AT_virtuality:
- attrs->at_virtuality = a;
- break;
- case DW_AT_visibility:
- attrs->at_visibility = a;
- break;
- case DW_AT_vtable_elem_location:
- attrs->at_vtable_elem_location = a;
- break;
- default:
- break;
- }
- }
- }
- /* Calculate the checksum of a DIE, using an ordered subset of attributes. */
- static void
- die_checksum_ordered (dw_die_ref die, struct md5_ctx *ctx, int *mark)
- {
- dw_die_ref c;
- dw_die_ref decl;
- struct checksum_attributes attrs;
- CHECKSUM_ULEB128 ('D');
- CHECKSUM_ULEB128 (die->die_tag);
- memset (&attrs, 0, sizeof (attrs));
- decl = get_AT_ref (die, DW_AT_specification);
- if (decl != NULL)
- collect_checksum_attributes (&attrs, decl);
- collect_checksum_attributes (&attrs, die);
- CHECKSUM_ATTR (attrs.at_name);
- CHECKSUM_ATTR (attrs.at_accessibility);
- CHECKSUM_ATTR (attrs.at_address_class);
- CHECKSUM_ATTR (attrs.at_allocated);
- CHECKSUM_ATTR (attrs.at_artificial);
- CHECKSUM_ATTR (attrs.at_associated);
- CHECKSUM_ATTR (attrs.at_binary_scale);
- CHECKSUM_ATTR (attrs.at_bit_offset);
- CHECKSUM_ATTR (attrs.at_bit_size);
- CHECKSUM_ATTR (attrs.at_bit_stride);
- CHECKSUM_ATTR (attrs.at_byte_size);
- CHECKSUM_ATTR (attrs.at_byte_stride);
- CHECKSUM_ATTR (attrs.at_const_value);
- CHECKSUM_ATTR (attrs.at_containing_type);
- CHECKSUM_ATTR (attrs.at_count);
- CHECKSUM_ATTR (attrs.at_data_location);
- CHECKSUM_ATTR (attrs.at_data_member_location);
- CHECKSUM_ATTR (attrs.at_decimal_scale);
- CHECKSUM_ATTR (attrs.at_decimal_sign);
- CHECKSUM_ATTR (attrs.at_default_value);
- CHECKSUM_ATTR (attrs.at_digit_count);
- CHECKSUM_ATTR (attrs.at_discr);
- CHECKSUM_ATTR (attrs.at_discr_list);
- CHECKSUM_ATTR (attrs.at_discr_value);
- CHECKSUM_ATTR (attrs.at_encoding);
- CHECKSUM_ATTR (attrs.at_endianity);
- CHECKSUM_ATTR (attrs.at_explicit);
- CHECKSUM_ATTR (attrs.at_is_optional);
- CHECKSUM_ATTR (attrs.at_location);
- CHECKSUM_ATTR (attrs.at_lower_bound);
- CHECKSUM_ATTR (attrs.at_mutable);
- CHECKSUM_ATTR (attrs.at_ordering);
- CHECKSUM_ATTR (attrs.at_picture_string);
- CHECKSUM_ATTR (attrs.at_prototyped);
- CHECKSUM_ATTR (attrs.at_small);
- CHECKSUM_ATTR (attrs.at_segment);
- CHECKSUM_ATTR (attrs.at_string_length);
- CHECKSUM_ATTR (attrs.at_threads_scaled);
- CHECKSUM_ATTR (attrs.at_upper_bound);
- CHECKSUM_ATTR (attrs.at_use_location);
- CHECKSUM_ATTR (attrs.at_use_UTF8);
- CHECKSUM_ATTR (attrs.at_variable_parameter);
- CHECKSUM_ATTR (attrs.at_virtuality);
- CHECKSUM_ATTR (attrs.at_visibility);
- CHECKSUM_ATTR (attrs.at_vtable_elem_location);
- CHECKSUM_ATTR (attrs.at_type);
- CHECKSUM_ATTR (attrs.at_friend);
- /* Checksum the child DIEs. */
- c = die->die_child;
- if (c) do {
- dw_attr_ref name_attr;
- c = c->die_sib;
- name_attr = get_AT (c, DW_AT_name);
- if (is_template_instantiation (c))
- {
- /* Ignore instantiations of member type and function templates. */
- }
- else if (name_attr != NULL
- && (is_type_die (c) || c->die_tag == DW_TAG_subprogram))
- {
- /* Use a shallow checksum for named nested types and member
- functions. */
- CHECKSUM_ULEB128 ('S');
- CHECKSUM_ULEB128 (c->die_tag);
- CHECKSUM_STRING (AT_string (name_attr));
- }
- else
- {
- /* Use a deep checksum for other children. */
- /* Mark this DIE so it gets processed when unmarking. */
- if (c->die_mark == 0)
- c->die_mark = -1;
- die_checksum_ordered (c, ctx, mark);
- }
- } while (c != die->die_child);
- CHECKSUM_ULEB128 (0);
- }
- /* Add a type name and tag to a hash. */
- static void
- die_odr_checksum (int tag, const char *name, md5_ctx *ctx)
- {
- CHECKSUM_ULEB128 (tag);
- CHECKSUM_STRING (name);
- }
- #undef CHECKSUM
- #undef CHECKSUM_STRING
- #undef CHECKSUM_ATTR
- #undef CHECKSUM_LEB128
- #undef CHECKSUM_ULEB128
- /* Generate the type signature for DIE. This is computed by generating an
- MD5 checksum over the DIE's tag, its relevant attributes, and its
- children. Attributes that are references to other DIEs are processed
- by recursion, using the MARK field to prevent infinite recursion.
- If the DIE is nested inside a namespace or another type, we also
- need to include that context in the signature. The lower 64 bits
- of the resulting MD5 checksum comprise the signature. */
- static void
- generate_type_signature (dw_die_ref die, comdat_type_node *type_node)
- {
- int mark;
- const char *name;
- unsigned char checksum[16];
- struct md5_ctx ctx;
- dw_die_ref decl;
- dw_die_ref parent;
- name = get_AT_string (die, DW_AT_name);
- decl = get_AT_ref (die, DW_AT_specification);
- parent = get_die_parent (die);
- /* First, compute a signature for just the type name (and its surrounding
- context, if any. This is stored in the type unit DIE for link-time
- ODR (one-definition rule) checking. */
- if (is_cxx () && name != NULL)
- {
- md5_init_ctx (&ctx);
- /* Checksum the names of surrounding namespaces and structures. */
- if (parent != NULL)
- checksum_die_context (parent, &ctx);
- /* Checksum the current DIE. */
- die_odr_checksum (die->die_tag, name, &ctx);
- md5_finish_ctx (&ctx, checksum);
- add_AT_data8 (type_node->root_die, DW_AT_GNU_odr_signature, &checksum[8]);
- }
- /* Next, compute the complete type signature. */
- md5_init_ctx (&ctx);
- mark = 1;
- die->die_mark = mark;
- /* Checksum the names of surrounding namespaces and structures. */
- if (parent != NULL)
- checksum_die_context (parent, &ctx);
- /* Checksum the DIE and its children. */
- die_checksum_ordered (die, &ctx, &mark);
- unmark_all_dies (die);
- md5_finish_ctx (&ctx, checksum);
- /* Store the signature in the type node and link the type DIE and the
- type node together. */
- memcpy (type_node->signature, &checksum[16 - DWARF_TYPE_SIGNATURE_SIZE],
- DWARF_TYPE_SIGNATURE_SIZE);
- die->comdat_type_p = true;
- die->die_id.die_type_node = type_node;
- type_node->type_die = die;
- /* If the DIE is a specification, link its declaration to the type node
- as well. */
- if (decl != NULL)
- {
- decl->comdat_type_p = true;
- decl->die_id.die_type_node = type_node;
- }
- }
- /* Do the location expressions look same? */
- static inline int
- same_loc_p (dw_loc_descr_ref loc1, dw_loc_descr_ref loc2, int *mark)
- {
- return loc1->dw_loc_opc == loc2->dw_loc_opc
- && same_dw_val_p (&loc1->dw_loc_oprnd1, &loc2->dw_loc_oprnd1, mark)
- && same_dw_val_p (&loc1->dw_loc_oprnd2, &loc2->dw_loc_oprnd2, mark);
- }
- /* Do the values look the same? */
- static int
- same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
- {
- dw_loc_descr_ref loc1, loc2;
- rtx r1, r2;
- if (v1->val_class != v2->val_class)
- return 0;
- switch (v1->val_class)
- {
- case dw_val_class_const:
- return v1->v.val_int == v2->v.val_int;
- case dw_val_class_unsigned_const:
- return v1->v.val_unsigned == v2->v.val_unsigned;
- case dw_val_class_const_double:
- return v1->v.val_double.high == v2->v.val_double.high
- && v1->v.val_double.low == v2->v.val_double.low;
- case dw_val_class_wide_int:
- return *v1->v.val_wide == *v2->v.val_wide;
- case dw_val_class_vec:
- if (v1->v.val_vec.length != v2->v.val_vec.length
- || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
- return 0;
- if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array,
- v1->v.val_vec.length * v1->v.val_vec.elt_size))
- return 0;
- return 1;
- case dw_val_class_flag:
- return v1->v.val_flag == v2->v.val_flag;
- case dw_val_class_str:
- return !strcmp (v1->v.val_str->str, v2->v.val_str->str);
- case dw_val_class_addr:
- r1 = v1->v.val_addr;
- r2 = v2->v.val_addr;
- if (GET_CODE (r1) != GET_CODE (r2))
- return 0;
- return !rtx_equal_p (r1, r2);
- case dw_val_class_offset:
- return v1->v.val_offset == v2->v.val_offset;
- case dw_val_class_loc:
- for (loc1 = v1->v.val_loc, loc2 = v2->v.val_loc;
- loc1 && loc2;
- loc1 = loc1->dw_loc_next, loc2 = loc2->dw_loc_next)
- if (!same_loc_p (loc1, loc2, mark))
- return 0;
- return !loc1 && !loc2;
- case dw_val_class_die_ref:
- return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark);
- case dw_val_class_fde_ref:
- case dw_val_class_vms_delta:
- case dw_val_class_lbl_id:
- case dw_val_class_lineptr:
- case dw_val_class_macptr:
- case dw_val_class_high_pc:
- return 1;
- case dw_val_class_file:
- return v1->v.val_file == v2->v.val_file;
- case dw_val_class_data8:
- return !memcmp (v1->v.val_data8, v2->v.val_data8, 8);
- default:
- return 1;
- }
- }
- /* Do the attributes look the same? */
- static int
- same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
- {
- if (at1->dw_attr != at2->dw_attr)
- return 0;
- /* We don't care that this was compiled with a different compiler
- snapshot; if the output is the same, that's what matters. */
- if (at1->dw_attr == DW_AT_producer)
- return 1;
- return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
- }
- /* Do the dies look the same? */
- static int
- same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
- {
- dw_die_ref c1, c2;
- dw_attr_ref a1;
- unsigned ix;
- /* To avoid infinite recursion. */
- if (die1->die_mark)
- return die1->die_mark == die2->die_mark;
- die1->die_mark = die2->die_mark = ++(*mark);
- if (die1->die_tag != die2->die_tag)
- return 0;
- if (vec_safe_length (die1->die_attr) != vec_safe_length (die2->die_attr))
- return 0;
- FOR_EACH_VEC_SAFE_ELT (die1->die_attr, ix, a1)
- if (!same_attr_p (a1, &(*die2->die_attr)[ix], mark))
- return 0;
- c1 = die1->die_child;
- c2 = die2->die_child;
- if (! c1)
- {
- if (c2)
- return 0;
- }
- else
- for (;;)
- {
- if (!same_die_p (c1, c2, mark))
- return 0;
- c1 = c1->die_sib;
- c2 = c2->die_sib;
- if (c1 == die1->die_child)
- {
- if (c2 == die2->die_child)
- break;
- else
- return 0;
- }
- }
- return 1;
- }
- /* Do the dies look the same? Wrapper around same_die_p. */
- static int
- same_die_p_wrap (dw_die_ref die1, dw_die_ref die2)
- {
- int mark = 0;
- int ret = same_die_p (die1, die2, &mark);
- unmark_all_dies (die1);
- unmark_all_dies (die2);
- return ret;
- }
- /* The prefix to attach to symbols on DIEs in the current comdat debug
- info section. */
- static const char *comdat_symbol_id;
- /* The index of the current symbol within the current comdat CU. */
- static unsigned int comdat_symbol_number;
- /* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its
- children, and set comdat_symbol_id accordingly. */
- static void
- compute_section_prefix (dw_die_ref unit_die)
- {
- const char *die_name = get_AT_string (unit_die, DW_AT_name);
- const char *base = die_name ? lbasename (die_name) : "anonymous";
- char *name = XALLOCAVEC (char, strlen (base) + 64);
- char *p;
- int i, mark;
- unsigned char checksum[16];
- struct md5_ctx ctx;
- /* Compute the checksum of the DIE, then append part of it as hex digits to
- the name filename of the unit. */
- md5_init_ctx (&ctx);
- mark = 0;
- die_checksum (unit_die, &ctx, &mark);
- unmark_all_dies (unit_die);
- md5_finish_ctx (&ctx, checksum);
- sprintf (name, "%s.", base);
- clean_symbol_name (name);
- p = name + strlen (name);
- for (i = 0; i < 4; i++)
- {
- sprintf (p, "%.2x", checksum[i]);
- p += 2;
- }
- comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
- comdat_symbol_number = 0;
- }
- /* Returns nonzero if DIE represents a type, in the sense of TYPE_P. */
- static int
- is_type_die (dw_die_ref die)
- {
- switch (die->die_tag)
- {
- case DW_TAG_array_type:
- case DW_TAG_class_type:
- case DW_TAG_interface_type:
- case DW_TAG_enumeration_type:
- case DW_TAG_pointer_type:
- case DW_TAG_reference_type:
- case DW_TAG_rvalue_reference_type:
- case DW_TAG_string_type:
- case DW_TAG_structure_type:
- case DW_TAG_subroutine_type:
- case DW_TAG_union_type:
- case DW_TAG_ptr_to_member_type:
- case DW_TAG_set_type:
- case DW_TAG_subrange_type:
- case DW_TAG_base_type:
- case DW_TAG_const_type:
- case DW_TAG_file_type:
- case DW_TAG_packed_type:
- case DW_TAG_volatile_type:
- case DW_TAG_typedef:
- return 1;
- default:
- return 0;
- }
- }
- /* Returns 1 iff C is the sort of DIE that should go into a COMDAT CU.
- Basically, we want to choose the bits that are likely to be shared between
- compilations (types) and leave out the bits that are specific to individual
- compilations (functions). */
- static int
- is_comdat_die (dw_die_ref c)
- {
- /* I think we want to leave base types and __vtbl_ptr_type in the main CU, as
- we do for stabs. The advantage is a greater likelihood of sharing between
- objects that don't include headers in the same order (and therefore would
- put the base types in a different comdat). jason 8/28/00 */
- if (c->die_tag == DW_TAG_base_type)
- return 0;
- if (c->die_tag == DW_TAG_pointer_type
- || c->die_tag == DW_TAG_reference_type
- || c->die_tag == DW_TAG_rvalue_reference_type
- || c->die_tag == DW_TAG_const_type
- || c->die_tag == DW_TAG_volatile_type)
- {
- dw_die_ref t = get_AT_ref (c, DW_AT_type);
- return t ? is_comdat_die (t) : 0;
- }
- return is_type_die (c);
- }
- /* Returns 1 iff C is the sort of DIE that might be referred to from another
- compilation unit. */
- static int
- is_symbol_die (dw_die_ref c)
- {
- return (is_type_die (c)
- || is_declaration_die (c)
- || c->die_tag == DW_TAG_namespace
- || c->die_tag == DW_TAG_module);
- }
- /* Returns true iff C is a compile-unit DIE. */
- static inline bool
- is_cu_die (dw_die_ref c)
- {
- return c && c->die_tag == DW_TAG_compile_unit;
- }
- /* Returns true iff C is a unit DIE of some sort. */
- static inline bool
- is_unit_die (dw_die_ref c)
- {
- return c && (c->die_tag == DW_TAG_compile_unit
- || c->die_tag == DW_TAG_partial_unit
- || c->die_tag == DW_TAG_type_unit);
- }
- /* Returns true iff C is a namespace DIE. */
- static inline bool
- is_namespace_die (dw_die_ref c)
- {
- return c && c->die_tag == DW_TAG_namespace;
- }
- /* Returns true iff C is a class or structure DIE. */
- static inline bool
- is_class_die (dw_die_ref c)
- {
- return c && (c->die_tag == DW_TAG_class_type
- || c->die_tag == DW_TAG_structure_type);
- }
- /* Return non-zero if this DIE is a template parameter. */
- static inline bool
- is_template_parameter (dw_die_ref die)
- {
- switch (die->die_tag)
- {
- case DW_TAG_template_type_param:
- case DW_TAG_template_value_param:
- case DW_TAG_GNU_template_template_param:
- case DW_TAG_GNU_template_parameter_pack:
- return true;
- default:
- return false;
- }
- }
- /* Return non-zero if this DIE represents a template instantiation. */
- static inline bool
- is_template_instantiation (dw_die_ref die)
- {
- dw_die_ref c;
- if (!is_type_die (die) && die->die_tag != DW_TAG_subprogram)
- return false;
- FOR_EACH_CHILD (die, c, if (is_template_parameter (c)) return true);
- return false;
- }
- static char *
- gen_internal_sym (const char *prefix)
- {
- char buf[256];
- ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++);
- return xstrdup (buf);
- }
- /* Assign symbols to all worthy DIEs under DIE. */
- static void
- assign_symbol_names (dw_die_ref die)
- {
- dw_die_ref c;
- if (is_symbol_die (die) && !die->comdat_type_p)
- {
- if (comdat_symbol_id)
- {
- char *p = XALLOCAVEC (char, strlen (comdat_symbol_id) + 64);
- sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX,
- comdat_symbol_id, comdat_symbol_number++);
- die->die_id.die_symbol = xstrdup (p);
- }
- else
- die->die_id.die_symbol = gen_internal_sym ("LDIE");
- }
- FOR_EACH_CHILD (die, c, assign_symbol_names (c));
- }
- struct cu_hash_table_entry
- {
- dw_die_ref cu;
- unsigned min_comdat_num, max_comdat_num;
- struct cu_hash_table_entry *next;
- };
- /* Helpers to manipulate hash table of CUs. */
- struct cu_hash_table_entry_hasher
- {
- typedef cu_hash_table_entry value_type;
- typedef die_struct compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
- static inline void remove (value_type *);
- };
- inline hashval_t
- cu_hash_table_entry_hasher::hash (const value_type *entry)
- {
- return htab_hash_string (entry->cu->die_id.die_symbol);
- }
- inline bool
- cu_hash_table_entry_hasher::equal (const value_type *entry1,
- const compare_type *entry2)
- {
- return !strcmp (entry1->cu->die_id.die_symbol, entry2->die_id.die_symbol);
- }
- inline void
- cu_hash_table_entry_hasher::remove (value_type *entry)
- {
- struct cu_hash_table_entry *next;
- while (entry)
- {
- next = entry->next;
- free (entry);
- entry = next;
- }
- }
- typedef hash_table<cu_hash_table_entry_hasher> cu_hash_type;
- /* Check whether we have already seen this CU and set up SYM_NUM
- accordingly. */
- static int
- check_duplicate_cu (dw_die_ref cu, cu_hash_type *htable, unsigned int *sym_num)
- {
- struct cu_hash_table_entry dummy;
- struct cu_hash_table_entry **slot, *entry, *last = &dummy;
- dummy.max_comdat_num = 0;
- slot = htable->find_slot_with_hash (cu,
- htab_hash_string (cu->die_id.die_symbol),
- INSERT);
- entry = *slot;
- for (; entry; last = entry, entry = entry->next)
- {
- if (same_die_p_wrap (cu, entry->cu))
- break;
- }
- if (entry)
- {
- *sym_num = entry->min_comdat_num;
- return 1;
- }
- entry = XCNEW (struct cu_hash_table_entry);
- entry->cu = cu;
- entry->min_comdat_num = *sym_num = last->max_comdat_num;
- entry->next = *slot;
- *slot = entry;
- return 0;
- }
- /* Record SYM_NUM to record of CU in HTABLE. */
- static void
- record_comdat_symbol_number (dw_die_ref cu, cu_hash_type *htable,
- unsigned int sym_num)
- {
- struct cu_hash_table_entry **slot, *entry;
- slot = htable->find_slot_with_hash (cu,
- htab_hash_string (cu->die_id.die_symbol),
- NO_INSERT);
- entry = *slot;
- entry->max_comdat_num = sym_num;
- }
- /* Traverse the DIE (which is always comp_unit_die), and set up
- additional compilation units for each of the include files we see
- bracketed by BINCL/EINCL. */
- static void
- break_out_includes (dw_die_ref die)
- {
- dw_die_ref c;
- dw_die_ref unit = NULL;
- limbo_die_node *node, **pnode;
- c = die->die_child;
- if (c) do {
- dw_die_ref prev = c;
- c = c->die_sib;
- while (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
- || (unit && is_comdat_die (c)))
- {
- dw_die_ref next = c->die_sib;
- /* This DIE is for a secondary CU; remove it from the main one. */
- remove_child_with_prev (c, prev);
- if (c->die_tag == DW_TAG_GNU_BINCL)
- unit = push_new_compile_unit (unit, c);
- else if (c->die_tag == DW_TAG_GNU_EINCL)
- unit = pop_compile_unit (unit);
- else
- add_child_die (unit, c);
- c = next;
- if (c == die->die_child)
- break;
- }
- } while (c != die->die_child);
- #if 0
- /* We can only use this in debugging, since the frontend doesn't check
- to make sure that we leave every include file we enter. */
- gcc_assert (!unit);
- #endif
- assign_symbol_names (die);
- cu_hash_type cu_hash_table (10);
- for (node = limbo_die_list, pnode = &limbo_die_list;
- node;
- node = node->next)
- {
- int is_dupl;
- compute_section_prefix (node->die);
- is_dupl = check_duplicate_cu (node->die, &cu_hash_table,
- &comdat_symbol_number);
- assign_symbol_names (node->die);
- if (is_dupl)
- *pnode = node->next;
- else
- {
- pnode = &node->next;
- record_comdat_symbol_number (node->die, &cu_hash_table,
- comdat_symbol_number);
- }
- }
- }
- /* Return non-zero if this DIE is a declaration. */
- static int
- is_declaration_die (dw_die_ref die)
- {
- dw_attr_ref a;
- unsigned ix;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- if (a->dw_attr == DW_AT_declaration)
- return 1;
- return 0;
- }
- /* Return non-zero if this DIE is nested inside a subprogram. */
- static int
- is_nested_in_subprogram (dw_die_ref die)
- {
- dw_die_ref decl = get_AT_ref (die, DW_AT_specification);
- if (decl == NULL)
- decl = die;
- return local_scope_p (decl);
- }
- /* Return non-zero if this DIE contains a defining declaration of a
- subprogram. */
- static int
- contains_subprogram_definition (dw_die_ref die)
- {
- dw_die_ref c;
- if (die->die_tag == DW_TAG_subprogram && ! is_declaration_die (die))
- return 1;
- FOR_EACH_CHILD (die, c, if (contains_subprogram_definition (c)) return 1);
- return 0;
- }
- /* Return non-zero if this is a type DIE that should be moved to a
- COMDAT .debug_types section. */
- static int
- should_move_die_to_comdat (dw_die_ref die)
- {
- switch (die->die_tag)
- {
- case DW_TAG_class_type:
- case DW_TAG_structure_type:
- case DW_TAG_enumeration_type:
- case DW_TAG_union_type:
- /* Don't move declarations, inlined instances, types nested in a
- subprogram, or types that contain subprogram definitions. */
- if (is_declaration_die (die)
- || get_AT (die, DW_AT_abstract_origin)
- || is_nested_in_subprogram (die)
- || contains_subprogram_definition (die))
- return 0;
- return 1;
- case DW_TAG_array_type:
- case DW_TAG_interface_type:
- case DW_TAG_pointer_type:
- case DW_TAG_reference_type:
- case DW_TAG_rvalue_reference_type:
- case DW_TAG_string_type:
- case DW_TAG_subroutine_type:
- case DW_TAG_ptr_to_member_type:
- case DW_TAG_set_type:
- case DW_TAG_subrange_type:
- case DW_TAG_base_type:
- case DW_TAG_const_type:
- case DW_TAG_file_type:
- case DW_TAG_packed_type:
- case DW_TAG_volatile_type:
- case DW_TAG_typedef:
- default:
- return 0;
- }
- }
- /* Make a clone of DIE. */
- static dw_die_ref
- clone_die (dw_die_ref die)
- {
- dw_die_ref clone;
- dw_attr_ref a;
- unsigned ix;
- clone = ggc_cleared_alloc<die_node> ();
- clone->die_tag = die->die_tag;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- add_dwarf_attr (clone, a);
- return clone;
- }
- /* Make a clone of the tree rooted at DIE. */
- static dw_die_ref
- clone_tree (dw_die_ref die)
- {
- dw_die_ref c;
- dw_die_ref clone = clone_die (die);
- FOR_EACH_CHILD (die, c, add_child_die (clone, clone_tree (c)));
- return clone;
- }
- /* Make a clone of DIE as a declaration. */
- static dw_die_ref
- clone_as_declaration (dw_die_ref die)
- {
- dw_die_ref clone;
- dw_die_ref decl;
- dw_attr_ref a;
- unsigned ix;
- /* If the DIE is already a declaration, just clone it. */
- if (is_declaration_die (die))
- return clone_die (die);
- /* If the DIE is a specification, just clone its declaration DIE. */
- decl = get_AT_ref (die, DW_AT_specification);
- if (decl != NULL)
- {
- clone = clone_die (decl);
- if (die->comdat_type_p)
- add_AT_die_ref (clone, DW_AT_signature, die);
- return clone;
- }
- clone = ggc_cleared_alloc<die_node> ();
- clone->die_tag = die->die_tag;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- {
- /* We don't want to copy over all attributes.
- For example we don't want DW_AT_byte_size because otherwise we will no
- longer have a declaration and GDB will treat it as a definition. */
- switch (a->dw_attr)
- {
- case DW_AT_abstract_origin:
- case DW_AT_artificial:
- case DW_AT_containing_type:
- case DW_AT_external:
- case DW_AT_name:
- case DW_AT_type:
- case DW_AT_virtuality:
- case DW_AT_linkage_name:
- case DW_AT_MIPS_linkage_name:
- add_dwarf_attr (clone, a);
- break;
- case DW_AT_byte_size:
- default:
- break;
- }
- }
- if (die->comdat_type_p)
- add_AT_die_ref (clone, DW_AT_signature, die);
- add_AT_flag (clone, DW_AT_declaration, 1);
- return clone;
- }
- /* Structure to map a DIE in one CU to its copy in a comdat type unit. */
- struct decl_table_entry
- {
- dw_die_ref orig;
- dw_die_ref copy;
- };
- /* Helpers to manipulate hash table of copied declarations. */
- /* Hashtable helpers. */
- struct decl_table_entry_hasher : typed_free_remove <decl_table_entry>
- {
- typedef decl_table_entry value_type;
- typedef die_struct compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
- };
- inline hashval_t
- decl_table_entry_hasher::hash (const value_type *entry)
- {
- return htab_hash_pointer (entry->orig);
- }
- inline bool
- decl_table_entry_hasher::equal (const value_type *entry1,
- const compare_type *entry2)
- {
- return entry1->orig == entry2;
- }
- typedef hash_table<decl_table_entry_hasher> decl_hash_type;
- /* Copy DIE and its ancestors, up to, but not including, the compile unit
- or type unit entry, to a new tree. Adds the new tree to UNIT and returns
- a pointer to the copy of DIE. If DECL_TABLE is provided, it is used
- to check if the ancestor has already been copied into UNIT. */
- static dw_die_ref
- copy_ancestor_tree (dw_die_ref unit, dw_die_ref die,
- decl_hash_type *decl_table)
- {
- dw_die_ref parent = die->die_parent;
- dw_die_ref new_parent = unit;
- dw_die_ref copy;
- decl_table_entry **slot = NULL;
- struct decl_table_entry *entry = NULL;
- if (decl_table)
- {
- /* Check if the entry has already been copied to UNIT. */
- slot = decl_table->find_slot_with_hash (die, htab_hash_pointer (die),
- INSERT);
- if (*slot != HTAB_EMPTY_ENTRY)
- {
- entry = *slot;
- return entry->copy;
- }
- /* Record in DECL_TABLE that DIE has been copied to UNIT. */
- entry = XCNEW (struct decl_table_entry);
- entry->orig = die;
- entry->copy = NULL;
- *slot = entry;
- }
- if (parent != NULL)
- {
- dw_die_ref spec = get_AT_ref (parent, DW_AT_specification);
- if (spec != NULL)
- parent = spec;
- if (!is_unit_die (parent))
- new_parent = copy_ancestor_tree (unit, parent, decl_table);
- }
- copy = clone_as_declaration (die);
- add_child_die (new_parent, copy);
- if (decl_table)
- {
- /* Record the pointer to the copy. */
- entry->copy = copy;
- }
- return copy;
- }
- /* Copy the declaration context to the new type unit DIE. This includes
- any surrounding namespace or type declarations. If the DIE has an
- AT_specification attribute, it also includes attributes and children
- attached to the specification, and returns a pointer to the original
- parent of the declaration DIE. Returns NULL otherwise. */
- static dw_die_ref
- copy_declaration_context (dw_die_ref unit, dw_die_ref die)
- {
- dw_die_ref decl;
- dw_die_ref new_decl;
- dw_die_ref orig_parent = NULL;
- decl = get_AT_ref (die, DW_AT_specification);
- if (decl == NULL)
- decl = die;
- else
- {
- unsigned ix;
- dw_die_ref c;
- dw_attr_ref a;
- /* The original DIE will be changed to a declaration, and must
- be moved to be a child of the original declaration DIE. */
- orig_parent = decl->die_parent;
- /* Copy the type node pointer from the new DIE to the original
- declaration DIE so we can forward references later. */
- decl->comdat_type_p = true;
- decl->die_id.die_type_node = die->die_id.die_type_node;
- remove_AT (die, DW_AT_specification);
- FOR_EACH_VEC_SAFE_ELT (decl->die_attr, ix, a)
- {
- if (a->dw_attr != DW_AT_name
- && a->dw_attr != DW_AT_declaration
- && a->dw_attr != DW_AT_external)
- add_dwarf_attr (die, a);
- }
- FOR_EACH_CHILD (decl, c, add_child_die (die, clone_tree (c)));
- }
- if (decl->die_parent != NULL
- && !is_unit_die (decl->die_parent))
- {
- new_decl = copy_ancestor_tree (unit, decl, NULL);
- if (new_decl != NULL)
- {
- remove_AT (new_decl, DW_AT_signature);
- add_AT_specification (die, new_decl);
- }
- }
- return orig_parent;
- }
- /* Generate the skeleton ancestor tree for the given NODE, then clone
- the DIE and add the clone into the tree. */
- static void
- generate_skeleton_ancestor_tree (skeleton_chain_node *node)
- {
- if (node->new_die != NULL)
- return;
- node->new_die = clone_as_declaration (node->old_die);
- if (node->parent != NULL)
- {
- generate_skeleton_ancestor_tree (node->parent);
- add_child_die (node->parent->new_die, node->new_die);
- }
- }
- /* Generate a skeleton tree of DIEs containing any declarations that are
- found in the original tree. We traverse the tree looking for declaration
- DIEs, and construct the skeleton from the bottom up whenever we find one. */
- static void
- generate_skeleton_bottom_up (skeleton_chain_node *parent)
- {
- skeleton_chain_node node;
- dw_die_ref c;
- dw_die_ref first;
- dw_die_ref prev = NULL;
- dw_die_ref next = NULL;
- node.parent = parent;
- first = c = parent->old_die->die_child;
- if (c)
- next = c->die_sib;
- if (c) do {
- if (prev == NULL || prev->die_sib == c)
- prev = c;
- c = next;
- next = (c == first ? NULL : c->die_sib);
- node.old_die = c;
- node.new_die = NULL;
- if (is_declaration_die (c))
- {
- if (is_template_instantiation (c))
- {
- /* Instantiated templates do not need to be cloned into the
- type unit. Just move the DIE and its children back to
- the skeleton tree (in the main CU). */
- remove_child_with_prev (c, prev);
- add_child_die (parent->new_die, c);
- c = prev;
- }
- else
- {
- /* Clone the existing DIE, move the original to the skeleton
- tree (which is in the main CU), and put the clone, with
- all the original's children, where the original came from
- (which is about to be moved to the type unit). */
- dw_die_ref clone = clone_die (c);
- move_all_children (c, clone);
- /* If the original has a DW_AT_object_pointer attribute,
- it would now point to a child DIE just moved to the
- cloned tree, so we need to remove that attribute from
- the original. */
- remove_AT (c, DW_AT_object_pointer);
- replace_child (c, clone, prev);
- generate_skeleton_ancestor_tree (parent);
- add_child_die (parent->new_die, c);
- node.new_die = c;
- c = clone;
- }
- }
- generate_skeleton_bottom_up (&node);
- } while (next != NULL);
- }
- /* Wrapper function for generate_skeleton_bottom_up. */
- static dw_die_ref
- generate_skeleton (dw_die_ref die)
- {
- skeleton_chain_node node;
- node.old_die = die;
- node.new_die = NULL;
- node.parent = NULL;
- /* If this type definition is nested inside another type,
- and is not an instantiation of a template, always leave
- at least a declaration in its place. */
- if (die->die_parent != NULL
- && is_type_die (die->die_parent)
- && !is_template_instantiation (die))
- node.new_die = clone_as_declaration (die);
- generate_skeleton_bottom_up (&node);
- return node.new_die;
- }
- /* Remove the CHILD DIE from its parent, possibly replacing it with a cloned
- declaration. The original DIE is moved to a new compile unit so that
- existing references to it follow it to the new location. If any of the
- original DIE's descendants is a declaration, we need to replace the
- original DIE with a skeleton tree and move the declarations back into the
- skeleton tree. */
- static dw_die_ref
- remove_child_or_replace_with_skeleton (dw_die_ref unit, dw_die_ref child,
- dw_die_ref prev)
- {
- dw_die_ref skeleton, orig_parent;
- /* Copy the declaration context to the type unit DIE. If the returned
- ORIG_PARENT is not NULL, the skeleton needs to be added as a child of
- that DIE. */
- orig_parent = copy_declaration_context (unit, child);
- skeleton = generate_skeleton (child);
- if (skeleton == NULL)
- remove_child_with_prev (child, prev);
- else
- {
- skeleton->comdat_type_p = true;
- skeleton->die_id.die_type_node = child->die_id.die_type_node;
- /* If the original DIE was a specification, we need to put
- the skeleton under the parent DIE of the declaration.
- This leaves the original declaration in the tree, but
- it will be pruned later since there are no longer any
- references to it. */
- if (orig_parent != NULL)
- {
- remove_child_with_prev (child, prev);
- add_child_die (orig_parent, skeleton);
- }
- else
- replace_child (child, skeleton, prev);
- }
- return skeleton;
- }
- /* Traverse the DIE and set up additional .debug_types sections for each
- type worthy of being placed in a COMDAT section. */
- static void
- break_out_comdat_types (dw_die_ref die)
- {
- dw_die_ref c;
- dw_die_ref first;
- dw_die_ref prev = NULL;
- dw_die_ref next = NULL;
- dw_die_ref unit = NULL;
- first = c = die->die_child;
- if (c)
- next = c->die_sib;
- if (c) do {
- if (prev == NULL || prev->die_sib == c)
- prev = c;
- c = next;
- next = (c == first ? NULL : c->die_sib);
- if (should_move_die_to_comdat (c))
- {
- dw_die_ref replacement;
- comdat_type_node_ref type_node;
- /* Break out nested types into their own type units. */
- break_out_comdat_types (c);
- /* Create a new type unit DIE as the root for the new tree, and
- add it to the list of comdat types. */
- unit = new_die (DW_TAG_type_unit, NULL, NULL);
- add_AT_unsigned (unit, DW_AT_language,
- get_AT_unsigned (comp_unit_die (), DW_AT_language));
- type_node = ggc_cleared_alloc<comdat_type_node> ();
- type_node->root_die = unit;
- type_node->next = comdat_type_list;
- comdat_type_list = type_node;
- /* Generate the type signature. */
- generate_type_signature (c, type_node);
- /* Copy the declaration context, attributes, and children of the
- declaration into the new type unit DIE, then remove this DIE
- from the main CU (or replace it with a skeleton if necessary). */
- replacement = remove_child_or_replace_with_skeleton (unit, c, prev);
- type_node->skeleton_die = replacement;
- /* Add the DIE to the new compunit. */
- add_child_die (unit, c);
- if (replacement != NULL)
- c = replacement;
- }
- else if (c->die_tag == DW_TAG_namespace
- || c->die_tag == DW_TAG_class_type
- || c->die_tag == DW_TAG_structure_type
- || c->die_tag == DW_TAG_union_type)
- {
- /* Look for nested types that can be broken out. */
- break_out_comdat_types (c);
- }
- } while (next != NULL);
- }
- /* Like clone_tree, but copy DW_TAG_subprogram DIEs as declarations.
- Enter all the cloned children into the hash table decl_table. */
- static dw_die_ref
- clone_tree_partial (dw_die_ref die, decl_hash_type *decl_table)
- {
- dw_die_ref c;
- dw_die_ref clone;
- struct decl_table_entry *entry;
- decl_table_entry **slot;
- if (die->die_tag == DW_TAG_subprogram)
- clone = clone_as_declaration (die);
- else
- clone = clone_die (die);
- slot = decl_table->find_slot_with_hash (die,
- htab_hash_pointer (die), INSERT);
- /* Assert that DIE isn't in the hash table yet. If it would be there
- before, the ancestors would be necessarily there as well, therefore
- clone_tree_partial wouldn't be called. */
- gcc_assert (*slot == HTAB_EMPTY_ENTRY);
- entry = XCNEW (struct decl_table_entry);
- entry->orig = die;
- entry->copy = clone;
- *slot = entry;
- if (die->die_tag != DW_TAG_subprogram)
- FOR_EACH_CHILD (die, c,
- add_child_die (clone, clone_tree_partial (c, decl_table)));
- return clone;
- }
- /* Walk the DIE and its children, looking for references to incomplete
- or trivial types that are unmarked (i.e., that are not in the current
- type_unit). */
- static void
- copy_decls_walk (dw_die_ref unit, dw_die_ref die, decl_hash_type *decl_table)
- {
- dw_die_ref c;
- dw_attr_ref a;
- unsigned ix;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- {
- if (AT_class (a) == dw_val_class_die_ref)
- {
- dw_die_ref targ = AT_ref (a);
- decl_table_entry **slot;
- struct decl_table_entry *entry;
- if (targ->die_mark != 0 || targ->comdat_type_p)
- continue;
- slot = decl_table->find_slot_with_hash (targ,
- htab_hash_pointer (targ),
- INSERT);
- if (*slot != HTAB_EMPTY_ENTRY)
- {
- /* TARG has already been copied, so we just need to
- modify the reference to point to the copy. */
- entry = *slot;
- a->dw_attr_val.v.val_die_ref.die = entry->copy;
- }
- else
- {
- dw_die_ref parent = unit;
- dw_die_ref copy = clone_die (targ);
- /* Record in DECL_TABLE that TARG has been copied.
- Need to do this now, before the recursive call,
- because DECL_TABLE may be expanded and SLOT
- would no longer be a valid pointer. */
- entry = XCNEW (struct decl_table_entry);
- entry->orig = targ;
- entry->copy = copy;
- *slot = entry;
- /* If TARG is not a declaration DIE, we need to copy its
- children. */
- if (!is_declaration_die (targ))
- {
- FOR_EACH_CHILD (
- targ, c,
- add_child_die (copy,
- clone_tree_partial (c, decl_table)));
- }
- /* Make sure the cloned tree is marked as part of the
- type unit. */
- mark_dies (copy);
- /* If TARG has surrounding context, copy its ancestor tree
- into the new type unit. */
- if (targ->die_parent != NULL
- && !is_unit_die (targ->die_parent))
- parent = copy_ancestor_tree (unit, targ->die_parent,
- decl_table);
- add_child_die (parent, copy);
- a->dw_attr_val.v.val_die_ref.die = copy;
- /* Make sure the newly-copied DIE is walked. If it was
- installed in a previously-added context, it won't
- get visited otherwise. */
- if (parent != unit)
- {
- /* Find the highest point of the newly-added tree,
- mark each node along the way, and walk from there. */
- parent->die_mark = 1;
- while (parent->die_parent
- && parent->die_parent->die_mark == 0)
- {
- parent = parent->die_parent;
- parent->die_mark = 1;
- }
- copy_decls_walk (unit, parent, decl_table);
- }
- }
- }
- }
- FOR_EACH_CHILD (die, c, copy_decls_walk (unit, c, decl_table));
- }
- /* Copy declarations for "unworthy" types into the new comdat section.
- Incomplete types, modified types, and certain other types aren't broken
- out into comdat sections of their own, so they don't have a signature,
- and we need to copy the declaration into the same section so that we
- don't have an external reference. */
- static void
- copy_decls_for_unworthy_types (dw_die_ref unit)
- {
- mark_dies (unit);
- decl_hash_type decl_table (10);
- copy_decls_walk (unit, unit, &decl_table);
- unmark_dies (unit);
- }
- /* Traverse the DIE and add a sibling attribute if it may have the
- effect of speeding up access to siblings. To save some space,
- avoid generating sibling attributes for DIE's without children. */
- static void
- add_sibling_attributes (dw_die_ref die)
- {
- dw_die_ref c;
- if (! die->die_child)
- return;
- if (die->die_parent && die != die->die_parent->die_child)
- add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
- FOR_EACH_CHILD (die, c, add_sibling_attributes (c));
- }
- /* Output all location lists for the DIE and its children. */
- static void
- output_location_lists (dw_die_ref die)
- {
- dw_die_ref c;
- dw_attr_ref a;
- unsigned ix;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- if (AT_class (a) == dw_val_class_loc_list)
- output_loc_list (AT_loc_list (a));
- FOR_EACH_CHILD (die, c, output_location_lists (c));
- }
- /* We want to limit the number of external references, because they are
- larger than local references: a relocation takes multiple words, and
- even a sig8 reference is always eight bytes, whereas a local reference
- can be as small as one byte (though DW_FORM_ref is usually 4 in GCC).
- So if we encounter multiple external references to the same type DIE, we
- make a local typedef stub for it and redirect all references there.
- This is the element of the hash table for keeping track of these
- references. */
- struct external_ref
- {
- dw_die_ref type;
- dw_die_ref stub;
- unsigned n_refs;
- };
- /* Hashtable helpers. */
- struct external_ref_hasher : typed_free_remove <external_ref>
- {
- typedef external_ref value_type;
- typedef external_ref compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
- };
- inline hashval_t
- external_ref_hasher::hash (const value_type *r)
- {
- dw_die_ref die = r->type;
- hashval_t h = 0;
- /* We can't use the address of the DIE for hashing, because
- that will make the order of the stub DIEs non-deterministic. */
- if (! die->comdat_type_p)
- /* We have a symbol; use it to compute a hash. */
- h = htab_hash_string (die->die_id.die_symbol);
- else
- {
- /* We have a type signature; use a subset of the bits as the hash.
- The 8-byte signature is at least as large as hashval_t. */
- comdat_type_node_ref type_node = die->die_id.die_type_node;
- memcpy (&h, type_node->signature, sizeof (h));
- }
- return h;
- }
- inline bool
- external_ref_hasher::equal (const value_type *r1, const compare_type *r2)
- {
- return r1->type == r2->type;
- }
- typedef hash_table<external_ref_hasher> external_ref_hash_type;
- /* Return a pointer to the external_ref for references to DIE. */
- static struct external_ref *
- lookup_external_ref (external_ref_hash_type *map, dw_die_ref die)
- {
- struct external_ref ref, *ref_p;
- external_ref **slot;
- ref.type = die;
- slot = map->find_slot (&ref, INSERT);
- if (*slot != HTAB_EMPTY_ENTRY)
- return *slot;
- ref_p = XCNEW (struct external_ref);
- ref_p->type = die;
- *slot = ref_p;
- return ref_p;
- }
- /* Subroutine of optimize_external_refs, below.
- If we see a type skeleton, record it as our stub. If we see external
- references, remember how many we've seen. */
- static void
- optimize_external_refs_1 (dw_die_ref die, external_ref_hash_type *map)
- {
- dw_die_ref c;
- dw_attr_ref a;
- unsigned ix;
- struct external_ref *ref_p;
- if (is_type_die (die)
- && (c = get_AT_ref (die, DW_AT_signature)))
- {
- /* This is a local skeleton; use it for local references. */
- ref_p = lookup_external_ref (map, c);
- ref_p->stub = die;
- }
- /* Scan the DIE references, and remember any that refer to DIEs from
- other CUs (i.e. those which are not marked). */
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- if (AT_class (a) == dw_val_class_die_ref
- && (c = AT_ref (a))->die_mark == 0
- && is_type_die (c))
- {
- ref_p = lookup_external_ref (map, c);
- ref_p->n_refs++;
- }
- FOR_EACH_CHILD (die, c, optimize_external_refs_1 (c, map));
- }
- /* htab_traverse callback function for optimize_external_refs, below. SLOT
- points to an external_ref, DATA is the CU we're processing. If we don't
- already have a local stub, and we have multiple refs, build a stub. */
- int
- dwarf2_build_local_stub (external_ref **slot, dw_die_ref data)
- {
- struct external_ref *ref_p = *slot;
- if (ref_p->stub == NULL && ref_p->n_refs > 1 && !dwarf_strict)
- {
- /* We have multiple references to this type, so build a small stub.
- Both of these forms are a bit dodgy from the perspective of the
- DWARF standard, since technically they should have names. */
- dw_die_ref cu = data;
- dw_die_ref type = ref_p->type;
- dw_die_ref stub = NULL;
- if (type->comdat_type_p)
- {
- /* If we refer to this type via sig8, use AT_signature. */
- stub = new_die (type->die_tag, cu, NULL_TREE);
- add_AT_die_ref (stub, DW_AT_signature, type);
- }
- else
- {
- /* Otherwise, use a typedef with no name. */
- stub = new_die (DW_TAG_typedef, cu, NULL_TREE);
- add_AT_die_ref (stub, DW_AT_type, type);
- }
- stub->die_mark++;
- ref_p->stub = stub;
- }
- return 1;
- }
- /* DIE is a unit; look through all the DIE references to see if there are
- any external references to types, and if so, create local stubs for
- them which will be applied in build_abbrev_table. This is useful because
- references to local DIEs are smaller. */
- static external_ref_hash_type *
- optimize_external_refs (dw_die_ref die)
- {
- external_ref_hash_type *map = new external_ref_hash_type (10);
- optimize_external_refs_1 (die, map);
- map->traverse <dw_die_ref, dwarf2_build_local_stub> (die);
- return map;
- }
- /* The format of each DIE (and its attribute value pairs) is encoded in an
- abbreviation table. This routine builds the abbreviation table and assigns
- a unique abbreviation id for each abbreviation entry. The children of each
- die are visited recursively. */
- static void
- build_abbrev_table (dw_die_ref die, external_ref_hash_type *extern_map)
- {
- unsigned long abbrev_id;
- unsigned int n_alloc;
- dw_die_ref c;
- dw_attr_ref a;
- unsigned ix;
- /* Scan the DIE references, and replace any that refer to
- DIEs from other CUs (i.e. those which are not marked) with
- the local stubs we built in optimize_external_refs. */
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- if (AT_class (a) == dw_val_class_die_ref
- && (c = AT_ref (a))->die_mark == 0)
- {
- struct external_ref *ref_p;
- gcc_assert (AT_ref (a)->comdat_type_p || AT_ref (a)->die_id.die_symbol);
- ref_p = lookup_external_ref (extern_map, c);
- if (ref_p->stub && ref_p->stub != die)
- change_AT_die_ref (a, ref_p->stub);
- else
- /* We aren't changing this reference, so mark it external. */
- set_AT_ref_external (a, 1);
- }
- for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
- {
- dw_die_ref abbrev = abbrev_die_table[abbrev_id];
- dw_attr_ref die_a, abbrev_a;
- unsigned ix;
- bool ok = true;
- if (abbrev->die_tag != die->die_tag)
- continue;
- if ((abbrev->die_child != NULL) != (die->die_child != NULL))
- continue;
- if (vec_safe_length (abbrev->die_attr) != vec_safe_length (die->die_attr))
- continue;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, die_a)
- {
- abbrev_a = &(*abbrev->die_attr)[ix];
- if ((abbrev_a->dw_attr != die_a->dw_attr)
- || (value_format (abbrev_a) != value_format (die_a)))
- {
- ok = false;
- break;
- }
- }
- if (ok)
- break;
- }
- if (abbrev_id >= abbrev_die_table_in_use)
- {
- if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
- {
- n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
- abbrev_die_table = GGC_RESIZEVEC (dw_die_ref, abbrev_die_table,
- n_alloc);
- memset (&abbrev_die_table[abbrev_die_table_allocated], 0,
- (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
- abbrev_die_table_allocated = n_alloc;
- }
- ++abbrev_die_table_in_use;
- abbrev_die_table[abbrev_id] = die;
- }
- die->die_abbrev = abbrev_id;
- FOR_EACH_CHILD (die, c, build_abbrev_table (c, extern_map));
- }
- /* Return the power-of-two number of bytes necessary to represent VALUE. */
- static int
- constant_size (unsigned HOST_WIDE_INT value)
- {
- int log;
- if (value == 0)
- log = 0;
- else
- log = floor_log2 (value);
- log = log / 8;
- log = 1 << (floor_log2 (log) + 1);
- return log;
- }
- /* Return the size of a DIE as it is represented in the
- .debug_info section. */
- static unsigned long
- size_of_die (dw_die_ref die)
- {
- unsigned long size = 0;
- dw_attr_ref a;
- unsigned ix;
- enum dwarf_form form;
- size += size_of_uleb128 (die->die_abbrev);
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- {
- switch (AT_class (a))
- {
- case dw_val_class_addr:
- if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED)
- {
- gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED);
- size += size_of_uleb128 (AT_index (a));
- }
- else
- size += DWARF2_ADDR_SIZE;
- break;
- case dw_val_class_offset:
- size += DWARF_OFFSET_SIZE;
- break;
- case dw_val_class_loc:
- {
- unsigned long lsize = size_of_locs (AT_loc (a));
- /* Block length. */
- if (dwarf_version >= 4)
- size += size_of_uleb128 (lsize);
- else
- size += constant_size (lsize);
- size += lsize;
- }
- break;
- case dw_val_class_loc_list:
- if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED)
- {
- gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED);
- size += size_of_uleb128 (AT_index (a));
- }
- else
- size += DWARF_OFFSET_SIZE;
- break;
- case dw_val_class_range_list:
- size += DWARF_OFFSET_SIZE;
- break;
- case dw_val_class_const:
- size += size_of_sleb128 (AT_int (a));
- break;
- case dw_val_class_unsigned_const:
- {
- int csize = constant_size (AT_unsigned (a));
- if (dwarf_version == 3
- && a->dw_attr == DW_AT_data_member_location
- && csize >= 4)
- size += size_of_uleb128 (AT_unsigned (a));
- else
- size += csize;
- }
- break;
- case dw_val_class_const_double:
- size += HOST_BITS_PER_DOUBLE_INT / HOST_BITS_PER_CHAR;
- if (HOST_BITS_PER_WIDE_INT >= 64)
- size++; /* block */
- break;
- case dw_val_class_wide_int:
- size += (get_full_len (*a->dw_attr_val.v.val_wide)
- * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
- if (get_full_len (*a->dw_attr_val.v.val_wide) * HOST_BITS_PER_WIDE_INT
- > 64)
- size++; /* block */
- break;
- case dw_val_class_vec:
- size += constant_size (a->dw_attr_val.v.val_vec.length
- * a->dw_attr_val.v.val_vec.elt_size)
- + a->dw_attr_val.v.val_vec.length
- * a->dw_attr_val.v.val_vec.elt_size; /* block */
- break;
- case dw_val_class_flag:
- if (dwarf_version >= 4)
- /* Currently all add_AT_flag calls pass in 1 as last argument,
- so DW_FORM_flag_present can be used. If that ever changes,
- we'll need to use DW_FORM_flag and have some optimization
- in build_abbrev_table that will change those to
- DW_FORM_flag_present if it is set to 1 in all DIEs using
- the same abbrev entry. */
- gcc_assert (a->dw_attr_val.v.val_flag == 1);
- else
- size += 1;
- break;
- case dw_val_class_die_ref:
- if (AT_ref_external (a))
- {
- /* In DWARF4, we use DW_FORM_ref_sig8; for earlier versions
- we use DW_FORM_ref_addr. In DWARF2, DW_FORM_ref_addr
- is sized by target address length, whereas in DWARF3
- it's always sized as an offset. */
- if (use_debug_types)
- size += DWARF_TYPE_SIGNATURE_SIZE;
- else if (dwarf_version == 2)
- size += DWARF2_ADDR_SIZE;
- else
- size += DWARF_OFFSET_SIZE;
- }
- else
- size += DWARF_OFFSET_SIZE;
- break;
- case dw_val_class_fde_ref:
- size += DWARF_OFFSET_SIZE;
- break;
- case dw_val_class_lbl_id:
- if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED)
- {
- gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED);
- size += size_of_uleb128 (AT_index (a));
- }
- else
- size += DWARF2_ADDR_SIZE;
- break;
- case dw_val_class_lineptr:
- case dw_val_class_macptr:
- size += DWARF_OFFSET_SIZE;
- break;
- case dw_val_class_str:
- form = AT_string_form (a);
- if (form == DW_FORM_strp)
- size += DWARF_OFFSET_SIZE;
- else if (form == DW_FORM_GNU_str_index)
- size += size_of_uleb128 (AT_index (a));
- else
- size += strlen (a->dw_attr_val.v.val_str->str) + 1;
- break;
- case dw_val_class_file:
- size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file));
- break;
- case dw_val_class_data8:
- size += 8;
- break;
- case dw_val_class_vms_delta:
- size += DWARF_OFFSET_SIZE;
- break;
- case dw_val_class_high_pc:
- size += DWARF2_ADDR_SIZE;
- break;
- default:
- gcc_unreachable ();
- }
- }
- return size;
- }
- /* Size the debugging information associated with a given DIE. Visits the
- DIE's children recursively. Updates the global variable next_die_offset, on
- each time through. Uses the current value of next_die_offset to update the
- die_offset field in each DIE. */
- static void
- calc_die_sizes (dw_die_ref die)
- {
- dw_die_ref c;
- gcc_assert (die->die_offset == 0
- || (unsigned long int) die->die_offset == next_die_offset);
- die->die_offset = next_die_offset;
- next_die_offset += size_of_die (die);
- FOR_EACH_CHILD (die, c, calc_die_sizes (c));
- if (die->die_child != NULL)
- /* Count the null byte used to terminate sibling lists. */
- next_die_offset += 1;
- }
- /* Size just the base type children at the start of the CU.
- This is needed because build_abbrev needs to size locs
- and sizing of type based stack ops needs to know die_offset
- values for the base types. */
- static void
- calc_base_type_die_sizes (void)
- {
- unsigned long die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
- unsigned int i;
- dw_die_ref base_type;
- #if ENABLE_ASSERT_CHECKING
- dw_die_ref prev = comp_unit_die ()->die_child;
- #endif
- die_offset += size_of_die (comp_unit_die ());
- for (i = 0; base_types.iterate (i, &base_type); i++)
- {
- #if ENABLE_ASSERT_CHECKING
- gcc_assert (base_type->die_offset == 0
- && prev->die_sib == base_type
- && base_type->die_child == NULL
- && base_type->die_abbrev);
- prev = base_type;
- #endif
- base_type->die_offset = die_offset;
- die_offset += size_of_die (base_type);
- }
- }
- /* Set the marks for a die and its children. We do this so
- that we know whether or not a reference needs to use FORM_ref_addr; only
- DIEs in the same CU will be marked. We used to clear out the offset
- and use that as the flag, but ran into ordering problems. */
- static void
- mark_dies (dw_die_ref die)
- {
- dw_die_ref c;
- gcc_assert (!die->die_mark);
- die->die_mark = 1;
- FOR_EACH_CHILD (die, c, mark_dies (c));
- }
- /* Clear the marks for a die and its children. */
- static void
- unmark_dies (dw_die_ref die)
- {
- dw_die_ref c;
- if (! use_debug_types)
- gcc_assert (die->die_mark);
- die->die_mark = 0;
- FOR_EACH_CHILD (die, c, unmark_dies (c));
- }
- /* Clear the marks for a die, its children and referred dies. */
- static void
- unmark_all_dies (dw_die_ref die)
- {
- dw_die_ref c;
- dw_attr_ref a;
- unsigned ix;
- if (!die->die_mark)
- return;
- die->die_mark = 0;
- FOR_EACH_CHILD (die, c, unmark_all_dies (c));
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- if (AT_class (a) == dw_val_class_die_ref)
- unmark_all_dies (AT_ref (a));
- }
- /* Calculate if the entry should appear in the final output file. It may be
- from a pruned a type. */
- static bool
- include_pubname_in_output (vec<pubname_entry, va_gc> *table, pubname_entry *p)
- {
- /* By limiting gnu pubnames to definitions only, gold can generate a
- gdb index without entries for declarations, which don't include
- enough information to be useful. */
- if (debug_generate_pub_sections == 2 && is_declaration_die (p->die))
- return false;
- if (table == pubname_table)
- {
- /* Enumerator names are part of the pubname table, but the
- parent DW_TAG_enumeration_type die may have been pruned.
- Don't output them if that is the case. */
- if (p->die->die_tag == DW_TAG_enumerator &&
- (p->die->die_parent == NULL
- || !p->die->die_parent->die_perennial_p))
- return false;
- /* Everything else in the pubname table is included. */
- return true;
- }
- /* The pubtypes table shouldn't include types that have been
- pruned. */
- return (p->die->die_offset != 0
- || !flag_eliminate_unused_debug_types);
- }
- /* Return the size of the .debug_pubnames or .debug_pubtypes table
- generated for the compilation unit. */
- static unsigned long
- size_of_pubnames (vec<pubname_entry, va_gc> *names)
- {
- unsigned long size;
- unsigned i;
- pubname_ref p;
- int space_for_flags = (debug_generate_pub_sections == 2) ? 1 : 0;
- size = DWARF_PUBNAMES_HEADER_SIZE;
- FOR_EACH_VEC_ELT (*names, i, p)
- if (include_pubname_in_output (names, p))
- size += strlen (p->name) + DWARF_OFFSET_SIZE + 1 + space_for_flags;
- size += DWARF_OFFSET_SIZE;
- return size;
- }
- /* Return the size of the information in the .debug_aranges section. */
- static unsigned long
- size_of_aranges (void)
- {
- unsigned long size;
- size = DWARF_ARANGES_HEADER_SIZE;
- /* Count the address/length pair for this compilation unit. */
- if (text_section_used)
- size += 2 * DWARF2_ADDR_SIZE;
- if (cold_text_section_used)
- size += 2 * DWARF2_ADDR_SIZE;
- if (have_multiple_function_sections)
- {
- unsigned fde_idx;
- dw_fde_ref fde;
- FOR_EACH_VEC_ELT (*fde_vec, fde_idx, fde)
- {
- if (DECL_IGNORED_P (fde->decl))
- continue;
- if (!fde->in_std_section)
- size += 2 * DWARF2_ADDR_SIZE;
- if (fde->dw_fde_second_begin && !fde->second_in_std_section)
- size += 2 * DWARF2_ADDR_SIZE;
- }
- }
- /* Count the two zero words used to terminated the address range table. */
- size += 2 * DWARF2_ADDR_SIZE;
- return size;
- }
- /* Select the encoding of an attribute value. */
- static enum dwarf_form
- value_format (dw_attr_ref a)
- {
- switch (AT_class (a))
- {
- case dw_val_class_addr:
- /* Only very few attributes allow DW_FORM_addr. */
- switch (a->dw_attr)
- {
- case DW_AT_low_pc:
- case DW_AT_high_pc:
- case DW_AT_entry_pc:
- case DW_AT_trampoline:
- return (AT_index (a) == NOT_INDEXED
- ? DW_FORM_addr : DW_FORM_GNU_addr_index);
- default:
- break;
- }
- switch (DWARF2_ADDR_SIZE)
- {
- case 1:
- return DW_FORM_data1;
- case 2:
- return DW_FORM_data2;
- case 4:
- return DW_FORM_data4;
- case 8:
- return DW_FORM_data8;
- default:
- gcc_unreachable ();
- }
- case dw_val_class_range_list:
- case dw_val_class_loc_list:
- if (dwarf_version >= 4)
- return DW_FORM_sec_offset;
- /* FALLTHRU */
- case dw_val_class_vms_delta:
- case dw_val_class_offset:
- switch (DWARF_OFFSET_SIZE)
- {
- case 4:
- return DW_FORM_data4;
- case 8:
- return DW_FORM_data8;
- default:
- gcc_unreachable ();
- }
- case dw_val_class_loc:
- if (dwarf_version >= 4)
- return DW_FORM_exprloc;
- switch (constant_size (size_of_locs (AT_loc (a))))
- {
- case 1:
- return DW_FORM_block1;
- case 2:
- return DW_FORM_block2;
- case 4:
- return DW_FORM_block4;
- default:
- gcc_unreachable ();
- }
- case dw_val_class_const:
- return DW_FORM_sdata;
- case dw_val_class_unsigned_const:
- switch (constant_size (AT_unsigned (a)))
- {
- case 1:
- return DW_FORM_data1;
- case 2:
- return DW_FORM_data2;
- case 4:
- /* In DWARF3 DW_AT_data_member_location with
- DW_FORM_data4 or DW_FORM_data8 is a loclistptr, not
- constant, so we need to use DW_FORM_udata if we need
- a large constant. */
- if (dwarf_version == 3 && a->dw_attr == DW_AT_data_member_location)
- return DW_FORM_udata;
- return DW_FORM_data4;
- case 8:
- if (dwarf_version == 3 && a->dw_attr == DW_AT_data_member_location)
- return DW_FORM_udata;
- return DW_FORM_data8;
- default:
- gcc_unreachable ();
- }
- case dw_val_class_const_double:
- switch (HOST_BITS_PER_WIDE_INT)
- {
- case 8:
- return DW_FORM_data2;
- case 16:
- return DW_FORM_data4;
- case 32:
- return DW_FORM_data8;
- case 64:
- default:
- return DW_FORM_block1;
- }
- case dw_val_class_wide_int:
- switch (get_full_len (*a->dw_attr_val.v.val_wide) * HOST_BITS_PER_WIDE_INT)
- {
- case 8:
- return DW_FORM_data1;
- case 16:
- return DW_FORM_data2;
- case 32:
- return DW_FORM_data4;
- case 64:
- return DW_FORM_data8;
- default:
- return DW_FORM_block1;
- }
- case dw_val_class_vec:
- switch (constant_size (a->dw_attr_val.v.val_vec.length
- * a->dw_attr_val.v.val_vec.elt_size))
- {
- case 1:
- return DW_FORM_block1;
- case 2:
- return DW_FORM_block2;
- case 4:
- return DW_FORM_block4;
- default:
- gcc_unreachable ();
- }
- case dw_val_class_flag:
- if (dwarf_version >= 4)
- {
- /* Currently all add_AT_flag calls pass in 1 as last argument,
- so DW_FORM_flag_present can be used. If that ever changes,
- we'll need to use DW_FORM_flag and have some optimization
- in build_abbrev_table that will change those to
- DW_FORM_flag_present if it is set to 1 in all DIEs using
- the same abbrev entry. */
- gcc_assert (a->dw_attr_val.v.val_flag == 1);
- return DW_FORM_flag_present;
- }
- return DW_FORM_flag;
- case dw_val_class_die_ref:
- if (AT_ref_external (a))
- return use_debug_types ? DW_FORM_ref_sig8 : DW_FORM_ref_addr;
- else
- return DW_FORM_ref;
- case dw_val_class_fde_ref:
- return DW_FORM_data;
- case dw_val_class_lbl_id:
- return (AT_index (a) == NOT_INDEXED
- ? DW_FORM_addr : DW_FORM_GNU_addr_index);
- case dw_val_class_lineptr:
- case dw_val_class_macptr:
- return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
- case dw_val_class_str:
- return AT_string_form (a);
- case dw_val_class_file:
- switch (constant_size (maybe_emit_file (a->dw_attr_val.v.val_file)))
- {
- case 1:
- return DW_FORM_data1;
- case 2:
- return DW_FORM_data2;
- case 4:
- return DW_FORM_data4;
- default:
- gcc_unreachable ();
- }
- case dw_val_class_data8:
- return DW_FORM_data8;
- case dw_val_class_high_pc:
- switch (DWARF2_ADDR_SIZE)
- {
- case 1:
- return DW_FORM_data1;
- case 2:
- return DW_FORM_data2;
- case 4:
- return DW_FORM_data4;
- case 8:
- return DW_FORM_data8;
- default:
- gcc_unreachable ();
- }
- default:
- gcc_unreachable ();
- }
- }
- /* Output the encoding of an attribute value. */
- static void
- output_value_format (dw_attr_ref a)
- {
- enum dwarf_form form = value_format (a);
- dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
- }
- /* Given a die and id, produce the appropriate abbreviations. */
- static void
- output_die_abbrevs (unsigned long abbrev_id, dw_die_ref abbrev)
- {
- unsigned ix;
- dw_attr_ref a_attr;
- dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
- dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
- dwarf_tag_name (abbrev->die_tag));
- if (abbrev->die_child != NULL)
- dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
- else
- dw2_asm_output_data (1, DW_children_no, "DW_children_no");
- for (ix = 0; vec_safe_iterate (abbrev->die_attr, ix, &a_attr); ix++)
- {
- dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
- dwarf_attr_name (a_attr->dw_attr));
- output_value_format (a_attr);
- }
- dw2_asm_output_data (1, 0, NULL);
- dw2_asm_output_data (1, 0, NULL);
- }
- /* Output the .debug_abbrev section which defines the DIE abbreviation
- table. */
- static void
- output_abbrev_section (void)
- {
- unsigned long abbrev_id;
- for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
- output_die_abbrevs (abbrev_id, abbrev_die_table[abbrev_id]);
- /* Terminate the table. */
- dw2_asm_output_data (1, 0, NULL);
- }
- /* Output a symbol we can use to refer to this DIE from another CU. */
- static inline void
- output_die_symbol (dw_die_ref die)
- {
- const char *sym = die->die_id.die_symbol;
- gcc_assert (!die->comdat_type_p);
- if (sym == 0)
- return;
- if (strncmp (sym, DIE_LABEL_PREFIX, sizeof (DIE_LABEL_PREFIX) - 1) == 0)
- /* We make these global, not weak; if the target doesn't support
- .linkonce, it doesn't support combining the sections, so debugging
- will break. */
- targetm.asm_out.globalize_label (asm_out_file, sym);
- ASM_OUTPUT_LABEL (asm_out_file, sym);
- }
- /* Return a new location list, given the begin and end range, and the
- expression. */
- static inline dw_loc_list_ref
- new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
- const char *section)
- {
- dw_loc_list_ref retlist = ggc_cleared_alloc<dw_loc_list_node> ();
- retlist->begin = begin;
- retlist->begin_entry = NULL;
- retlist->end = end;
- retlist->expr = expr;
- retlist->section = section;
- return retlist;
- }
- /* Generate a new internal symbol for this location list node, if it
- hasn't got one yet. */
- static inline void
- gen_llsym (dw_loc_list_ref list)
- {
- gcc_assert (!list->ll_symbol);
- list->ll_symbol = gen_internal_sym ("LLST");
- }
- /* Output the location list given to us. */
- static void
- output_loc_list (dw_loc_list_ref list_head)
- {
- dw_loc_list_ref curr = list_head;
- if (list_head->emitted)
- return;
- list_head->emitted = true;
- ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
- /* Walk the location list, and output each range + expression. */
- for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
- {
- unsigned long size;
- /* Don't output an entry that starts and ends at the same address. */
- if (strcmp (curr->begin, curr->end) == 0 && !curr->force)
- continue;
- size = size_of_locs (curr->expr);
- /* If the expression is too large, drop it on the floor. We could
- perhaps put it into DW_TAG_dwarf_procedure and refer to that
- in the expression, but >= 64KB expressions for a single value
- in a single range are unlikely very useful. */
- if (size > 0xffff)
- continue;
- if (dwarf_split_debug_info)
- {
- dw2_asm_output_data (1, DW_LLE_GNU_start_length_entry,
- "Location list start/length entry (%s)",
- list_head->ll_symbol);
- dw2_asm_output_data_uleb128 (curr->begin_entry->index,
- "Location list range start index (%s)",
- curr->begin);
- /* The length field is 4 bytes. If we ever need to support
- an 8-byte length, we can add a new DW_LLE code or fall back
- to DW_LLE_GNU_start_end_entry. */
- dw2_asm_output_delta (4, curr->end, curr->begin,
- "Location list range length (%s)",
- list_head->ll_symbol);
- }
- else if (!have_multiple_function_sections)
- {
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
- "Location list begin address (%s)",
- list_head->ll_symbol);
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->end, curr->section,
- "Location list end address (%s)",
- list_head->ll_symbol);
- }
- else
- {
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->begin,
- "Location list begin address (%s)",
- list_head->ll_symbol);
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->end,
- "Location list end address (%s)",
- list_head->ll_symbol);
- }
- /* Output the block length for this list of location operations. */
- gcc_assert (size <= 0xffff);
- dw2_asm_output_data (2, size, "%s", "Location expression size");
- output_loc_sequence (curr->expr, -1);
- }
- if (dwarf_split_debug_info)
- dw2_asm_output_data (1, DW_LLE_GNU_end_of_list_entry,
- "Location list terminator (%s)",
- list_head->ll_symbol);
- else
- {
- dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
- "Location list terminator begin (%s)",
- list_head->ll_symbol);
- dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
- "Location list terminator end (%s)",
- list_head->ll_symbol);
- }
- }
- /* Output a range_list offset into the debug_range section. Emit a
- relocated reference if val_entry is NULL, otherwise, emit an
- indirect reference. */
- static void
- output_range_list_offset (dw_attr_ref a)
- {
- const char *name = dwarf_attr_name (a->dw_attr);
- if (a->dw_attr_val.val_entry == RELOCATED_OFFSET)
- {
- char *p = strchr (ranges_section_label, '\0');
- sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset);
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
- debug_ranges_section, "%s", name);
- *p = '\0';
- }
- else
- dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
- "%s (offset from %s)", name, ranges_section_label);
- }
- /* Output the offset into the debug_loc section. */
- static void
- output_loc_list_offset (dw_attr_ref a)
- {
- char *sym = AT_loc_list (a)->ll_symbol;
- gcc_assert (sym);
- if (dwarf_split_debug_info)
- dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
- "%s", dwarf_attr_name (a->dw_attr));
- else
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
- "%s", dwarf_attr_name (a->dw_attr));
- }
- /* Output an attribute's index or value appropriately. */
- static void
- output_attr_index_or_value (dw_attr_ref a)
- {
- const char *name = dwarf_attr_name (a->dw_attr);
- if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED)
- {
- dw2_asm_output_data_uleb128 (AT_index (a), "%s", name);
- return;
- }
- switch (AT_class (a))
- {
- case dw_val_class_addr:
- dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
- break;
- case dw_val_class_high_pc:
- case dw_val_class_lbl_id:
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
- break;
- case dw_val_class_loc_list:
- output_loc_list_offset (a);
- break;
- default:
- gcc_unreachable ();
- }
- }
- /* Output a type signature. */
- static inline void
- output_signature (const char *sig, const char *name)
- {
- int i;
- for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
- dw2_asm_output_data (1, sig[i], i == 0 ? "%s" : NULL, name);
- }
- /* Output the DIE and its attributes. Called recursively to generate
- the definitions of each child DIE. */
- static void
- output_die (dw_die_ref die)
- {
- dw_attr_ref a;
- dw_die_ref c;
- unsigned long size;
- unsigned ix;
- /* If someone in another CU might refer to us, set up a symbol for
- them to point to. */
- if (! die->comdat_type_p && die->die_id.die_symbol)
- output_die_symbol (die);
- dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
- (unsigned long)die->die_offset,
- dwarf_tag_name (die->die_tag));
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- {
- const char *name = dwarf_attr_name (a->dw_attr);
- switch (AT_class (a))
- {
- case dw_val_class_addr:
- output_attr_index_or_value (a);
- break;
- case dw_val_class_offset:
- dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
- "%s", name);
- break;
- case dw_val_class_range_list:
- output_range_list_offset (a);
- break;
- case dw_val_class_loc:
- size = size_of_locs (AT_loc (a));
- /* Output the block length for this list of location operations. */
- if (dwarf_version >= 4)
- dw2_asm_output_data_uleb128 (size, "%s", name);
- else
- dw2_asm_output_data (constant_size (size), size, "%s", name);
- output_loc_sequence (AT_loc (a), -1);
- break;
- case dw_val_class_const:
- /* ??? It would be slightly more efficient to use a scheme like is
- used for unsigned constants below, but gdb 4.x does not sign
- extend. Gdb 5.x does sign extend. */
- dw2_asm_output_data_sleb128 (AT_int (a), "%s", name);
- break;
- case dw_val_class_unsigned_const:
- {
- int csize = constant_size (AT_unsigned (a));
- if (dwarf_version == 3
- && a->dw_attr == DW_AT_data_member_location
- && csize >= 4)
- dw2_asm_output_data_uleb128 (AT_unsigned (a), "%s", name);
- else
- dw2_asm_output_data (csize, AT_unsigned (a), "%s", name);
- }
- break;
- case dw_val_class_const_double:
- {
- unsigned HOST_WIDE_INT first, second;
- if (HOST_BITS_PER_WIDE_INT >= 64)
- dw2_asm_output_data (1,
- HOST_BITS_PER_DOUBLE_INT
- / HOST_BITS_PER_CHAR,
- NULL);
- if (WORDS_BIG_ENDIAN)
- {
- first = a->dw_attr_val.v.val_double.high;
- second = a->dw_attr_val.v.val_double.low;
- }
- else
- {
- first = a->dw_attr_val.v.val_double.low;
- second = a->dw_attr_val.v.val_double.high;
- }
- dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
- first, "%s", name);
- dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
- second, NULL);
- }
- break;
- case dw_val_class_wide_int:
- {
- int i;
- int len = get_full_len (*a->dw_attr_val.v.val_wide);
- int l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
- if (len * HOST_BITS_PER_WIDE_INT > 64)
- dw2_asm_output_data (1, get_full_len (*a->dw_attr_val.v.val_wide) * l,
- NULL);
- if (WORDS_BIG_ENDIAN)
- for (i = len - 1; i >= 0; --i)
- {
- dw2_asm_output_data (l, a->dw_attr_val.v.val_wide->elt (i),
- "%s", name);
- name = NULL;
- }
- else
- for (i = 0; i < len; ++i)
- {
- dw2_asm_output_data (l, a->dw_attr_val.v.val_wide->elt (i),
- "%s", name);
- name = NULL;
- }
- }
- break;
- case dw_val_class_vec:
- {
- unsigned int elt_size = a->dw_attr_val.v.val_vec.elt_size;
- unsigned int len = a->dw_attr_val.v.val_vec.length;
- unsigned int i;
- unsigned char *p;
- dw2_asm_output_data (constant_size (len * elt_size),
- len * elt_size, "%s", name);
- if (elt_size > sizeof (HOST_WIDE_INT))
- {
- elt_size /= 2;
- len *= 2;
- }
- for (i = 0, p = a->dw_attr_val.v.val_vec.array;
- i < len;
- i++, p += elt_size)
- dw2_asm_output_data (elt_size, extract_int (p, elt_size),
- "fp or vector constant word %u", i);
- break;
- }
- case dw_val_class_flag:
- if (dwarf_version >= 4)
- {
- /* Currently all add_AT_flag calls pass in 1 as last argument,
- so DW_FORM_flag_present can be used. If that ever changes,
- we'll need to use DW_FORM_flag and have some optimization
- in build_abbrev_table that will change those to
- DW_FORM_flag_present if it is set to 1 in all DIEs using
- the same abbrev entry. */
- gcc_assert (AT_flag (a) == 1);
- if (flag_debug_asm)
- fprintf (asm_out_file, "\t\t\t%s %s\n",
- ASM_COMMENT_START, name);
- break;
- }
- dw2_asm_output_data (1, AT_flag (a), "%s", name);
- break;
- case dw_val_class_loc_list:
- output_attr_index_or_value (a);
- break;
- case dw_val_class_die_ref:
- if (AT_ref_external (a))
- {
- if (AT_ref (a)->comdat_type_p)
- {
- comdat_type_node_ref type_node =
- AT_ref (a)->die_id.die_type_node;
- gcc_assert (type_node);
- output_signature (type_node->signature, name);
- }
- else
- {
- const char *sym = AT_ref (a)->die_id.die_symbol;
- int size;
- gcc_assert (sym);
- /* In DWARF2, DW_FORM_ref_addr is sized by target address
- length, whereas in DWARF3 it's always sized as an
- offset. */
- if (dwarf_version == 2)
- size = DWARF2_ADDR_SIZE;
- else
- size = DWARF_OFFSET_SIZE;
- dw2_asm_output_offset (size, sym, debug_info_section, "%s",
- name);
- }
- }
- else
- {
- gcc_assert (AT_ref (a)->die_offset);
- dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset,
- "%s", name);
- }
- break;
- case dw_val_class_fde_ref:
- {
- char l1[20];
- ASM_GENERATE_INTERNAL_LABEL (l1, FDE_LABEL,
- a->dw_attr_val.v.val_fde_index * 2);
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, l1, debug_frame_section,
- "%s", name);
- }
- break;
- case dw_val_class_vms_delta:
- #ifdef ASM_OUTPUT_DWARF_VMS_DELTA
- dw2_asm_output_vms_delta (DWARF_OFFSET_SIZE,
- AT_vms_delta2 (a), AT_vms_delta1 (a),
- "%s", name);
- #else
- dw2_asm_output_delta (DWARF_OFFSET_SIZE,
- AT_vms_delta2 (a), AT_vms_delta1 (a),
- "%s", name);
- #endif
- break;
- case dw_val_class_lbl_id:
- output_attr_index_or_value (a);
- break;
- case dw_val_class_lineptr:
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
- debug_line_section, "%s", name);
- break;
- case dw_val_class_macptr:
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
- debug_macinfo_section, "%s", name);
- break;
- case dw_val_class_str:
- if (a->dw_attr_val.v.val_str->form == DW_FORM_strp)
- dw2_asm_output_offset (DWARF_OFFSET_SIZE,
- a->dw_attr_val.v.val_str->label,
- debug_str_section,
- "%s: \"%s\"", name, AT_string (a));
- else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
- dw2_asm_output_data_uleb128 (AT_index (a),
- "%s: \"%s\"", name, AT_string (a));
- else
- dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
- break;
- case dw_val_class_file:
- {
- int f = maybe_emit_file (a->dw_attr_val.v.val_file);
- dw2_asm_output_data (constant_size (f), f, "%s (%s)", name,
- a->dw_attr_val.v.val_file->filename);
- break;
- }
- case dw_val_class_data8:
- {
- int i;
- for (i = 0; i < 8; i++)
- dw2_asm_output_data (1, a->dw_attr_val.v.val_data8[i],
- i == 0 ? "%s" : NULL, name);
- break;
- }
- case dw_val_class_high_pc:
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, AT_lbl (a),
- get_AT_low_pc (die), "DW_AT_high_pc");
- break;
- default:
- gcc_unreachable ();
- }
- }
- FOR_EACH_CHILD (die, c, output_die (c));
- /* Add null byte to terminate sibling list. */
- if (die->die_child != NULL)
- dw2_asm_output_data (1, 0, "end of children of DIE %#lx",
- (unsigned long) die->die_offset);
- }
- /* Output the compilation unit that appears at the beginning of the
- .debug_info section, and precedes the DIE descriptions. */
- static void
- output_compilation_unit_header (void)
- {
- /* We don't support actual DWARFv5 units yet, we just use some
- DWARFv5 draft DIE tags in DWARFv4 format. */
- int ver = dwarf_version < 5 ? dwarf_version : 4;
- if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
- dw2_asm_output_data (4, 0xffffffff,
- "Initial length escape value indicating 64-bit DWARF extension");
- dw2_asm_output_data (DWARF_OFFSET_SIZE,
- next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
- "Length of Compilation Unit Info");
- dw2_asm_output_data (2, ver, "DWARF version number");
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
- debug_abbrev_section,
- "Offset Into Abbrev. Section");
- dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
- }
- /* Output the compilation unit DIE and its children. */
- static void
- output_comp_unit (dw_die_ref die, int output_if_empty)
- {
- const char *secname, *oldsym;
- char *tmp;
- /* Unless we are outputting main CU, we may throw away empty ones. */
- if (!output_if_empty && die->die_child == NULL)
- return;
- /* Even if there are no children of this DIE, we must output the information
- about the compilation unit. Otherwise, on an empty translation unit, we
- will generate a present, but empty, .debug_info section. IRIX 6.5 `nm'
- will then complain when examining the file. First mark all the DIEs in
- this CU so we know which get local refs. */
- mark_dies (die);
- external_ref_hash_type *extern_map = optimize_external_refs (die);
- build_abbrev_table (die, extern_map);
- delete extern_map;
- /* Initialize the beginning DIE offset - and calculate sizes/offsets. */
- next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
- calc_die_sizes (die);
- oldsym = die->die_id.die_symbol;
- if (oldsym)
- {
- tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
- sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym);
- secname = tmp;
- die->die_id.die_symbol = NULL;
- switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
- }
- else
- {
- switch_to_section (debug_info_section);
- ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
- info_section_emitted = true;
- }
- /* Output debugging information. */
- output_compilation_unit_header ();
- output_die (die);
- /* Leave the marks on the main CU, so we can check them in
- output_pubnames. */
- if (oldsym)
- {
- unmark_dies (die);
- die->die_id.die_symbol = oldsym;
- }
- }
- /* Whether to generate the DWARF accelerator tables in .debug_pubnames
- and .debug_pubtypes. This is configured per-target, but can be
- overridden by the -gpubnames or -gno-pubnames options. */
- static inline bool
- want_pubnames (void)
- {
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- return false;
- if (debug_generate_pub_sections != -1)
- return debug_generate_pub_sections;
- return targetm.want_debug_pub_sections;
- }
- /* Add the DW_AT_GNU_pubnames and DW_AT_GNU_pubtypes attributes. */
- static void
- add_AT_pubnames (dw_die_ref die)
- {
- if (want_pubnames ())
- add_AT_flag (die, DW_AT_GNU_pubnames, 1);
- }
- /* Add a string attribute value to a skeleton DIE. */
- static inline void
- add_skeleton_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind,
- const char *str)
- {
- dw_attr_node attr;
- struct indirect_string_node *node;
- if (! skeleton_debug_str_hash)
- skeleton_debug_str_hash
- = hash_table<indirect_string_hasher>::create_ggc (10);
- node = find_AT_string_in_table (str, skeleton_debug_str_hash);
- find_string_form (node);
- if (node->form == DW_FORM_GNU_str_index)
- node->form = DW_FORM_strp;
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_str;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_str = node;
- add_dwarf_attr (die, &attr);
- }
- /* Helper function to generate top-level dies for skeleton debug_info and
- debug_types. */
- static void
- add_top_level_skeleton_die_attrs (dw_die_ref die)
- {
- const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL);
- const char *comp_dir = comp_dir_string ();
- add_skeleton_AT_string (die, DW_AT_GNU_dwo_name, dwo_file_name);
- if (comp_dir != NULL)
- add_skeleton_AT_string (die, DW_AT_comp_dir, comp_dir);
- add_AT_pubnames (die);
- add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label);
- }
- /* Output skeleton debug sections that point to the dwo file. */
- static void
- output_skeleton_debug_sections (dw_die_ref comp_unit)
- {
- /* We don't support actual DWARFv5 units yet, we just use some
- DWARFv5 draft DIE tags in DWARFv4 format. */
- int ver = dwarf_version < 5 ? dwarf_version : 4;
- /* These attributes will be found in the full debug_info section. */
- remove_AT (comp_unit, DW_AT_producer);
- remove_AT (comp_unit, DW_AT_language);
- switch_to_section (debug_skeleton_info_section);
- ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_info_section_label);
- /* Produce the skeleton compilation-unit header. This one differs enough from
- a normal CU header that it's better not to call output_compilation_unit
- header. */
- if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
- dw2_asm_output_data (4, 0xffffffff,
- "Initial length escape value indicating 64-bit DWARF extension");
- dw2_asm_output_data (DWARF_OFFSET_SIZE,
- DWARF_COMPILE_UNIT_HEADER_SIZE
- - DWARF_INITIAL_LENGTH_SIZE
- + size_of_die (comp_unit),
- "Length of Compilation Unit Info");
- dw2_asm_output_data (2, ver, "DWARF version number");
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label,
- debug_abbrev_section,
- "Offset Into Abbrev. Section");
- dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
- comp_unit->die_abbrev = SKELETON_COMP_DIE_ABBREV;
- output_die (comp_unit);
- /* Build the skeleton debug_abbrev section. */
- switch_to_section (debug_skeleton_abbrev_section);
- ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_abbrev_section_label);
- output_die_abbrevs (SKELETON_COMP_DIE_ABBREV, comp_unit);
- dw2_asm_output_data (1, 0, "end of skeleton .debug_abbrev");
- }
- /* Output a comdat type unit DIE and its children. */
- static void
- output_comdat_type_unit (comdat_type_node *node)
- {
- const char *secname;
- char *tmp;
- int i;
- #if defined (OBJECT_FORMAT_ELF)
- tree comdat_key;
- #endif
- /* First mark all the DIEs in this CU so we know which get local refs. */
- mark_dies (node->root_die);
- external_ref_hash_type *extern_map = optimize_external_refs (node->root_die);
- build_abbrev_table (node->root_die, extern_map);
- delete extern_map;
- extern_map = NULL;
- /* Initialize the beginning DIE offset - and calculate sizes/offsets. */
- next_die_offset = DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE;
- calc_die_sizes (node->root_die);
- #if defined (OBJECT_FORMAT_ELF)
- if (!dwarf_split_debug_info)
- secname = ".debug_types";
- else
- secname = ".debug_types.dwo";
- tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
- sprintf (tmp, "wt.");
- for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
- sprintf (tmp + 3 + i * 2, "%02x", node->signature[i] & 0xff);
- comdat_key = get_identifier (tmp);
- targetm.asm_out.named_section (secname,
- SECTION_DEBUG | SECTION_LINKONCE,
- comdat_key);
- #else
- tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
- sprintf (tmp, ".gnu.linkonce.wt.");
- for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
- sprintf (tmp + 17 + i * 2, "%02x", node->signature[i] & 0xff);
- secname = tmp;
- switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
- #endif
- /* Output debugging information. */
- output_compilation_unit_header ();
- output_signature (node->signature, "Type Signature");
- dw2_asm_output_data (DWARF_OFFSET_SIZE, node->type_die->die_offset,
- "Offset to Type DIE");
- output_die (node->root_die);
- unmark_dies (node->root_die);
- }
- /* Return the DWARF2/3 pubname associated with a decl. */
- static const char *
- dwarf2_name (tree decl, int scope)
- {
- if (DECL_NAMELESS (decl))
- return NULL;
- return lang_hooks.dwarf_name (decl, scope ? 1 : 0);
- }
- /* Add a new entry to .debug_pubnames if appropriate. */
- static void
- add_pubname_string (const char *str, dw_die_ref die)
- {
- pubname_entry e;
- e.die = die;
- e.name = xstrdup (str);
- vec_safe_push (pubname_table, e);
- }
- static void
- add_pubname (tree decl, dw_die_ref die)
- {
- if (!want_pubnames ())
- return;
- /* Don't add items to the table when we expect that the consumer will have
- just read the enclosing die. For example, if the consumer is looking at a
- class_member, it will either be inside the class already, or will have just
- looked up the class to find the member. Either way, searching the class is
- faster than searching the index. */
- if ((TREE_PUBLIC (decl) && !class_scope_p (die->die_parent))
- || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
- {
- const char *name = dwarf2_name (decl, 1);
- if (name)
- add_pubname_string (name, die);
- }
- }
- /* Add an enumerator to the pubnames section. */
- static void
- add_enumerator_pubname (const char *scope_name, dw_die_ref die)
- {
- pubname_entry e;
- gcc_assert (scope_name);
- e.name = concat (scope_name, get_AT_string (die, DW_AT_name), NULL);
- e.die = die;
- vec_safe_push (pubname_table, e);
- }
- /* Add a new entry to .debug_pubtypes if appropriate. */
- static void
- add_pubtype (tree decl, dw_die_ref die)
- {
- pubname_entry e;
- if (!want_pubnames ())
- return;
- if ((TREE_PUBLIC (decl)
- || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
- && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
- {
- tree scope = NULL;
- const char *scope_name = "";
- const char *sep = is_cxx () ? "::" : ".";
- const char *name;
- scope = TYPE_P (decl) ? TYPE_CONTEXT (decl) : NULL;
- if (scope && TREE_CODE (scope) == NAMESPACE_DECL)
- {
- scope_name = lang_hooks.dwarf_name (scope, 1);
- if (scope_name != NULL && scope_name[0] != '\0')
- scope_name = concat (scope_name, sep, NULL);
- else
- scope_name = "";
- }
- if (TYPE_P (decl))
- name = type_tag (decl);
- else
- name = lang_hooks.dwarf_name (decl, 1);
- /* If we don't have a name for the type, there's no point in adding
- it to the table. */
- if (name != NULL && name[0] != '\0')
- {
- e.die = die;
- e.name = concat (scope_name, name, NULL);
- vec_safe_push (pubtype_table, e);
- }
- /* Although it might be more consistent to add the pubinfo for the
- enumerators as their dies are created, they should only be added if the
- enum type meets the criteria above. So rather than re-check the parent
- enum type whenever an enumerator die is created, just output them all
- here. This isn't protected by the name conditional because anonymous
- enums don't have names. */
- if (die->die_tag == DW_TAG_enumeration_type)
- {
- dw_die_ref c;
- FOR_EACH_CHILD (die, c, add_enumerator_pubname (scope_name, c));
- }
- }
- }
- /* Output a single entry in the pubnames table. */
- static void
- output_pubname (dw_offset die_offset, pubname_entry *entry)
- {
- dw_die_ref die = entry->die;
- int is_static = get_AT_flag (die, DW_AT_external) ? 0 : 1;
- dw2_asm_output_data (DWARF_OFFSET_SIZE, die_offset, "DIE offset");
- if (debug_generate_pub_sections == 2)
- {
- /* This logic follows gdb's method for determining the value of the flag
- byte. */
- uint32_t flags = GDB_INDEX_SYMBOL_KIND_NONE;
- switch (die->die_tag)
- {
- case DW_TAG_typedef:
- case DW_TAG_base_type:
- case DW_TAG_subrange_type:
- GDB_INDEX_SYMBOL_KIND_SET_VALUE(flags, GDB_INDEX_SYMBOL_KIND_TYPE);
- GDB_INDEX_SYMBOL_STATIC_SET_VALUE(flags, 1);
- break;
- case DW_TAG_enumerator:
- GDB_INDEX_SYMBOL_KIND_SET_VALUE(flags,
- GDB_INDEX_SYMBOL_KIND_VARIABLE);
- if (!is_cxx () && !is_java ())
- GDB_INDEX_SYMBOL_STATIC_SET_VALUE(flags, 1);
- break;
- case DW_TAG_subprogram:
- GDB_INDEX_SYMBOL_KIND_SET_VALUE(flags,
- GDB_INDEX_SYMBOL_KIND_FUNCTION);
- if (!is_ada ())
- GDB_INDEX_SYMBOL_STATIC_SET_VALUE(flags, is_static);
- break;
- case DW_TAG_constant:
- GDB_INDEX_SYMBOL_KIND_SET_VALUE(flags,
- GDB_INDEX_SYMBOL_KIND_VARIABLE);
- GDB_INDEX_SYMBOL_STATIC_SET_VALUE(flags, is_static);
- break;
- case DW_TAG_variable:
- GDB_INDEX_SYMBOL_KIND_SET_VALUE(flags,
- GDB_INDEX_SYMBOL_KIND_VARIABLE);
- GDB_INDEX_SYMBOL_STATIC_SET_VALUE(flags, is_static);
- break;
- case DW_TAG_namespace:
- case DW_TAG_imported_declaration:
- GDB_INDEX_SYMBOL_KIND_SET_VALUE(flags, GDB_INDEX_SYMBOL_KIND_TYPE);
- break;
- case DW_TAG_class_type:
- case DW_TAG_interface_type:
- case DW_TAG_structure_type:
- case DW_TAG_union_type:
- case DW_TAG_enumeration_type:
- GDB_INDEX_SYMBOL_KIND_SET_VALUE(flags, GDB_INDEX_SYMBOL_KIND_TYPE);
- if (!is_cxx () && !is_java ())
- GDB_INDEX_SYMBOL_STATIC_SET_VALUE(flags, 1);
- break;
- default:
- /* An unusual tag. Leave the flag-byte empty. */
- break;
- }
- dw2_asm_output_data (1, flags >> GDB_INDEX_CU_BITSIZE,
- "GDB-index flags");
- }
- dw2_asm_output_nstring (entry->name, -1, "external name");
- }
- /* Output the public names table used to speed up access to externally
- visible names; or the public types table used to find type definitions. */
- static void
- output_pubnames (vec<pubname_entry, va_gc> *names)
- {
- unsigned i;
- unsigned long pubnames_length = size_of_pubnames (names);
- pubname_ref pub;
- if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
- dw2_asm_output_data (4, 0xffffffff,
- "Initial length escape value indicating 64-bit DWARF extension");
- dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length, "Pub Info Length");
- /* Version number for pubnames/pubtypes is independent of dwarf version. */
- dw2_asm_output_data (2, 2, "DWARF Version");
- if (dwarf_split_debug_info)
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
- debug_skeleton_info_section,
- "Offset of Compilation Unit Info");
- else
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
- debug_info_section,
- "Offset of Compilation Unit Info");
- dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
- "Compilation Unit Length");
- FOR_EACH_VEC_ELT (*names, i, pub)
- {
- if (include_pubname_in_output (names, pub))
- {
- dw_offset die_offset = pub->die->die_offset;
- /* We shouldn't see pubnames for DIEs outside of the main CU. */
- if (names == pubname_table && pub->die->die_tag != DW_TAG_enumerator)
- gcc_assert (pub->die->die_mark);
- /* If we're putting types in their own .debug_types sections,
- the .debug_pubtypes table will still point to the compile
- unit (not the type unit), so we want to use the offset of
- the skeleton DIE (if there is one). */
- if (pub->die->comdat_type_p && names == pubtype_table)
- {
- comdat_type_node_ref type_node = pub->die->die_id.die_type_node;
- if (type_node != NULL)
- die_offset = (type_node->skeleton_die != NULL
- ? type_node->skeleton_die->die_offset
- : comp_unit_die ()->die_offset);
- }
- output_pubname (die_offset, pub);
- }
- }
- dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL);
- }
- /* Output public names and types tables if necessary. */
- static void
- output_pubtables (void)
- {
- if (!want_pubnames () || !info_section_emitted)
- return;
- switch_to_section (debug_pubnames_section);
- output_pubnames (pubname_table);
- /* ??? Only defined by DWARF3, but emitted by Darwin for DWARF2.
- It shouldn't hurt to emit it always, since pure DWARF2 consumers
- simply won't look for the section. */
- switch_to_section (debug_pubtypes_section);
- output_pubnames (pubtype_table);
- }
- /* Output the information that goes into the .debug_aranges table.
- Namely, define the beginning and ending address range of the
- text section generated for this compilation unit. */
- static void
- output_aranges (unsigned long aranges_length)
- {
- unsigned i;
- if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
- dw2_asm_output_data (4, 0xffffffff,
- "Initial length escape value indicating 64-bit DWARF extension");
- dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length,
- "Length of Address Ranges Info");
- /* Version number for aranges is still 2, even up to DWARF5. */
- dw2_asm_output_data (2, 2, "DWARF Version");
- if (dwarf_split_debug_info)
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
- debug_skeleton_info_section,
- "Offset of Compilation Unit Info");
- else
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
- debug_info_section,
- "Offset of Compilation Unit Info");
- dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
- dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
- /* We need to align to twice the pointer size here. */
- if (DWARF_ARANGES_PAD_SIZE)
- {
- /* Pad using a 2 byte words so that padding is correct for any
- pointer size. */
- dw2_asm_output_data (2, 0, "Pad to %d byte boundary",
- 2 * DWARF2_ADDR_SIZE);
- for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
- dw2_asm_output_data (2, 0, NULL);
- }
- /* It is necessary not to output these entries if the sections were
- not used; if the sections were not used, the length will be 0 and
- the address may end up as 0 if the section is discarded by ld
- --gc-sections, leaving an invalid (0, 0) entry that can be
- confused with the terminator. */
- if (text_section_used)
- {
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
- text_section_label, "Length");
- }
- if (cold_text_section_used)
- {
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
- "Address");
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
- cold_text_section_label, "Length");
- }
- if (have_multiple_function_sections)
- {
- unsigned fde_idx;
- dw_fde_ref fde;
- FOR_EACH_VEC_ELT (*fde_vec, fde_idx, fde)
- {
- if (DECL_IGNORED_P (fde->decl))
- continue;
- if (!fde->in_std_section)
- {
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
- "Address");
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, fde->dw_fde_end,
- fde->dw_fde_begin, "Length");
- }
- if (fde->dw_fde_second_begin && !fde->second_in_std_section)
- {
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_second_begin,
- "Address");
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, fde->dw_fde_second_end,
- fde->dw_fde_second_begin, "Length");
- }
- }
- }
- /* Output the terminator words. */
- dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
- dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
- }
- /* Add a new entry to .debug_ranges. Return the offset at which it
- was placed. */
- static unsigned int
- add_ranges_num (int num)
- {
- unsigned int in_use = ranges_table_in_use;
- if (in_use == ranges_table_allocated)
- {
- ranges_table_allocated += RANGES_TABLE_INCREMENT;
- ranges_table = GGC_RESIZEVEC (struct dw_ranges_struct, ranges_table,
- ranges_table_allocated);
- memset (ranges_table + ranges_table_in_use, 0,
- RANGES_TABLE_INCREMENT * sizeof (struct dw_ranges_struct));
- }
- ranges_table[in_use].num = num;
- ranges_table_in_use = in_use + 1;
- return in_use * 2 * DWARF2_ADDR_SIZE;
- }
- /* Add a new entry to .debug_ranges corresponding to a block, or a
- range terminator if BLOCK is NULL. */
- static unsigned int
- add_ranges (const_tree block)
- {
- return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
- }
- /* Add a new entry to .debug_ranges corresponding to a pair of labels.
- When using dwarf_split_debug_info, address attributes in dies destined
- for the final executable should be direct references--setting the
- parameter force_direct ensures this behavior. */
- static void
- add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
- bool *added, bool force_direct)
- {
- unsigned int in_use = ranges_by_label_in_use;
- unsigned int offset;
- if (in_use == ranges_by_label_allocated)
- {
- ranges_by_label_allocated += RANGES_TABLE_INCREMENT;
- ranges_by_label = GGC_RESIZEVEC (struct dw_ranges_by_label_struct,
- ranges_by_label,
- ranges_by_label_allocated);
- memset (ranges_by_label + ranges_by_label_in_use, 0,
- RANGES_TABLE_INCREMENT
- * sizeof (struct dw_ranges_by_label_struct));
- }
- ranges_by_label[in_use].begin = begin;
- ranges_by_label[in_use].end = end;
- ranges_by_label_in_use = in_use + 1;
- offset = add_ranges_num (-(int)in_use - 1);
- if (!*added)
- {
- add_AT_range_list (die, DW_AT_ranges, offset, force_direct);
- *added = true;
- }
- }
- static void
- output_ranges (void)
- {
- unsigned i;
- static const char *const start_fmt = "Offset %#x";
- const char *fmt = start_fmt;
- for (i = 0; i < ranges_table_in_use; i++)
- {
- int block_num = ranges_table[i].num;
- if (block_num > 0)
- {
- char blabel[MAX_ARTIFICIAL_LABEL_BYTES];
- char elabel[MAX_ARTIFICIAL_LABEL_BYTES];
- ASM_GENERATE_INTERNAL_LABEL (blabel, BLOCK_BEGIN_LABEL, block_num);
- ASM_GENERATE_INTERNAL_LABEL (elabel, BLOCK_END_LABEL, block_num);
- /* If all code is in the text section, then the compilation
- unit base address defaults to DW_AT_low_pc, which is the
- base of the text section. */
- if (!have_multiple_function_sections)
- {
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
- text_section_label,
- fmt, i * 2 * DWARF2_ADDR_SIZE);
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
- text_section_label, NULL);
- }
- /* Otherwise, the compilation unit base address is zero,
- which allows us to use absolute addresses, and not worry
- about whether the target supports cross-section
- arithmetic. */
- else
- {
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
- fmt, i * 2 * DWARF2_ADDR_SIZE);
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, elabel, NULL);
- }
- fmt = NULL;
- }
- /* Negative block_num stands for an index into ranges_by_label. */
- else if (block_num < 0)
- {
- int lab_idx = - block_num - 1;
- if (!have_multiple_function_sections)
- {
- gcc_unreachable ();
- #if 0
- /* If we ever use add_ranges_by_labels () for a single
- function section, all we have to do is to take out
- the #if 0 above. */
- dw2_asm_output_delta (DWARF2_ADDR_SIZE,
- ranges_by_label[lab_idx].begin,
- text_section_label,
- fmt, i * 2 * DWARF2_ADDR_SIZE);
- dw2_asm_output_delta (DWARF2_ADDR_SIZE,
- ranges_by_label[lab_idx].end,
- text_section_label, NULL);
- #endif
- }
- else
- {
- dw2_asm_output_addr (DWARF2_ADDR_SIZE,
- ranges_by_label[lab_idx].begin,
- fmt, i * 2 * DWARF2_ADDR_SIZE);
- dw2_asm_output_addr (DWARF2_ADDR_SIZE,
- ranges_by_label[lab_idx].end,
- NULL);
- }
- }
- else
- {
- dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
- dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
- fmt = start_fmt;
- }
- }
- }
- /* Data structure containing information about input files. */
- struct file_info
- {
- const char *path; /* Complete file name. */
- const char *fname; /* File name part. */
- int length; /* Length of entire string. */
- struct dwarf_file_data * file_idx; /* Index in input file table. */
- int dir_idx; /* Index in directory table. */
- };
- /* Data structure containing information about directories with source
- files. */
- struct dir_info
- {
- const char *path; /* Path including directory name. */
- int length; /* Path length. */
- int prefix; /* Index of directory entry which is a prefix. */
- int count; /* Number of files in this directory. */
- int dir_idx; /* Index of directory used as base. */
- };
- /* Callback function for file_info comparison. We sort by looking at
- the directories in the path. */
- static int
- file_info_cmp (const void *p1, const void *p2)
- {
- const struct file_info *const s1 = (const struct file_info *) p1;
- const struct file_info *const s2 = (const struct file_info *) p2;
- const unsigned char *cp1;
- const unsigned char *cp2;
- /* Take care of file names without directories. We need to make sure that
- we return consistent values to qsort since some will get confused if
- we return the same value when identical operands are passed in opposite
- orders. So if neither has a directory, return 0 and otherwise return
- 1 or -1 depending on which one has the directory. */
- if ((s1->path == s1->fname || s2->path == s2->fname))
- return (s2->path == s2->fname) - (s1->path == s1->fname);
- cp1 = (const unsigned char *) s1->path;
- cp2 = (const unsigned char *) s2->path;
- while (1)
- {
- ++cp1;
- ++cp2;
- /* Reached the end of the first path? If so, handle like above. */
- if ((cp1 == (const unsigned char *) s1->fname)
- || (cp2 == (const unsigned char *) s2->fname))
- return ((cp2 == (const unsigned char *) s2->fname)
- - (cp1 == (const unsigned char *) s1->fname));
- /* Character of current path component the same? */
- else if (*cp1 != *cp2)
- return *cp1 - *cp2;
- }
- }
- struct file_name_acquire_data
- {
- struct file_info *files;
- int used_files;
- int max_files;
- };
- /* Traversal function for the hash table. */
- int
- file_name_acquire (dwarf_file_data **slot, file_name_acquire_data *fnad)
- {
- struct dwarf_file_data *d = *slot;
- struct file_info *fi;
- const char *f;
- gcc_assert (fnad->max_files >= d->emitted_number);
- if (! d->emitted_number)
- return 1;
- gcc_assert (fnad->max_files != fnad->used_files);
- fi = fnad->files + fnad->used_files++;
- /* Skip all leading "./". */
- f = d->filename;
- while (f[0] == '.' && IS_DIR_SEPARATOR (f[1]))
- f += 2;
- /* Create a new array entry. */
- fi->path = f;
- fi->length = strlen (f);
- fi->file_idx = d;
- /* Search for the file name part. */
- f = strrchr (f, DIR_SEPARATOR);
- #if defined (DIR_SEPARATOR_2)
- {
- char *g = strrchr (fi->path, DIR_SEPARATOR_2);
- if (g != NULL)
- {
- if (f == NULL || f < g)
- f = g;
- }
- }
- #endif
- fi->fname = f == NULL ? fi->path : f + 1;
- return 1;
- }
- /* Output the directory table and the file name table. We try to minimize
- the total amount of memory needed. A heuristic is used to avoid large
- slowdowns with many input files. */
- static void
- output_file_names (void)
- {
- struct file_name_acquire_data fnad;
- int numfiles;
- struct file_info *files;
- struct dir_info *dirs;
- int *saved;
- int *savehere;
- int *backmap;
- int ndirs;
- int idx_offset;
- int i;
- if (!last_emitted_file)
- {
- dw2_asm_output_data (1, 0, "End directory table");
- dw2_asm_output_data (1, 0, "End file name table");
- return;
- }
- numfiles = last_emitted_file->emitted_number;
- /* Allocate the various arrays we need. */
- files = XALLOCAVEC (struct file_info, numfiles);
- dirs = XALLOCAVEC (struct dir_info, numfiles);
- fnad.files = files;
- fnad.used_files = 0;
- fnad.max_files = numfiles;
- file_table->traverse<file_name_acquire_data *, file_name_acquire> (&fnad);
- gcc_assert (fnad.used_files == fnad.max_files);
- qsort (files, numfiles, sizeof (files[0]), file_info_cmp);
- /* Find all the different directories used. */
- dirs[0].path = files[0].path;
- dirs[0].length = files[0].fname - files[0].path;
- dirs[0].prefix = -1;
- dirs[0].count = 1;
- dirs[0].dir_idx = 0;
- files[0].dir_idx = 0;
- ndirs = 1;
- for (i = 1; i < numfiles; i++)
- if (files[i].fname - files[i].path == dirs[ndirs - 1].length
- && memcmp (dirs[ndirs - 1].path, files[i].path,
- dirs[ndirs - 1].length) == 0)
- {
- /* Same directory as last entry. */
- files[i].dir_idx = ndirs - 1;
- ++dirs[ndirs - 1].count;
- }
- else
- {
- int j;
- /* This is a new directory. */
- dirs[ndirs].path = files[i].path;
- dirs[ndirs].length = files[i].fname - files[i].path;
- dirs[ndirs].count = 1;
- dirs[ndirs].dir_idx = ndirs;
- files[i].dir_idx = ndirs;
- /* Search for a prefix. */
- dirs[ndirs].prefix = -1;
- for (j = 0; j < ndirs; j++)
- if (dirs[j].length < dirs[ndirs].length
- && dirs[j].length > 1
- && (dirs[ndirs].prefix == -1
- || dirs[j].length > dirs[dirs[ndirs].prefix].length)
- && memcmp (dirs[j].path, dirs[ndirs].path, dirs[j].length) == 0)
- dirs[ndirs].prefix = j;
- ++ndirs;
- }
- /* Now to the actual work. We have to find a subset of the directories which
- allow expressing the file name using references to the directory table
- with the least amount of characters. We do not do an exhaustive search
- where we would have to check out every combination of every single
- possible prefix. Instead we use a heuristic which provides nearly optimal
- results in most cases and never is much off. */
- saved = XALLOCAVEC (int, ndirs);
- savehere = XALLOCAVEC (int, ndirs);
- memset (saved, '\0', ndirs * sizeof (saved[0]));
- for (i = 0; i < ndirs; i++)
- {
- int j;
- int total;
- /* We can always save some space for the current directory. But this
- does not mean it will be enough to justify adding the directory. */
- savehere[i] = dirs[i].length;
- total = (savehere[i] - saved[i]) * dirs[i].count;
- for (j = i + 1; j < ndirs; j++)
- {
- savehere[j] = 0;
- if (saved[j] < dirs[i].length)
- {
- /* Determine whether the dirs[i] path is a prefix of the
- dirs[j] path. */
- int k;
- k = dirs[j].prefix;
- while (k != -1 && k != (int) i)
- k = dirs[k].prefix;
- if (k == (int) i)
- {
- /* Yes it is. We can possibly save some memory by
- writing the filenames in dirs[j] relative to
- dirs[i]. */
- savehere[j] = dirs[i].length;
- total += (savehere[j] - saved[j]) * dirs[j].count;
- }
- }
- }
- /* Check whether we can save enough to justify adding the dirs[i]
- directory. */
- if (total > dirs[i].length + 1)
- {
- /* It's worthwhile adding. */
- for (j = i; j < ndirs; j++)
- if (savehere[j] > 0)
- {
- /* Remember how much we saved for this directory so far. */
- saved[j] = savehere[j];
- /* Remember the prefix directory. */
- dirs[j].dir_idx = i;
- }
- }
- }
- /* Emit the directory name table. */
- idx_offset = dirs[0].length > 0 ? 1 : 0;
- for (i = 1 - idx_offset; i < ndirs; i++)
- dw2_asm_output_nstring (dirs[i].path,
- dirs[i].length
- - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
- "Directory Entry: %#x", i + idx_offset);
- dw2_asm_output_data (1, 0, "End directory table");
- /* We have to emit them in the order of emitted_number since that's
- used in the debug info generation. To do this efficiently we
- generate a back-mapping of the indices first. */
- backmap = XALLOCAVEC (int, numfiles);
- for (i = 0; i < numfiles; i++)
- backmap[files[i].file_idx->emitted_number - 1] = i;
- /* Now write all the file names. */
- for (i = 0; i < numfiles; i++)
- {
- int file_idx = backmap[i];
- int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
- #ifdef VMS_DEBUGGING_INFO
- #define MAX_VMS_VERSION_LEN 6 /* ";32768" */
- /* Setting these fields can lead to debugger miscomparisons,
- but VMS Debug requires them to be set correctly. */
- int ver;
- long long cdt;
- long siz;
- int maxfilelen = strlen (files[file_idx].path)
- + dirs[dir_idx].length
- + MAX_VMS_VERSION_LEN + 1;
- char *filebuf = XALLOCAVEC (char, maxfilelen);
- vms_file_stats_name (files[file_idx].path, 0, 0, 0, &ver);
- snprintf (filebuf, maxfilelen, "%s;%d",
- files[file_idx].path + dirs[dir_idx].length, ver);
- dw2_asm_output_nstring
- (filebuf, -1, "File Entry: %#x", (unsigned) i + 1);
- /* Include directory index. */
- dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
- /* Modification time. */
- dw2_asm_output_data_uleb128
- ((vms_file_stats_name (files[file_idx].path, &cdt, 0, 0, 0) == 0)
- ? cdt : 0,
- NULL);
- /* File length in bytes. */
- dw2_asm_output_data_uleb128
- ((vms_file_stats_name (files[file_idx].path, 0, &siz, 0, 0) == 0)
- ? siz : 0,
- NULL);
- #else
- dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
- "File Entry: %#x", (unsigned) i + 1);
- /* Include directory index. */
- dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
- /* Modification time. */
- dw2_asm_output_data_uleb128 (0, NULL);
- /* File length in bytes. */
- dw2_asm_output_data_uleb128 (0, NULL);
- #endif /* VMS_DEBUGGING_INFO */
- }
- dw2_asm_output_data (1, 0, "End file name table");
- }
- /* Output one line number table into the .debug_line section. */
- static void
- output_one_line_info_table (dw_line_info_table *table)
- {
- char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
- unsigned int current_line = 1;
- bool current_is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
- dw_line_info_entry *ent;
- size_t i;
- FOR_EACH_VEC_SAFE_ELT (table->entries, i, ent)
- {
- switch (ent->opcode)
- {
- case LI_set_address:
- /* ??? Unfortunately, we have little choice here currently, and
- must always use the most general form. GCC does not know the
- address delta itself, so we can't use DW_LNS_advance_pc. Many
- ports do have length attributes which will give an upper bound
- on the address range. We could perhaps use length attributes
- to determine when it is safe to use DW_LNS_fixed_advance_pc. */
- ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val);
- /* This can handle any delta. This takes
- 4+DWARF2_ADDR_SIZE bytes. */
- dw2_asm_output_data (1, 0, "set address %s", line_label);
- dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
- dw2_asm_output_data (1, DW_LNE_set_address, NULL);
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
- break;
- case LI_set_line:
- if (ent->val == current_line)
- {
- /* We still need to start a new row, so output a copy insn. */
- dw2_asm_output_data (1, DW_LNS_copy,
- "copy line %u", current_line);
- }
- else
- {
- int line_offset = ent->val - current_line;
- int line_delta = line_offset - DWARF_LINE_BASE;
- current_line = ent->val;
- if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
- {
- /* This can handle deltas from -10 to 234, using the current
- definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE.
- This takes 1 byte. */
- dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
- "line %u", current_line);
- }
- else
- {
- /* This can handle any delta. This takes at least 4 bytes,
- depending on the value being encoded. */
- dw2_asm_output_data (1, DW_LNS_advance_line,
- "advance to line %u", current_line);
- dw2_asm_output_data_sleb128 (line_offset, NULL);
- dw2_asm_output_data (1, DW_LNS_copy, NULL);
- }
- }
- break;
- case LI_set_file:
- dw2_asm_output_data (1, DW_LNS_set_file, "set file %u", ent->val);
- dw2_asm_output_data_uleb128 (ent->val, "%u", ent->val);
- break;
- case LI_set_column:
- dw2_asm_output_data (1, DW_LNS_set_column, "column %u", ent->val);
- dw2_asm_output_data_uleb128 (ent->val, "%u", ent->val);
- break;
- case LI_negate_stmt:
- current_is_stmt = !current_is_stmt;
- dw2_asm_output_data (1, DW_LNS_negate_stmt,
- "is_stmt %d", current_is_stmt);
- break;
- case LI_set_prologue_end:
- dw2_asm_output_data (1, DW_LNS_set_prologue_end,
- "set prologue end");
- break;
-
- case LI_set_epilogue_begin:
- dw2_asm_output_data (1, DW_LNS_set_epilogue_begin,
- "set epilogue begin");
- break;
- case LI_set_discriminator:
- dw2_asm_output_data (1, 0, "discriminator %u", ent->val);
- dw2_asm_output_data_uleb128 (1 + size_of_uleb128 (ent->val), NULL);
- dw2_asm_output_data (1, DW_LNE_set_discriminator, NULL);
- dw2_asm_output_data_uleb128 (ent->val, NULL);
- break;
- }
- }
- /* Emit debug info for the address of the end of the table. */
- dw2_asm_output_data (1, 0, "set address %s", table->end_label);
- dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
- dw2_asm_output_data (1, DW_LNE_set_address, NULL);
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, table->end_label, NULL);
- dw2_asm_output_data (1, 0, "end sequence");
- dw2_asm_output_data_uleb128 (1, NULL);
- dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
- }
- /* Output the source line number correspondence information. This
- information goes into the .debug_line section. */
- static void
- output_line_info (bool prologue_only)
- {
- char l1[20], l2[20], p1[20], p2[20];
- /* We don't support DWARFv5 line tables yet. */
- int ver = dwarf_version < 5 ? dwarf_version : 4;
- bool saw_one = false;
- int opc;
- ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (p1, LN_PROLOG_AS_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (p2, LN_PROLOG_END_LABEL, 0);
- if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
- dw2_asm_output_data (4, 0xffffffff,
- "Initial length escape value indicating 64-bit DWARF extension");
- dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
- "Length of Source Line Info");
- ASM_OUTPUT_LABEL (asm_out_file, l1);
- dw2_asm_output_data (2, ver, "DWARF Version");
- dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
- ASM_OUTPUT_LABEL (asm_out_file, p1);
- /* Define the architecture-dependent minimum instruction length (in bytes).
- In this implementation of DWARF, this field is used for information
- purposes only. Since GCC generates assembly language, we have no
- a priori knowledge of how many instruction bytes are generated for each
- source line, and therefore can use only the DW_LNE_set_address and
- DW_LNS_fixed_advance_pc line information commands. Accordingly, we fix
- this as '1', which is "correct enough" for all architectures,
- and don't let the target override. */
- dw2_asm_output_data (1, 1, "Minimum Instruction Length");
- if (ver >= 4)
- dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN,
- "Maximum Operations Per Instruction");
- dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
- "Default is_stmt_start flag");
- dw2_asm_output_data (1, DWARF_LINE_BASE,
- "Line Base Value (Special Opcodes)");
- dw2_asm_output_data (1, DWARF_LINE_RANGE,
- "Line Range Value (Special Opcodes)");
- dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE,
- "Special Opcode Base");
- for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; opc++)
- {
- int n_op_args;
- switch (opc)
- {
- case DW_LNS_advance_pc:
- case DW_LNS_advance_line:
- case DW_LNS_set_file:
- case DW_LNS_set_column:
- case DW_LNS_fixed_advance_pc:
- case DW_LNS_set_isa:
- n_op_args = 1;
- break;
- default:
- n_op_args = 0;
- break;
- }
- dw2_asm_output_data (1, n_op_args, "opcode: %#x has %d args",
- opc, n_op_args);
- }
- /* Write out the information about the files we use. */
- output_file_names ();
- ASM_OUTPUT_LABEL (asm_out_file, p2);
- if (prologue_only)
- {
- /* Output the marker for the end of the line number info. */
- ASM_OUTPUT_LABEL (asm_out_file, l2);
- return;
- }
- if (separate_line_info)
- {
- dw_line_info_table *table;
- size_t i;
- FOR_EACH_VEC_ELT (*separate_line_info, i, table)
- if (table->in_use)
- {
- output_one_line_info_table (table);
- saw_one = true;
- }
- }
- if (cold_text_section_line_info && cold_text_section_line_info->in_use)
- {
- output_one_line_info_table (cold_text_section_line_info);
- saw_one = true;
- }
- /* ??? Some Darwin linkers crash on a .debug_line section with no
- sequences. Further, merely a DW_LNE_end_sequence entry is not
- sufficient -- the address column must also be initialized.
- Make sure to output at least one set_address/end_sequence pair,
- choosing .text since that section is always present. */
- if (text_section_line_info->in_use || !saw_one)
- output_one_line_info_table (text_section_line_info);
- /* Output the marker for the end of the line number info. */
- ASM_OUTPUT_LABEL (asm_out_file, l2);
- }
- /* Given a pointer to a tree node for some base type, return a pointer to
- a DIE that describes the given type.
- This routine must only be called for GCC type nodes that correspond to
- Dwarf base (fundamental) types. */
- static dw_die_ref
- base_type_die (tree type)
- {
- dw_die_ref base_type_result;
- enum dwarf_type encoding;
- if (TREE_CODE (type) == ERROR_MARK || TREE_CODE (type) == VOID_TYPE)
- return 0;
- /* If this is a subtype that should not be emitted as a subrange type,
- use the base type. See subrange_type_for_debug_p. */
- if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type) != NULL_TREE)
- type = TREE_TYPE (type);
- switch (TREE_CODE (type))
- {
- case INTEGER_TYPE:
- if ((dwarf_version >= 4 || !dwarf_strict)
- && TYPE_NAME (type)
- && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
- && DECL_IS_BUILTIN (TYPE_NAME (type))
- && DECL_NAME (TYPE_NAME (type)))
- {
- const char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
- if (strcmp (name, "char16_t") == 0
- || strcmp (name, "char32_t") == 0)
- {
- encoding = DW_ATE_UTF;
- break;
- }
- }
- if (TYPE_STRING_FLAG (type))
- {
- if (TYPE_UNSIGNED (type))
- encoding = DW_ATE_unsigned_char;
- else
- encoding = DW_ATE_signed_char;
- }
- else if (TYPE_UNSIGNED (type))
- encoding = DW_ATE_unsigned;
- else
- encoding = DW_ATE_signed;
- break;
- case REAL_TYPE:
- if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
- {
- if (dwarf_version >= 3 || !dwarf_strict)
- encoding = DW_ATE_decimal_float;
- else
- encoding = DW_ATE_lo_user;
- }
- else
- encoding = DW_ATE_float;
- break;
- case FIXED_POINT_TYPE:
- if (!(dwarf_version >= 3 || !dwarf_strict))
- encoding = DW_ATE_lo_user;
- else if (TYPE_UNSIGNED (type))
- encoding = DW_ATE_unsigned_fixed;
- else
- encoding = DW_ATE_signed_fixed;
- break;
- /* Dwarf2 doesn't know anything about complex ints, so use
- a user defined type for it. */
- case COMPLEX_TYPE:
- if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
- encoding = DW_ATE_complex_float;
- else
- encoding = DW_ATE_lo_user;
- break;
- case BOOLEAN_TYPE:
- /* GNU FORTRAN/Ada/C++ BOOLEAN type. */
- encoding = DW_ATE_boolean;
- break;
- default:
- /* No other TREE_CODEs are Dwarf fundamental types. */
- gcc_unreachable ();
- }
- base_type_result = new_die (DW_TAG_base_type, comp_unit_die (), type);
- add_AT_unsigned (base_type_result, DW_AT_byte_size,
- int_size_in_bytes (type));
- add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
- add_pubtype (type, base_type_result);
- return base_type_result;
- }
- /* A C++ function with deduced return type can have a TEMPLATE_TYPE_PARM
- named 'auto' in its type: return true for it, false otherwise. */
- static inline bool
- is_cxx_auto (tree type)
- {
- if (is_cxx ())
- {
- tree name = TYPE_IDENTIFIER (type);
- if (name == get_identifier ("auto")
- || name == get_identifier ("decltype(auto)"))
- return true;
- }
- return false;
- }
- /* Given a pointer to an arbitrary ..._TYPE tree node, return nonzero if the
- given input type is a Dwarf "fundamental" type. Otherwise return null. */
- static inline int
- is_base_type (tree type)
- {
- switch (TREE_CODE (type))
- {
- case ERROR_MARK:
- case VOID_TYPE:
- case INTEGER_TYPE:
- case REAL_TYPE:
- case FIXED_POINT_TYPE:
- case COMPLEX_TYPE:
- case BOOLEAN_TYPE:
- case POINTER_BOUNDS_TYPE:
- return 1;
- case ARRAY_TYPE:
- case RECORD_TYPE:
- case UNION_TYPE:
- case QUAL_UNION_TYPE:
- case ENUMERAL_TYPE:
- case FUNCTION_TYPE:
- case METHOD_TYPE:
- case POINTER_TYPE:
- case REFERENCE_TYPE:
- case NULLPTR_TYPE:
- case OFFSET_TYPE:
- case LANG_TYPE:
- case VECTOR_TYPE:
- return 0;
- default:
- if (is_cxx_auto (type))
- return 0;
- gcc_unreachable ();
- }
- return 0;
- }
- /* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
- node, return the size in bits for the type if it is a constant, or else
- return the alignment for the type if the type's size is not constant, or
- else return BITS_PER_WORD if the type actually turns out to be an
- ERROR_MARK node. */
- static inline unsigned HOST_WIDE_INT
- simple_type_size_in_bits (const_tree type)
- {
- if (TREE_CODE (type) == ERROR_MARK)
- return BITS_PER_WORD;
- else if (TYPE_SIZE (type) == NULL_TREE)
- return 0;
- else if (tree_fits_uhwi_p (TYPE_SIZE (type)))
- return tree_to_uhwi (TYPE_SIZE (type));
- else
- return TYPE_ALIGN (type);
- }
- /* Similarly, but return an offset_int instead of UHWI. */
- static inline offset_int
- offset_int_type_size_in_bits (const_tree type)
- {
- if (TREE_CODE (type) == ERROR_MARK)
- return BITS_PER_WORD;
- else if (TYPE_SIZE (type) == NULL_TREE)
- return 0;
- else if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
- return wi::to_offset (TYPE_SIZE (type));
- else
- return TYPE_ALIGN (type);
- }
- /* Given a pointer to a tree node for a subrange type, return a pointer
- to a DIE that describes the given type. */
- static dw_die_ref
- subrange_type_die (tree type, tree low, tree high, dw_die_ref context_die)
- {
- dw_die_ref subrange_die;
- const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type);
- if (context_die == NULL)
- context_die = comp_unit_die ();
- subrange_die = new_die (DW_TAG_subrange_type, context_die, type);
- if (int_size_in_bytes (TREE_TYPE (type)) != size_in_bytes)
- {
- /* The size of the subrange type and its base type do not match,
- so we need to generate a size attribute for the subrange type. */
- add_AT_unsigned (subrange_die, DW_AT_byte_size, size_in_bytes);
- }
- if (low)
- add_bound_info (subrange_die, DW_AT_lower_bound, low, NULL);
- if (high)
- add_bound_info (subrange_die, DW_AT_upper_bound, high, NULL);
- return subrange_die;
- }
- /* Returns the (const and/or volatile) cv_qualifiers associated with
- the decl node. This will normally be augmented with the
- cv_qualifiers of the underlying type in add_type_attribute. */
- static int
- decl_quals (const_tree decl)
- {
- return ((TREE_READONLY (decl)
- ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED)
- | (TREE_THIS_VOLATILE (decl)
- ? TYPE_QUAL_VOLATILE : TYPE_UNQUALIFIED));
- }
- /* Determine the TYPE whose qualifiers match the largest strict subset
- of the given TYPE_QUALS, and return its qualifiers. Ignore all
- qualifiers outside QUAL_MASK. */
- static int
- get_nearest_type_subqualifiers (tree type, int type_quals, int qual_mask)
- {
- tree t;
- int best_rank = 0, best_qual = 0, max_rank;
- type_quals &= qual_mask;
- max_rank = popcount_hwi (type_quals) - 1;
- for (t = TYPE_MAIN_VARIANT (type); t && best_rank < max_rank;
- t = TYPE_NEXT_VARIANT (t))
- {
- int q = TYPE_QUALS (t) & qual_mask;
- if ((q & type_quals) == q && q != type_quals
- && check_base_type (t, type))
- {
- int rank = popcount_hwi (q);
- if (rank > best_rank)
- {
- best_rank = rank;
- best_qual = q;
- }
- }
- }
- return best_qual;
- }
- /* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
- entry that chains various modifiers in front of the given type. */
- static dw_die_ref
- modified_type_die (tree type, int cv_quals, dw_die_ref context_die)
- {
- enum tree_code code = TREE_CODE (type);
- dw_die_ref mod_type_die;
- dw_die_ref sub_die = NULL;
- tree item_type = NULL;
- tree qualified_type;
- tree name, low, high;
- dw_die_ref mod_scope;
- /* Only these cv-qualifiers are currently handled. */
- const int cv_qual_mask = (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE
- | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC);
- if (code == ERROR_MARK)
- return NULL;
- cv_quals &= cv_qual_mask;
- /* Don't emit DW_TAG_restrict_type for DWARFv2, since it is a type
- tag modifier (and not an attribute) old consumers won't be able
- to handle it. */
- if (dwarf_version < 3)
- cv_quals &= ~TYPE_QUAL_RESTRICT;
- /* Likewise for DW_TAG_atomic_type for DWARFv5. */
- if (dwarf_version < 5)
- cv_quals &= ~TYPE_QUAL_ATOMIC;
- /* See if we already have the appropriately qualified variant of
- this type. */
- qualified_type = get_qualified_type (type, cv_quals);
- if (qualified_type == sizetype
- && TYPE_NAME (qualified_type)
- && TREE_CODE (TYPE_NAME (qualified_type)) == TYPE_DECL)
- {
- tree t = TREE_TYPE (TYPE_NAME (qualified_type));
- gcc_checking_assert (TREE_CODE (t) == INTEGER_TYPE
- && TYPE_PRECISION (t)
- == TYPE_PRECISION (qualified_type)
- && TYPE_UNSIGNED (t)
- == TYPE_UNSIGNED (qualified_type));
- qualified_type = t;
- }
- /* If we do, then we can just use its DIE, if it exists. */
- if (qualified_type)
- {
- mod_type_die = lookup_type_die (qualified_type);
- if (mod_type_die)
- return mod_type_die;
- }
- name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
- /* Handle C typedef types. */
- if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name)
- && !DECL_ARTIFICIAL (name))
- {
- tree dtype = TREE_TYPE (name);
- if (qualified_type == dtype)
- {
- /* For a named type, use the typedef. */
- gen_type_die (qualified_type, context_die);
- return lookup_type_die (qualified_type);
- }
- else
- {
- int dquals = TYPE_QUALS_NO_ADDR_SPACE (dtype);
- dquals &= cv_qual_mask;
- if ((dquals & ~cv_quals) != TYPE_UNQUALIFIED
- || (cv_quals == dquals && DECL_ORIGINAL_TYPE (name) != type))
- /* cv-unqualified version of named type. Just use
- the unnamed type to which it refers. */
- return modified_type_die (DECL_ORIGINAL_TYPE (name),
- cv_quals, context_die);
- /* Else cv-qualified version of named type; fall through. */
- }
- }
- mod_scope = scope_die_for (type, context_die);
- if (cv_quals)
- {
- struct qual_info { int q; enum dwarf_tag t; };
- static const struct qual_info qual_info[] =
- {
- { TYPE_QUAL_ATOMIC, DW_TAG_atomic_type },
- { TYPE_QUAL_RESTRICT, DW_TAG_restrict_type },
- { TYPE_QUAL_VOLATILE, DW_TAG_volatile_type },
- { TYPE_QUAL_CONST, DW_TAG_const_type },
- };
- int sub_quals;
- unsigned i;
- /* Determine a lesser qualified type that most closely matches
- this one. Then generate DW_TAG_* entries for the remaining
- qualifiers. */
- sub_quals = get_nearest_type_subqualifiers (type, cv_quals,
- cv_qual_mask);
- mod_type_die = modified_type_die (type, sub_quals, context_die);
- for (i = 0; i < sizeof (qual_info) / sizeof (qual_info[0]); i++)
- if (qual_info[i].q & cv_quals & ~sub_quals)
- {
- dw_die_ref d = new_die (qual_info[i].t, mod_scope, type);
- if (mod_type_die)
- add_AT_die_ref (d, DW_AT_type, mod_type_die);
- mod_type_die = d;
- }
- }
- else if (code == POINTER_TYPE)
- {
- mod_type_die = new_die (DW_TAG_pointer_type, mod_scope, type);
- add_AT_unsigned (mod_type_die, DW_AT_byte_size,
- simple_type_size_in_bits (type) / BITS_PER_UNIT);
- item_type = TREE_TYPE (type);
- if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type)))
- add_AT_unsigned (mod_type_die, DW_AT_address_class,
- TYPE_ADDR_SPACE (item_type));
- }
- else if (code == REFERENCE_TYPE)
- {
- if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4)
- mod_type_die = new_die (DW_TAG_rvalue_reference_type, mod_scope,
- type);
- else
- mod_type_die = new_die (DW_TAG_reference_type, mod_scope, type);
- add_AT_unsigned (mod_type_die, DW_AT_byte_size,
- simple_type_size_in_bits (type) / BITS_PER_UNIT);
- item_type = TREE_TYPE (type);
- if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type)))
- add_AT_unsigned (mod_type_die, DW_AT_address_class,
- TYPE_ADDR_SPACE (item_type));
- }
- else if (code == INTEGER_TYPE
- && TREE_TYPE (type) != NULL_TREE
- && subrange_type_for_debug_p (type, &low, &high))
- {
- mod_type_die = subrange_type_die (type, low, high, context_die);
- item_type = TREE_TYPE (type);
- }
- else if (is_base_type (type))
- mod_type_die = base_type_die (type);
- else
- {
- gen_type_die (type, context_die);
- /* We have to get the type_main_variant here (and pass that to the
- `lookup_type_die' routine) because the ..._TYPE node we have
- might simply be a *copy* of some original type node (where the
- copy was created to help us keep track of typedef names) and
- that copy might have a different TYPE_UID from the original
- ..._TYPE node. */
- if (TREE_CODE (type) != VECTOR_TYPE)
- return lookup_type_die (type_main_variant (type));
- else
- /* Vectors have the debugging information in the type,
- not the main variant. */
- return lookup_type_die (type);
- }
- /* Builtin types don't have a DECL_ORIGINAL_TYPE. For those,
- don't output a DW_TAG_typedef, since there isn't one in the
- user's program; just attach a DW_AT_name to the type.
- Don't attach a DW_AT_name to DW_TAG_const_type or DW_TAG_volatile_type
- if the base type already has the same name. */
- if (name
- && ((TREE_CODE (name) != TYPE_DECL
- && (qualified_type == TYPE_MAIN_VARIANT (type)
- || (cv_quals == TYPE_UNQUALIFIED)))
- || (TREE_CODE (name) == TYPE_DECL
- && TREE_TYPE (name) == qualified_type
- && DECL_NAME (name))))
- {
- if (TREE_CODE (name) == TYPE_DECL)
- /* Could just call add_name_and_src_coords_attributes here,
- but since this is a builtin type it doesn't have any
- useful source coordinates anyway. */
- name = DECL_NAME (name);
- add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
- }
- /* This probably indicates a bug. */
- else if (mod_type_die && mod_type_die->die_tag == DW_TAG_base_type)
- {
- name = TYPE_IDENTIFIER (type);
- add_name_attribute (mod_type_die,
- name ? IDENTIFIER_POINTER (name) : "__unknown__");
- }
- if (qualified_type)
- equate_type_number_to_die (qualified_type, mod_type_die);
- if (item_type)
- /* We must do this after the equate_type_number_to_die call, in case
- this is a recursive type. This ensures that the modified_type_die
- recursion will terminate even if the type is recursive. Recursive
- types are possible in Ada. */
- sub_die = modified_type_die (item_type,
- TYPE_QUALS_NO_ADDR_SPACE (item_type),
- context_die);
- if (sub_die != NULL)
- add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
- add_gnat_descriptive_type_attribute (mod_type_die, type, context_die);
- if (TYPE_ARTIFICIAL (type))
- add_AT_flag (mod_type_die, DW_AT_artificial, 1);
- return mod_type_die;
- }
- /* Generate DIEs for the generic parameters of T.
- T must be either a generic type or a generic function.
- See http://gcc.gnu.org/wiki/TemplateParmsDwarf for more. */
- static void
- gen_generic_params_dies (tree t)
- {
- tree parms, args;
- int parms_num, i;
- dw_die_ref die = NULL;
- int non_default;
- if (!t || (TYPE_P (t) && !COMPLETE_TYPE_P (t)))
- return;
- if (TYPE_P (t))
- die = lookup_type_die (t);
- else if (DECL_P (t))
- die = lookup_decl_die (t);
- gcc_assert (die);
- parms = lang_hooks.get_innermost_generic_parms (t);
- if (!parms)
- /* T has no generic parameter. It means T is neither a generic type
- or function. End of story. */
- return;
- parms_num = TREE_VEC_LENGTH (parms);
- args = lang_hooks.get_innermost_generic_args (t);
- if (TREE_CHAIN (args) && TREE_CODE (TREE_CHAIN (args)) == INTEGER_CST)
- non_default = int_cst_value (TREE_CHAIN (args));
- else
- non_default = TREE_VEC_LENGTH (args);
- for (i = 0; i < parms_num; i++)
- {
- tree parm, arg, arg_pack_elems;
- dw_die_ref parm_die;
- parm = TREE_VEC_ELT (parms, i);
- arg = TREE_VEC_ELT (args, i);
- arg_pack_elems = lang_hooks.types.get_argument_pack_elems (arg);
- gcc_assert (parm && TREE_VALUE (parm) && arg);
- if (parm && TREE_VALUE (parm) && arg)
- {
- /* If PARM represents a template parameter pack,
- emit a DW_TAG_GNU_template_parameter_pack DIE, followed
- by DW_TAG_template_*_parameter DIEs for the argument
- pack elements of ARG. Note that ARG would then be
- an argument pack. */
- if (arg_pack_elems)
- parm_die = template_parameter_pack_die (TREE_VALUE (parm),
- arg_pack_elems,
- die);
- else
- parm_die = generic_parameter_die (TREE_VALUE (parm), arg,
- true /* emit name */, die);
- if (i >= non_default)
- add_AT_flag (parm_die, DW_AT_default_value, 1);
- }
- }
- }
- /* Create and return a DIE for PARM which should be
- the representation of a generic type parameter.
- For instance, in the C++ front end, PARM would be a template parameter.
- ARG is the argument to PARM.
- EMIT_NAME_P if tree, the DIE will have DW_AT_name attribute set to the
- name of the PARM.
- PARENT_DIE is the parent DIE which the new created DIE should be added to,
- as a child node. */
- static dw_die_ref
- generic_parameter_die (tree parm, tree arg,
- bool emit_name_p,
- dw_die_ref parent_die)
- {
- dw_die_ref tmpl_die = NULL;
- const char *name = NULL;
- if (!parm || !DECL_NAME (parm) || !arg)
- return NULL;
- /* We support non-type generic parameters and arguments,
- type generic parameters and arguments, as well as
- generic generic parameters (a.k.a. template template parameters in C++)
- and arguments. */
- if (TREE_CODE (parm) == PARM_DECL)
- /* PARM is a nontype generic parameter */
- tmpl_die = new_die (DW_TAG_template_value_param, parent_die, parm);
- else if (TREE_CODE (parm) == TYPE_DECL)
- /* PARM is a type generic parameter. */
- tmpl_die = new_die (DW_TAG_template_type_param, parent_die, parm);
- else if (lang_hooks.decls.generic_generic_parameter_decl_p (parm))
- /* PARM is a generic generic parameter.
- Its DIE is a GNU extension. It shall have a
- DW_AT_name attribute to represent the name of the template template
- parameter, and a DW_AT_GNU_template_name attribute to represent the
- name of the template template argument. */
- tmpl_die = new_die (DW_TAG_GNU_template_template_param,
- parent_die, parm);
- else
- gcc_unreachable ();
- if (tmpl_die)
- {
- tree tmpl_type;
- /* If PARM is a generic parameter pack, it means we are
- emitting debug info for a template argument pack element.
- In other terms, ARG is a template argument pack element.
- In that case, we don't emit any DW_AT_name attribute for
- the die. */
- if (emit_name_p)
- {
- name = IDENTIFIER_POINTER (DECL_NAME (parm));
- gcc_assert (name);
- add_AT_string (tmpl_die, DW_AT_name, name);
- }
- if (!lang_hooks.decls.generic_generic_parameter_decl_p (parm))
- {
- /* DWARF3, 5.6.8 says if PARM is a non-type generic parameter
- TMPL_DIE should have a child DW_AT_type attribute that is set
- to the type of the argument to PARM, which is ARG.
- If PARM is a type generic parameter, TMPL_DIE should have a
- child DW_AT_type that is set to ARG. */
- tmpl_type = TYPE_P (arg) ? arg : TREE_TYPE (arg);
- add_type_attribute (tmpl_die, tmpl_type,
- (TREE_THIS_VOLATILE (tmpl_type)
- ? TYPE_QUAL_VOLATILE : TYPE_UNQUALIFIED),
- parent_die);
- }
- else
- {
- /* So TMPL_DIE is a DIE representing a
- a generic generic template parameter, a.k.a template template
- parameter in C++ and arg is a template. */
- /* The DW_AT_GNU_template_name attribute of the DIE must be set
- to the name of the argument. */
- name = dwarf2_name (TYPE_P (arg) ? TYPE_NAME (arg) : arg, 1);
- if (name)
- add_AT_string (tmpl_die, DW_AT_GNU_template_name, name);
- }
- if (TREE_CODE (parm) == PARM_DECL)
- /* So PARM is a non-type generic parameter.
- DWARF3 5.6.8 says we must set a DW_AT_const_value child
- attribute of TMPL_DIE which value represents the value
- of ARG.
- We must be careful here:
- The value of ARG might reference some function decls.
- We might currently be emitting debug info for a generic
- type and types are emitted before function decls, we don't
- know if the function decls referenced by ARG will actually be
- emitted after cgraph computations.
- So must defer the generation of the DW_AT_const_value to
- after cgraph is ready. */
- append_entry_to_tmpl_value_parm_die_table (tmpl_die, arg);
- }
- return tmpl_die;
- }
- /* Generate and return a DW_TAG_GNU_template_parameter_pack DIE representing.
- PARM_PACK must be a template parameter pack. The returned DIE
- will be child DIE of PARENT_DIE. */
- static dw_die_ref
- template_parameter_pack_die (tree parm_pack,
- tree parm_pack_args,
- dw_die_ref parent_die)
- {
- dw_die_ref die;
- int j;
- gcc_assert (parent_die && parm_pack);
- die = new_die (DW_TAG_GNU_template_parameter_pack, parent_die, parm_pack);
- add_name_and_src_coords_attributes (die, parm_pack);
- for (j = 0; j < TREE_VEC_LENGTH (parm_pack_args); j++)
- generic_parameter_die (parm_pack,
- TREE_VEC_ELT (parm_pack_args, j),
- false /* Don't emit DW_AT_name */,
- die);
- return die;
- }
- /* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
- an enumerated type. */
- static inline int
- type_is_enum (const_tree type)
- {
- return TREE_CODE (type) == ENUMERAL_TYPE;
- }
- /* Return the DBX register number described by a given RTL node. */
- static unsigned int
- dbx_reg_number (const_rtx rtl)
- {
- unsigned regno = REGNO (rtl);
- gcc_assert (regno < FIRST_PSEUDO_REGISTER);
- #ifdef LEAF_REG_REMAP
- if (crtl->uses_only_leaf_regs)
- {
- int leaf_reg = LEAF_REG_REMAP (regno);
- if (leaf_reg != -1)
- regno = (unsigned) leaf_reg;
- }
- #endif
- regno = DBX_REGISTER_NUMBER (regno);
- gcc_assert (regno != INVALID_REGNUM);
- return regno;
- }
- /* Optionally add a DW_OP_piece term to a location description expression.
- DW_OP_piece is only added if the location description expression already
- doesn't end with DW_OP_piece. */
- static void
- add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size)
- {
- dw_loc_descr_ref loc;
- if (*list_head != NULL)
- {
- /* Find the end of the chain. */
- for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
- ;
- if (loc->dw_loc_opc != DW_OP_piece)
- loc->dw_loc_next = new_loc_descr (DW_OP_piece, size, 0);
- }
- }
- /* Return a location descriptor that designates a machine register or
- zero if there is none. */
- static dw_loc_descr_ref
- reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
- {
- rtx regs;
- if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
- return 0;
- /* We only use "frame base" when we're sure we're talking about the
- post-prologue local stack frame. We do this by *not* running
- register elimination until this point, and recognizing the special
- argument pointer and soft frame pointer rtx's.
- Use DW_OP_fbreg offset DW_OP_stack_value in this case. */
- if ((rtl == arg_pointer_rtx || rtl == frame_pointer_rtx)
- && eliminate_regs (rtl, VOIDmode, NULL_RTX) != rtl)
- {
- dw_loc_descr_ref result = NULL;
- if (dwarf_version >= 4 || !dwarf_strict)
- {
- result = mem_loc_descriptor (rtl, GET_MODE (rtl), VOIDmode,
- initialized);
- if (result)
- add_loc_descr (&result,
- new_loc_descr (DW_OP_stack_value, 0, 0));
- }
- return result;
- }
- regs = targetm.dwarf_register_span (rtl);
- if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
- return multiple_reg_loc_descriptor (rtl, regs, initialized);
- else
- {
- unsigned int dbx_regnum = dbx_reg_number (rtl);
- if (dbx_regnum == IGNORED_DWARF_REGNUM)
- return 0;
- return one_reg_loc_descriptor (dbx_regnum, initialized);
- }
- }
- /* Return a location descriptor that designates a machine register for
- a given hard register number. */
- static dw_loc_descr_ref
- one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized)
- {
- dw_loc_descr_ref reg_loc_descr;
- if (regno <= 31)
- reg_loc_descr
- = new_loc_descr ((enum dwarf_location_atom) (DW_OP_reg0 + regno), 0, 0);
- else
- reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0);
- if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
- add_loc_descr (®_loc_descr, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
- return reg_loc_descr;
- }
- /* Given an RTL of a register, return a location descriptor that
- designates a value that spans more than one register. */
- static dw_loc_descr_ref
- multiple_reg_loc_descriptor (rtx rtl, rtx regs,
- enum var_init_status initialized)
- {
- int size, i;
- dw_loc_descr_ref loc_result = NULL;
- /* Simple, contiguous registers. */
- if (regs == NULL_RTX)
- {
- unsigned reg = REGNO (rtl);
- int nregs;
- #ifdef LEAF_REG_REMAP
- if (crtl->uses_only_leaf_regs)
- {
- int leaf_reg = LEAF_REG_REMAP (reg);
- if (leaf_reg != -1)
- reg = (unsigned) leaf_reg;
- }
- #endif
- gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
- nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
- size = GET_MODE_SIZE (GET_MODE (rtl)) / nregs;
- loc_result = NULL;
- while (nregs--)
- {
- dw_loc_descr_ref t;
- t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg),
- VAR_INIT_STATUS_INITIALIZED);
- add_loc_descr (&loc_result, t);
- add_loc_descr_op_piece (&loc_result, size);
- ++reg;
- }
- return loc_result;
- }
- /* Now onto stupid register sets in non contiguous locations. */
- gcc_assert (GET_CODE (regs) == PARALLEL);
- size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
- loc_result = NULL;
- for (i = 0; i < XVECLEN (regs, 0); ++i)
- {
- dw_loc_descr_ref t;
- t = one_reg_loc_descriptor (dbx_reg_number (XVECEXP (regs, 0, i)),
- VAR_INIT_STATUS_INITIALIZED);
- add_loc_descr (&loc_result, t);
- add_loc_descr_op_piece (&loc_result, size);
- }
- if (loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
- add_loc_descr (&loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
- return loc_result;
- }
- static unsigned long size_of_int_loc_descriptor (HOST_WIDE_INT);
- /* Return a location descriptor that designates a constant i,
- as a compound operation from constant (i >> shift), constant shift
- and DW_OP_shl. */
- static dw_loc_descr_ref
- int_shift_loc_descriptor (HOST_WIDE_INT i, int shift)
- {
- dw_loc_descr_ref ret = int_loc_descriptor (i >> shift);
- add_loc_descr (&ret, int_loc_descriptor (shift));
- add_loc_descr (&ret, new_loc_descr (DW_OP_shl, 0, 0));
- return ret;
- }
- /* Return a location descriptor that designates a constant. */
- static dw_loc_descr_ref
- int_loc_descriptor (HOST_WIDE_INT i)
- {
- enum dwarf_location_atom op;
- /* Pick the smallest representation of a constant, rather than just
- defaulting to the LEB encoding. */
- if (i >= 0)
- {
- int clz = clz_hwi (i);
- int ctz = ctz_hwi (i);
- if (i <= 31)
- op = (enum dwarf_location_atom) (DW_OP_lit0 + i);
- else if (i <= 0xff)
- op = DW_OP_const1u;
- else if (i <= 0xffff)
- op = DW_OP_const2u;
- else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 5
- && clz + 5 + 255 >= HOST_BITS_PER_WIDE_INT)
- /* DW_OP_litX DW_OP_litY DW_OP_shl takes just 3 bytes and
- DW_OP_litX DW_OP_const1u Y DW_OP_shl takes just 4 bytes,
- while DW_OP_const4u is 5 bytes. */
- return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 5);
- else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
- && clz + 8 + 31 >= HOST_BITS_PER_WIDE_INT)
- /* DW_OP_const1u X DW_OP_litY DW_OP_shl takes just 4 bytes,
- while DW_OP_const4u is 5 bytes. */
- return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 8);
- else if (HOST_BITS_PER_WIDE_INT == 32 || i <= 0xffffffff)
- op = DW_OP_const4u;
- else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
- && clz + 8 + 255 >= HOST_BITS_PER_WIDE_INT)
- /* DW_OP_const1u X DW_OP_const1u Y DW_OP_shl takes just 5 bytes,
- while DW_OP_constu of constant >= 0x100000000 takes at least
- 6 bytes. */
- return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 8);
- else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 16
- && clz + 16 + (size_of_uleb128 (i) > 5 ? 255 : 31)
- >= HOST_BITS_PER_WIDE_INT)
- /* DW_OP_const2u X DW_OP_litY DW_OP_shl takes just 5 bytes,
- DW_OP_const2u X DW_OP_const1u Y DW_OP_shl takes 6 bytes,
- while DW_OP_constu takes in this case at least 6 bytes. */
- return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 16);
- else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 32
- && clz + 32 + 31 >= HOST_BITS_PER_WIDE_INT
- && size_of_uleb128 (i) > 6)
- /* DW_OP_const4u X DW_OP_litY DW_OP_shl takes just 7 bytes. */
- return int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT - clz - 32);
- else
- op = DW_OP_constu;
- }
- else
- {
- if (i >= -0x80)
- op = DW_OP_const1s;
- else if (i >= -0x8000)
- op = DW_OP_const2s;
- else if (HOST_BITS_PER_WIDE_INT == 32 || i >= -0x80000000)
- {
- if (size_of_int_loc_descriptor (i) < 5)
- {
- dw_loc_descr_ref ret = int_loc_descriptor (-i);
- add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
- return ret;
- }
- op = DW_OP_const4s;
- }
- else
- {
- if (size_of_int_loc_descriptor (i)
- < (unsigned long) 1 + size_of_sleb128 (i))
- {
- dw_loc_descr_ref ret = int_loc_descriptor (-i);
- add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
- return ret;
- }
- op = DW_OP_consts;
- }
- }
- return new_loc_descr (op, i, 0);
- }
- /* Return size_of_locs (int_shift_loc_descriptor (i, shift))
- without actually allocating it. */
- static unsigned long
- size_of_int_shift_loc_descriptor (HOST_WIDE_INT i, int shift)
- {
- return size_of_int_loc_descriptor (i >> shift)
- + size_of_int_loc_descriptor (shift)
- + 1;
- }
- /* Return size_of_locs (int_loc_descriptor (i)) without
- actually allocating it. */
- static unsigned long
- size_of_int_loc_descriptor (HOST_WIDE_INT i)
- {
- unsigned long s;
- if (i >= 0)
- {
- int clz, ctz;
- if (i <= 31)
- return 1;
- else if (i <= 0xff)
- return 2;
- else if (i <= 0xffff)
- return 3;
- clz = clz_hwi (i);
- ctz = ctz_hwi (i);
- if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 5
- && clz + 5 + 255 >= HOST_BITS_PER_WIDE_INT)
- return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
- - clz - 5);
- else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
- && clz + 8 + 31 >= HOST_BITS_PER_WIDE_INT)
- return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
- - clz - 8);
- else if (HOST_BITS_PER_WIDE_INT == 32 || i <= 0xffffffff)
- return 5;
- s = size_of_uleb128 ((unsigned HOST_WIDE_INT) i);
- if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 8
- && clz + 8 + 255 >= HOST_BITS_PER_WIDE_INT)
- return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
- - clz - 8);
- else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 16
- && clz + 16 + (s > 5 ? 255 : 31) >= HOST_BITS_PER_WIDE_INT)
- return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
- - clz - 16);
- else if (clz + ctz >= HOST_BITS_PER_WIDE_INT - 32
- && clz + 32 + 31 >= HOST_BITS_PER_WIDE_INT
- && s > 6)
- return size_of_int_shift_loc_descriptor (i, HOST_BITS_PER_WIDE_INT
- - clz - 32);
- else
- return 1 + s;
- }
- else
- {
- if (i >= -0x80)
- return 2;
- else if (i >= -0x8000)
- return 3;
- else if (HOST_BITS_PER_WIDE_INT == 32 || i >= -0x80000000)
- {
- if (-(unsigned HOST_WIDE_INT) i != (unsigned HOST_WIDE_INT) i)
- {
- s = size_of_int_loc_descriptor (-i) + 1;
- if (s < 5)
- return s;
- }
- return 5;
- }
- else
- {
- unsigned long r = 1 + size_of_sleb128 (i);
- if (-(unsigned HOST_WIDE_INT) i != (unsigned HOST_WIDE_INT) i)
- {
- s = size_of_int_loc_descriptor (-i) + 1;
- if (s < r)
- return s;
- }
- return r;
- }
- }
- }
- /* Return loc description representing "address" of integer value.
- This can appear only as toplevel expression. */
- static dw_loc_descr_ref
- address_of_int_loc_descriptor (int size, HOST_WIDE_INT i)
- {
- int litsize;
- dw_loc_descr_ref loc_result = NULL;
- if (!(dwarf_version >= 4 || !dwarf_strict))
- return NULL;
- litsize = size_of_int_loc_descriptor (i);
- /* Determine if DW_OP_stack_value or DW_OP_implicit_value
- is more compact. For DW_OP_stack_value we need:
- litsize + 1 (DW_OP_stack_value)
- and for DW_OP_implicit_value:
- 1 (DW_OP_implicit_value) + 1 (length) + size. */
- if ((int) DWARF2_ADDR_SIZE >= size && litsize + 1 <= 1 + 1 + size)
- {
- loc_result = int_loc_descriptor (i);
- add_loc_descr (&loc_result,
- new_loc_descr (DW_OP_stack_value, 0, 0));
- return loc_result;
- }
- loc_result = new_loc_descr (DW_OP_implicit_value,
- size, 0);
- loc_result->dw_loc_oprnd2.val_class = dw_val_class_const;
- loc_result->dw_loc_oprnd2.v.val_int = i;
- return loc_result;
- }
- /* Return a location descriptor that designates a base+offset location. */
- static dw_loc_descr_ref
- based_loc_descr (rtx reg, HOST_WIDE_INT offset,
- enum var_init_status initialized)
- {
- unsigned int regno;
- dw_loc_descr_ref result;
- dw_fde_ref fde = cfun->fde;
- /* We only use "frame base" when we're sure we're talking about the
- post-prologue local stack frame. We do this by *not* running
- register elimination until this point, and recognizing the special
- argument pointer and soft frame pointer rtx's. */
- if (reg == arg_pointer_rtx || reg == frame_pointer_rtx)
- {
- rtx elim = (ira_use_lra_p
- ? lra_eliminate_regs (reg, VOIDmode, NULL_RTX)
- : eliminate_regs (reg, VOIDmode, NULL_RTX));
- if (elim != reg)
- {
- if (GET_CODE (elim) == PLUS)
- {
- offset += INTVAL (XEXP (elim, 1));
- elim = XEXP (elim, 0);
- }
- gcc_assert ((SUPPORTS_STACK_ALIGNMENT
- && (elim == hard_frame_pointer_rtx
- || elim == stack_pointer_rtx))
- || elim == (frame_pointer_needed
- ? hard_frame_pointer_rtx
- : stack_pointer_rtx));
- /* If drap register is used to align stack, use frame
- pointer + offset to access stack variables. If stack
- is aligned without drap, use stack pointer + offset to
- access stack variables. */
- if (crtl->stack_realign_tried
- && reg == frame_pointer_rtx)
- {
- int base_reg
- = DWARF_FRAME_REGNUM ((fde && fde->drap_reg != INVALID_REGNUM)
- ? HARD_FRAME_POINTER_REGNUM
- : REGNO (elim));
- return new_reg_loc_descr (base_reg, offset);
- }
- gcc_assert (frame_pointer_fb_offset_valid);
- offset += frame_pointer_fb_offset;
- return new_loc_descr (DW_OP_fbreg, offset, 0);
- }
- }
- regno = REGNO (reg);
- #ifdef LEAF_REG_REMAP
- if (crtl->uses_only_leaf_regs)
- {
- int leaf_reg = LEAF_REG_REMAP (regno);
- if (leaf_reg != -1)
- regno = (unsigned) leaf_reg;
- }
- #endif
- regno = DWARF_FRAME_REGNUM (regno);
- if (!optimize && fde
- && (fde->drap_reg == regno || fde->vdrap_reg == regno))
- {
- /* Use cfa+offset to represent the location of arguments passed
- on the stack when drap is used to align stack.
- Only do this when not optimizing, for optimized code var-tracking
- is supposed to track where the arguments live and the register
- used as vdrap or drap in some spot might be used for something
- else in other part of the routine. */
- return new_loc_descr (DW_OP_fbreg, offset, 0);
- }
- if (regno <= 31)
- result = new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + regno),
- offset, 0);
- else
- result = new_loc_descr (DW_OP_bregx, regno, offset);
- if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
- add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
- return result;
- }
- /* Return true if this RTL expression describes a base+offset calculation. */
- static inline int
- is_based_loc (const_rtx rtl)
- {
- return (GET_CODE (rtl) == PLUS
- && ((REG_P (XEXP (rtl, 0))
- && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
- && CONST_INT_P (XEXP (rtl, 1)))));
- }
- /* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0)
- failed. */
- static dw_loc_descr_ref
- tls_mem_loc_descriptor (rtx mem)
- {
- tree base;
- dw_loc_descr_ref loc_result;
- if (MEM_EXPR (mem) == NULL_TREE || !MEM_OFFSET_KNOWN_P (mem))
- return NULL;
- base = get_base_address (MEM_EXPR (mem));
- if (base == NULL
- || TREE_CODE (base) != VAR_DECL
- || !DECL_THREAD_LOCAL_P (base))
- return NULL;
- loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1, NULL);
- if (loc_result == NULL)
- return NULL;
- if (MEM_OFFSET (mem))
- loc_descr_plus_const (&loc_result, MEM_OFFSET (mem));
- return loc_result;
- }
- /* Output debug info about reason why we failed to expand expression as dwarf
- expression. */
- static void
- expansion_failed (tree expr, rtx rtl, char const *reason)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Failed to expand as dwarf: ");
- if (expr)
- print_generic_expr (dump_file, expr, dump_flags);
- if (rtl)
- {
- fprintf (dump_file, "\n");
- print_rtl (dump_file, rtl);
- }
- fprintf (dump_file, "\nReason: %s\n", reason);
- }
- }
- /* Helper function for const_ok_for_output. */
- static bool
- const_ok_for_output_1 (rtx rtl)
- {
- if (GET_CODE (rtl) == UNSPEC)
- {
- /* If delegitimize_address couldn't do anything with the UNSPEC, assume
- we can't express it in the debug info. */
- #ifdef ENABLE_CHECKING
- /* Don't complain about TLS UNSPECs, those are just too hard to
- delegitimize. Note this could be a non-decl SYMBOL_REF such as
- one in a constant pool entry, so testing SYMBOL_REF_TLS_MODEL
- rather than DECL_THREAD_LOCAL_P is not just an optimization. */
- if (XVECLEN (rtl, 0) == 0
- || GET_CODE (XVECEXP (rtl, 0, 0)) != SYMBOL_REF
- || SYMBOL_REF_TLS_MODEL (XVECEXP (rtl, 0, 0)) == TLS_MODEL_NONE)
- inform (current_function_decl
- ? DECL_SOURCE_LOCATION (current_function_decl)
- : UNKNOWN_LOCATION,
- #if NUM_UNSPEC_VALUES > 0
- "non-delegitimized UNSPEC %s (%d) found in variable location",
- ((XINT (rtl, 1) >= 0 && XINT (rtl, 1) < NUM_UNSPEC_VALUES)
- ? unspec_strings[XINT (rtl, 1)] : "unknown"),
- XINT (rtl, 1));
- #else
- "non-delegitimized UNSPEC %d found in variable location",
- XINT (rtl, 1));
- #endif
- #endif
- expansion_failed (NULL_TREE, rtl,
- "UNSPEC hasn't been delegitimized.\n");
- return false;
- }
- if (targetm.const_not_ok_for_debug_p (rtl))
- {
- expansion_failed (NULL_TREE, rtl,
- "Expression rejected for debug by the backend.\n");
- return false;
- }
- /* FIXME: Refer to PR60655. It is possible for simplification
- of rtl expressions in var tracking to produce such expressions.
- We should really identify / validate expressions
- enclosed in CONST that can be handled by assemblers on various
- targets and only handle legitimate cases here. */
- if (GET_CODE (rtl) != SYMBOL_REF)
- {
- if (GET_CODE (rtl) == NOT)
- return false;
- return true;
- }
- if (CONSTANT_POOL_ADDRESS_P (rtl))
- {
- bool marked;
- get_pool_constant_mark (rtl, &marked);
- /* If all references to this pool constant were optimized away,
- it was not output and thus we can't represent it. */
- if (!marked)
- {
- expansion_failed (NULL_TREE, rtl,
- "Constant was removed from constant pool.\n");
- return false;
- }
- }
- if (SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
- return false;
- /* Avoid references to external symbols in debug info, on several targets
- the linker might even refuse to link when linking a shared library,
- and in many other cases the relocations for .debug_info/.debug_loc are
- dropped, so the address becomes zero anyway. Hidden symbols, guaranteed
- to be defined within the same shared library or executable are fine. */
- if (SYMBOL_REF_EXTERNAL_P (rtl))
- {
- tree decl = SYMBOL_REF_DECL (rtl);
- if (decl == NULL || !targetm.binds_local_p (decl))
- {
- expansion_failed (NULL_TREE, rtl,
- "Symbol not defined in current TU.\n");
- return false;
- }
- }
- return true;
- }
- /* Return true if constant RTL can be emitted in DW_OP_addr or
- DW_AT_const_value. TLS SYMBOL_REFs, external SYMBOL_REFs or
- non-marked constant pool SYMBOL_REFs can't be referenced in it. */
- static bool
- const_ok_for_output (rtx rtl)
- {
- if (GET_CODE (rtl) == SYMBOL_REF)
- return const_ok_for_output_1 (rtl);
- if (GET_CODE (rtl) == CONST)
- {
- subrtx_var_iterator::array_type array;
- FOR_EACH_SUBRTX_VAR (iter, array, XEXP (rtl, 0), ALL)
- if (!const_ok_for_output_1 (*iter))
- return false;
- return true;
- }
- return true;
- }
- /* Return a reference to DW_TAG_base_type corresponding to MODE and UNSIGNEDP
- if possible, NULL otherwise. */
- static dw_die_ref
- base_type_for_mode (machine_mode mode, bool unsignedp)
- {
- dw_die_ref type_die;
- tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
- if (type == NULL)
- return NULL;
- switch (TREE_CODE (type))
- {
- case INTEGER_TYPE:
- case REAL_TYPE:
- break;
- default:
- return NULL;
- }
- type_die = lookup_type_die (type);
- if (!type_die)
- type_die = modified_type_die (type, TYPE_UNQUALIFIED, comp_unit_die ());
- if (type_die == NULL || type_die->die_tag != DW_TAG_base_type)
- return NULL;
- return type_die;
- }
- /* For OP descriptor assumed to be in unsigned MODE, convert it to a unsigned
- type matching MODE, or, if MODE is narrower than or as wide as
- DWARF2_ADDR_SIZE, untyped. Return NULL if the conversion is not
- possible. */
- static dw_loc_descr_ref
- convert_descriptor_to_mode (machine_mode mode, dw_loc_descr_ref op)
- {
- machine_mode outer_mode = mode;
- dw_die_ref type_die;
- dw_loc_descr_ref cvt;
- if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE)
- {
- add_loc_descr (&op, new_loc_descr (DW_OP_GNU_convert, 0, 0));
- return op;
- }
- type_die = base_type_for_mode (outer_mode, 1);
- if (type_die == NULL)
- return NULL;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&op, cvt);
- return op;
- }
- /* Return location descriptor for comparison OP with operands OP0 and OP1. */
- static dw_loc_descr_ref
- compare_loc_descriptor (enum dwarf_location_atom op, dw_loc_descr_ref op0,
- dw_loc_descr_ref op1)
- {
- dw_loc_descr_ref ret = op0;
- add_loc_descr (&ret, op1);
- add_loc_descr (&ret, new_loc_descr (op, 0, 0));
- if (STORE_FLAG_VALUE != 1)
- {
- add_loc_descr (&ret, int_loc_descriptor (STORE_FLAG_VALUE));
- add_loc_descr (&ret, new_loc_descr (DW_OP_mul, 0, 0));
- }
- return ret;
- }
- /* Return location descriptor for signed comparison OP RTL. */
- static dw_loc_descr_ref
- scompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl,
- machine_mode mem_mode)
- {
- machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
- dw_loc_descr_ref op0, op1;
- int shift;
- if (op_mode == VOIDmode)
- op_mode = GET_MODE (XEXP (rtl, 1));
- if (op_mode == VOIDmode)
- return NULL;
- if (dwarf_strict
- && (GET_MODE_CLASS (op_mode) != MODE_INT
- || GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE))
- return NULL;
- op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- op1 = mem_loc_descriptor (XEXP (rtl, 1), op_mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == NULL || op1 == NULL)
- return NULL;
- if (GET_MODE_CLASS (op_mode) != MODE_INT
- || GET_MODE_SIZE (op_mode) == DWARF2_ADDR_SIZE)
- return compare_loc_descriptor (op, op0, op1);
- if (GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE)
- {
- dw_die_ref type_die = base_type_for_mode (op_mode, 0);
- dw_loc_descr_ref cvt;
- if (type_die == NULL)
- return NULL;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&op0, cvt);
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&op1, cvt);
- return compare_loc_descriptor (op, op0, op1);
- }
- shift = (DWARF2_ADDR_SIZE - GET_MODE_SIZE (op_mode)) * BITS_PER_UNIT;
- /* For eq/ne, if the operands are known to be zero-extended,
- there is no need to do the fancy shifting up. */
- if (op == DW_OP_eq || op == DW_OP_ne)
- {
- dw_loc_descr_ref last0, last1;
- for (last0 = op0; last0->dw_loc_next != NULL; last0 = last0->dw_loc_next)
- ;
- for (last1 = op1; last1->dw_loc_next != NULL; last1 = last1->dw_loc_next)
- ;
- /* deref_size zero extends, and for constants we can check
- whether they are zero extended or not. */
- if (((last0->dw_loc_opc == DW_OP_deref_size
- && last0->dw_loc_oprnd1.v.val_int <= GET_MODE_SIZE (op_mode))
- || (CONST_INT_P (XEXP (rtl, 0))
- && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 0))
- == (INTVAL (XEXP (rtl, 0)) & GET_MODE_MASK (op_mode))))
- && ((last1->dw_loc_opc == DW_OP_deref_size
- && last1->dw_loc_oprnd1.v.val_int <= GET_MODE_SIZE (op_mode))
- || (CONST_INT_P (XEXP (rtl, 1))
- && (unsigned HOST_WIDE_INT) INTVAL (XEXP (rtl, 1))
- == (INTVAL (XEXP (rtl, 1)) & GET_MODE_MASK (op_mode)))))
- return compare_loc_descriptor (op, op0, op1);
- /* EQ/NE comparison against constant in narrower type than
- DWARF2_ADDR_SIZE can be performed either as
- DW_OP_const1u <shift> DW_OP_shl DW_OP_const* <cst << shift>
- DW_OP_{eq,ne}
- or
- DW_OP_const*u <mode_mask> DW_OP_and DW_OP_const* <cst & mode_mask>
- DW_OP_{eq,ne}. Pick whatever is shorter. */
- if (CONST_INT_P (XEXP (rtl, 1))
- && GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT
- && (size_of_int_loc_descriptor (shift) + 1
- + size_of_int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift)
- >= size_of_int_loc_descriptor (GET_MODE_MASK (op_mode)) + 1
- + size_of_int_loc_descriptor (INTVAL (XEXP (rtl, 1))
- & GET_MODE_MASK (op_mode))))
- {
- add_loc_descr (&op0, int_loc_descriptor (GET_MODE_MASK (op_mode)));
- add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
- op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1))
- & GET_MODE_MASK (op_mode));
- return compare_loc_descriptor (op, op0, op1);
- }
- }
- add_loc_descr (&op0, int_loc_descriptor (shift));
- add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
- if (CONST_INT_P (XEXP (rtl, 1)))
- op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) << shift);
- else
- {
- add_loc_descr (&op1, int_loc_descriptor (shift));
- add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
- }
- return compare_loc_descriptor (op, op0, op1);
- }
- /* Return location descriptor for unsigned comparison OP RTL. */
- static dw_loc_descr_ref
- ucompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl,
- machine_mode mem_mode)
- {
- machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
- dw_loc_descr_ref op0, op1;
- if (op_mode == VOIDmode)
- op_mode = GET_MODE (XEXP (rtl, 1));
- if (op_mode == VOIDmode)
- return NULL;
- if (GET_MODE_CLASS (op_mode) != MODE_INT)
- return NULL;
- if (dwarf_strict && GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE)
- return NULL;
- op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- op1 = mem_loc_descriptor (XEXP (rtl, 1), op_mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == NULL || op1 == NULL)
- return NULL;
- if (GET_MODE_SIZE (op_mode) < DWARF2_ADDR_SIZE)
- {
- HOST_WIDE_INT mask = GET_MODE_MASK (op_mode);
- dw_loc_descr_ref last0, last1;
- for (last0 = op0; last0->dw_loc_next != NULL; last0 = last0->dw_loc_next)
- ;
- for (last1 = op1; last1->dw_loc_next != NULL; last1 = last1->dw_loc_next)
- ;
- if (CONST_INT_P (XEXP (rtl, 0)))
- op0 = int_loc_descriptor (INTVAL (XEXP (rtl, 0)) & mask);
- /* deref_size zero extends, so no need to mask it again. */
- else if (last0->dw_loc_opc != DW_OP_deref_size
- || last0->dw_loc_oprnd1.v.val_int > GET_MODE_SIZE (op_mode))
- {
- add_loc_descr (&op0, int_loc_descriptor (mask));
- add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
- }
- if (CONST_INT_P (XEXP (rtl, 1)))
- op1 = int_loc_descriptor (INTVAL (XEXP (rtl, 1)) & mask);
- /* deref_size zero extends, so no need to mask it again. */
- else if (last1->dw_loc_opc != DW_OP_deref_size
- || last1->dw_loc_oprnd1.v.val_int > GET_MODE_SIZE (op_mode))
- {
- add_loc_descr (&op1, int_loc_descriptor (mask));
- add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
- }
- }
- else if (GET_MODE_SIZE (op_mode) == DWARF2_ADDR_SIZE)
- {
- HOST_WIDE_INT bias = 1;
- bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
- add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
- if (CONST_INT_P (XEXP (rtl, 1)))
- op1 = int_loc_descriptor ((unsigned HOST_WIDE_INT) bias
- + INTVAL (XEXP (rtl, 1)));
- else
- add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst,
- bias, 0));
- }
- return compare_loc_descriptor (op, op0, op1);
- }
- /* Return location descriptor for {U,S}{MIN,MAX}. */
- static dw_loc_descr_ref
- minmax_loc_descriptor (rtx rtl, machine_mode mode,
- machine_mode mem_mode)
- {
- enum dwarf_location_atom op;
- dw_loc_descr_ref op0, op1, ret;
- dw_loc_descr_ref bra_node, drop_node;
- if (dwarf_strict
- && (GET_MODE_CLASS (mode) != MODE_INT
- || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE))
- return NULL;
- op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == NULL || op1 == NULL)
- return NULL;
- add_loc_descr (&op0, new_loc_descr (DW_OP_dup, 0, 0));
- add_loc_descr (&op1, new_loc_descr (DW_OP_swap, 0, 0));
- add_loc_descr (&op1, new_loc_descr (DW_OP_over, 0, 0));
- if (GET_CODE (rtl) == UMIN || GET_CODE (rtl) == UMAX)
- {
- if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
- {
- HOST_WIDE_INT mask = GET_MODE_MASK (mode);
- add_loc_descr (&op0, int_loc_descriptor (mask));
- add_loc_descr (&op0, new_loc_descr (DW_OP_and, 0, 0));
- add_loc_descr (&op1, int_loc_descriptor (mask));
- add_loc_descr (&op1, new_loc_descr (DW_OP_and, 0, 0));
- }
- else if (GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE)
- {
- HOST_WIDE_INT bias = 1;
- bias <<= (DWARF2_ADDR_SIZE * BITS_PER_UNIT - 1);
- add_loc_descr (&op0, new_loc_descr (DW_OP_plus_uconst, bias, 0));
- add_loc_descr (&op1, new_loc_descr (DW_OP_plus_uconst, bias, 0));
- }
- }
- else if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
- {
- int shift = (DWARF2_ADDR_SIZE - GET_MODE_SIZE (mode)) * BITS_PER_UNIT;
- add_loc_descr (&op0, int_loc_descriptor (shift));
- add_loc_descr (&op0, new_loc_descr (DW_OP_shl, 0, 0));
- add_loc_descr (&op1, int_loc_descriptor (shift));
- add_loc_descr (&op1, new_loc_descr (DW_OP_shl, 0, 0));
- }
- else if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)
- {
- dw_die_ref type_die = base_type_for_mode (mode, 0);
- dw_loc_descr_ref cvt;
- if (type_die == NULL)
- return NULL;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&op0, cvt);
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&op1, cvt);
- }
- if (GET_CODE (rtl) == SMIN || GET_CODE (rtl) == UMIN)
- op = DW_OP_lt;
- else
- op = DW_OP_gt;
- ret = op0;
- add_loc_descr (&ret, op1);
- add_loc_descr (&ret, new_loc_descr (op, 0, 0));
- bra_node = new_loc_descr (DW_OP_bra, 0, 0);
- add_loc_descr (&ret, bra_node);
- add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
- drop_node = new_loc_descr (DW_OP_drop, 0, 0);
- add_loc_descr (&ret, drop_node);
- bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
- bra_node->dw_loc_oprnd1.v.val_loc = drop_node;
- if ((GET_CODE (rtl) == SMIN || GET_CODE (rtl) == SMAX)
- && GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)
- ret = convert_descriptor_to_mode (mode, ret);
- return ret;
- }
- /* Helper function for mem_loc_descriptor. Perform OP binary op,
- but after converting arguments to type_die, afterwards
- convert back to unsigned. */
- static dw_loc_descr_ref
- typed_binop (enum dwarf_location_atom op, rtx rtl, dw_die_ref type_die,
- machine_mode mode, machine_mode mem_mode)
- {
- dw_loc_descr_ref cvt, op0, op1;
- if (type_die == NULL)
- return NULL;
- op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == NULL || op1 == NULL)
- return NULL;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&op0, cvt);
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&op1, cvt);
- add_loc_descr (&op0, op1);
- add_loc_descr (&op0, new_loc_descr (op, 0, 0));
- return convert_descriptor_to_mode (mode, op0);
- }
- /* CLZ (where constV is CLZ_DEFINED_VALUE_AT_ZERO computed value,
- const0 is DW_OP_lit0 or corresponding typed constant,
- const1 is DW_OP_lit1 or corresponding typed constant
- and constMSB is constant with just the MSB bit set
- for the mode):
- DW_OP_dup DW_OP_bra <L1> DW_OP_drop constV DW_OP_skip <L4>
- L1: const0 DW_OP_swap
- L2: DW_OP_dup constMSB DW_OP_and DW_OP_bra <L3> const1 DW_OP_shl
- DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
- L3: DW_OP_drop
- L4: DW_OP_nop
- CTZ is similar:
- DW_OP_dup DW_OP_bra <L1> DW_OP_drop constV DW_OP_skip <L4>
- L1: const0 DW_OP_swap
- L2: DW_OP_dup const1 DW_OP_and DW_OP_bra <L3> const1 DW_OP_shr
- DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
- L3: DW_OP_drop
- L4: DW_OP_nop
- FFS is similar:
- DW_OP_dup DW_OP_bra <L1> DW_OP_drop const0 DW_OP_skip <L4>
- L1: const1 DW_OP_swap
- L2: DW_OP_dup const1 DW_OP_and DW_OP_bra <L3> const1 DW_OP_shr
- DW_OP_swap DW_OP_plus_uconst <1> DW_OP_swap DW_OP_skip <L2>
- L3: DW_OP_drop
- L4: DW_OP_nop */
- static dw_loc_descr_ref
- clz_loc_descriptor (rtx rtl, machine_mode mode,
- machine_mode mem_mode)
- {
- dw_loc_descr_ref op0, ret, tmp;
- HOST_WIDE_INT valv;
- dw_loc_descr_ref l1jump, l1label;
- dw_loc_descr_ref l2jump, l2label;
- dw_loc_descr_ref l3jump, l3label;
- dw_loc_descr_ref l4jump, l4label;
- rtx msb;
- if (GET_MODE_CLASS (mode) != MODE_INT
- || GET_MODE (XEXP (rtl, 0)) != mode)
- return NULL;
- op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == NULL)
- return NULL;
- ret = op0;
- if (GET_CODE (rtl) == CLZ)
- {
- if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, valv))
- valv = GET_MODE_BITSIZE (mode);
- }
- else if (GET_CODE (rtl) == FFS)
- valv = 0;
- else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, valv))
- valv = GET_MODE_BITSIZE (mode);
- add_loc_descr (&ret, new_loc_descr (DW_OP_dup, 0, 0));
- l1jump = new_loc_descr (DW_OP_bra, 0, 0);
- add_loc_descr (&ret, l1jump);
- add_loc_descr (&ret, new_loc_descr (DW_OP_drop, 0, 0));
- tmp = mem_loc_descriptor (GEN_INT (valv), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tmp == NULL)
- return NULL;
- add_loc_descr (&ret, tmp);
- l4jump = new_loc_descr (DW_OP_skip, 0, 0);
- add_loc_descr (&ret, l4jump);
- l1label = mem_loc_descriptor (GET_CODE (rtl) == FFS
- ? const1_rtx : const0_rtx,
- mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (l1label == NULL)
- return NULL;
- add_loc_descr (&ret, l1label);
- add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
- l2label = new_loc_descr (DW_OP_dup, 0, 0);
- add_loc_descr (&ret, l2label);
- if (GET_CODE (rtl) != CLZ)
- msb = const1_rtx;
- else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
- msb = GEN_INT ((unsigned HOST_WIDE_INT) 1
- << (GET_MODE_BITSIZE (mode) - 1));
- else
- msb = immed_wide_int_const
- (wi::set_bit_in_zero (GET_MODE_PRECISION (mode) - 1,
- GET_MODE_PRECISION (mode)), mode);
- if (GET_CODE (msb) == CONST_INT && INTVAL (msb) < 0)
- tmp = new_loc_descr (HOST_BITS_PER_WIDE_INT == 32
- ? DW_OP_const4u : HOST_BITS_PER_WIDE_INT == 64
- ? DW_OP_const8u : DW_OP_constu, INTVAL (msb), 0);
- else
- tmp = mem_loc_descriptor (msb, mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tmp == NULL)
- return NULL;
- add_loc_descr (&ret, tmp);
- add_loc_descr (&ret, new_loc_descr (DW_OP_and, 0, 0));
- l3jump = new_loc_descr (DW_OP_bra, 0, 0);
- add_loc_descr (&ret, l3jump);
- tmp = mem_loc_descriptor (const1_rtx, mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tmp == NULL)
- return NULL;
- add_loc_descr (&ret, tmp);
- add_loc_descr (&ret, new_loc_descr (GET_CODE (rtl) == CLZ
- ? DW_OP_shl : DW_OP_shr, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst, 1, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
- l2jump = new_loc_descr (DW_OP_skip, 0, 0);
- add_loc_descr (&ret, l2jump);
- l3label = new_loc_descr (DW_OP_drop, 0, 0);
- add_loc_descr (&ret, l3label);
- l4label = new_loc_descr (DW_OP_nop, 0, 0);
- add_loc_descr (&ret, l4label);
- l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
- l1jump->dw_loc_oprnd1.v.val_loc = l1label;
- l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
- l2jump->dw_loc_oprnd1.v.val_loc = l2label;
- l3jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
- l3jump->dw_loc_oprnd1.v.val_loc = l3label;
- l4jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
- l4jump->dw_loc_oprnd1.v.val_loc = l4label;
- return ret;
- }
- /* POPCOUNT (const0 is DW_OP_lit0 or corresponding typed constant,
- const1 is DW_OP_lit1 or corresponding typed constant):
- const0 DW_OP_swap
- L1: DW_OP_dup DW_OP_bra <L2> DW_OP_dup DW_OP_rot const1 DW_OP_and
- DW_OP_plus DW_OP_swap const1 DW_OP_shr DW_OP_skip <L1>
- L2: DW_OP_drop
- PARITY is similar:
- L1: DW_OP_dup DW_OP_bra <L2> DW_OP_dup DW_OP_rot const1 DW_OP_and
- DW_OP_xor DW_OP_swap const1 DW_OP_shr DW_OP_skip <L1>
- L2: DW_OP_drop */
- static dw_loc_descr_ref
- popcount_loc_descriptor (rtx rtl, machine_mode mode,
- machine_mode mem_mode)
- {
- dw_loc_descr_ref op0, ret, tmp;
- dw_loc_descr_ref l1jump, l1label;
- dw_loc_descr_ref l2jump, l2label;
- if (GET_MODE_CLASS (mode) != MODE_INT
- || GET_MODE (XEXP (rtl, 0)) != mode)
- return NULL;
- op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == NULL)
- return NULL;
- ret = op0;
- tmp = mem_loc_descriptor (const0_rtx, mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tmp == NULL)
- return NULL;
- add_loc_descr (&ret, tmp);
- add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
- l1label = new_loc_descr (DW_OP_dup, 0, 0);
- add_loc_descr (&ret, l1label);
- l2jump = new_loc_descr (DW_OP_bra, 0, 0);
- add_loc_descr (&ret, l2jump);
- add_loc_descr (&ret, new_loc_descr (DW_OP_dup, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_rot, 0, 0));
- tmp = mem_loc_descriptor (const1_rtx, mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tmp == NULL)
- return NULL;
- add_loc_descr (&ret, tmp);
- add_loc_descr (&ret, new_loc_descr (DW_OP_and, 0, 0));
- add_loc_descr (&ret, new_loc_descr (GET_CODE (rtl) == POPCOUNT
- ? DW_OP_plus : DW_OP_xor, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
- tmp = mem_loc_descriptor (const1_rtx, mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- add_loc_descr (&ret, tmp);
- add_loc_descr (&ret, new_loc_descr (DW_OP_shr, 0, 0));
- l1jump = new_loc_descr (DW_OP_skip, 0, 0);
- add_loc_descr (&ret, l1jump);
- l2label = new_loc_descr (DW_OP_drop, 0, 0);
- add_loc_descr (&ret, l2label);
- l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
- l1jump->dw_loc_oprnd1.v.val_loc = l1label;
- l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
- l2jump->dw_loc_oprnd1.v.val_loc = l2label;
- return ret;
- }
- /* BSWAP (constS is initial shift count, either 56 or 24):
- constS const0
- L1: DW_OP_pick <2> constS DW_OP_pick <3> DW_OP_minus DW_OP_shr
- const255 DW_OP_and DW_OP_pick <2> DW_OP_shl DW_OP_or
- DW_OP_swap DW_OP_dup const0 DW_OP_eq DW_OP_bra <L2> const8
- DW_OP_minus DW_OP_swap DW_OP_skip <L1>
- L2: DW_OP_drop DW_OP_swap DW_OP_drop */
- static dw_loc_descr_ref
- bswap_loc_descriptor (rtx rtl, machine_mode mode,
- machine_mode mem_mode)
- {
- dw_loc_descr_ref op0, ret, tmp;
- dw_loc_descr_ref l1jump, l1label;
- dw_loc_descr_ref l2jump, l2label;
- if (GET_MODE_CLASS (mode) != MODE_INT
- || BITS_PER_UNIT != 8
- || (GET_MODE_BITSIZE (mode) != 32
- && GET_MODE_BITSIZE (mode) != 64))
- return NULL;
- op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == NULL)
- return NULL;
- ret = op0;
- tmp = mem_loc_descriptor (GEN_INT (GET_MODE_BITSIZE (mode) - 8),
- mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tmp == NULL)
- return NULL;
- add_loc_descr (&ret, tmp);
- tmp = mem_loc_descriptor (const0_rtx, mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tmp == NULL)
- return NULL;
- add_loc_descr (&ret, tmp);
- l1label = new_loc_descr (DW_OP_pick, 2, 0);
- add_loc_descr (&ret, l1label);
- tmp = mem_loc_descriptor (GEN_INT (GET_MODE_BITSIZE (mode) - 8),
- mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- add_loc_descr (&ret, tmp);
- add_loc_descr (&ret, new_loc_descr (DW_OP_pick, 3, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_minus, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_shr, 0, 0));
- tmp = mem_loc_descriptor (GEN_INT (255), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tmp == NULL)
- return NULL;
- add_loc_descr (&ret, tmp);
- add_loc_descr (&ret, new_loc_descr (DW_OP_and, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_pick, 2, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_shl, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_or, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_dup, 0, 0));
- tmp = mem_loc_descriptor (const0_rtx, mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- add_loc_descr (&ret, tmp);
- add_loc_descr (&ret, new_loc_descr (DW_OP_eq, 0, 0));
- l2jump = new_loc_descr (DW_OP_bra, 0, 0);
- add_loc_descr (&ret, l2jump);
- tmp = mem_loc_descriptor (GEN_INT (8), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- add_loc_descr (&ret, tmp);
- add_loc_descr (&ret, new_loc_descr (DW_OP_minus, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
- l1jump = new_loc_descr (DW_OP_skip, 0, 0);
- add_loc_descr (&ret, l1jump);
- l2label = new_loc_descr (DW_OP_drop, 0, 0);
- add_loc_descr (&ret, l2label);
- add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_drop, 0, 0));
- l1jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
- l1jump->dw_loc_oprnd1.v.val_loc = l1label;
- l2jump->dw_loc_oprnd1.val_class = dw_val_class_loc;
- l2jump->dw_loc_oprnd1.v.val_loc = l2label;
- return ret;
- }
- /* ROTATE (constMASK is mode mask, BITSIZE is bitsize of mode):
- DW_OP_over DW_OP_over DW_OP_shl [ constMASK DW_OP_and ] DW_OP_rot
- [ DW_OP_swap constMASK DW_OP_and DW_OP_swap ] DW_OP_neg
- DW_OP_plus_uconst <BITSIZE> DW_OP_shr DW_OP_or
- ROTATERT is similar:
- DW_OP_over DW_OP_over DW_OP_neg DW_OP_plus_uconst <BITSIZE>
- DW_OP_shl [ constMASK DW_OP_and ] DW_OP_rot
- [ DW_OP_swap constMASK DW_OP_and DW_OP_swap ] DW_OP_shr DW_OP_or */
- static dw_loc_descr_ref
- rotate_loc_descriptor (rtx rtl, machine_mode mode,
- machine_mode mem_mode)
- {
- rtx rtlop1 = XEXP (rtl, 1);
- dw_loc_descr_ref op0, op1, ret, mask[2] = { NULL, NULL };
- int i;
- if (GET_MODE_CLASS (mode) != MODE_INT)
- return NULL;
- if (GET_MODE (rtlop1) != VOIDmode
- && GET_MODE_BITSIZE (GET_MODE (rtlop1)) < GET_MODE_BITSIZE (mode))
- rtlop1 = gen_rtx_ZERO_EXTEND (mode, rtlop1);
- op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- op1 = mem_loc_descriptor (rtlop1, mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == NULL || op1 == NULL)
- return NULL;
- if (GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE)
- for (i = 0; i < 2; i++)
- {
- if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_WIDE_INT)
- mask[i] = mem_loc_descriptor (GEN_INT (GET_MODE_MASK (mode)),
- mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- else if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT)
- mask[i] = new_loc_descr (HOST_BITS_PER_WIDE_INT == 32
- ? DW_OP_const4u
- : HOST_BITS_PER_WIDE_INT == 64
- ? DW_OP_const8u : DW_OP_constu,
- GET_MODE_MASK (mode), 0);
- else
- mask[i] = NULL;
- if (mask[i] == NULL)
- return NULL;
- add_loc_descr (&mask[i], new_loc_descr (DW_OP_and, 0, 0));
- }
- ret = op0;
- add_loc_descr (&ret, op1);
- add_loc_descr (&ret, new_loc_descr (DW_OP_over, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_over, 0, 0));
- if (GET_CODE (rtl) == ROTATERT)
- {
- add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst,
- GET_MODE_BITSIZE (mode), 0));
- }
- add_loc_descr (&ret, new_loc_descr (DW_OP_shl, 0, 0));
- if (mask[0] != NULL)
- add_loc_descr (&ret, mask[0]);
- add_loc_descr (&ret, new_loc_descr (DW_OP_rot, 0, 0));
- if (mask[1] != NULL)
- {
- add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
- add_loc_descr (&ret, mask[1]);
- add_loc_descr (&ret, new_loc_descr (DW_OP_swap, 0, 0));
- }
- if (GET_CODE (rtl) == ROTATE)
- {
- add_loc_descr (&ret, new_loc_descr (DW_OP_neg, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst,
- GET_MODE_BITSIZE (mode), 0));
- }
- add_loc_descr (&ret, new_loc_descr (DW_OP_shr, 0, 0));
- add_loc_descr (&ret, new_loc_descr (DW_OP_or, 0, 0));
- return ret;
- }
- /* Helper function for mem_loc_descriptor. Return DW_OP_GNU_parameter_ref
- for DEBUG_PARAMETER_REF RTL. */
- static dw_loc_descr_ref
- parameter_ref_descriptor (rtx rtl)
- {
- dw_loc_descr_ref ret;
- dw_die_ref ref;
- if (dwarf_strict)
- return NULL;
- gcc_assert (TREE_CODE (DEBUG_PARAMETER_REF_DECL (rtl)) == PARM_DECL);
- ref = lookup_decl_die (DEBUG_PARAMETER_REF_DECL (rtl));
- ret = new_loc_descr (DW_OP_GNU_parameter_ref, 0, 0);
- if (ref)
- {
- ret->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- ret->dw_loc_oprnd1.v.val_die_ref.die = ref;
- ret->dw_loc_oprnd1.v.val_die_ref.external = 0;
- }
- else
- {
- ret->dw_loc_oprnd1.val_class = dw_val_class_decl_ref;
- ret->dw_loc_oprnd1.v.val_decl_ref = DEBUG_PARAMETER_REF_DECL (rtl);
- }
- return ret;
- }
- /* The following routine converts the RTL for a variable or parameter
- (resident in memory) into an equivalent Dwarf representation of a
- mechanism for getting the address of that same variable onto the top of a
- hypothetical "address evaluation" stack.
- When creating memory location descriptors, we are effectively transforming
- the RTL for a memory-resident object into its Dwarf postfix expression
- equivalent. This routine recursively descends an RTL tree, turning
- it into Dwarf postfix code as it goes.
- MODE is the mode that should be assumed for the rtl if it is VOIDmode.
- MEM_MODE is the mode of the memory reference, needed to handle some
- autoincrement addressing modes.
- Return 0 if we can't represent the location. */
- dw_loc_descr_ref
- mem_loc_descriptor (rtx rtl, machine_mode mode,
- machine_mode mem_mode,
- enum var_init_status initialized)
- {
- dw_loc_descr_ref mem_loc_result = NULL;
- enum dwarf_location_atom op;
- dw_loc_descr_ref op0, op1;
- rtx inner = NULL_RTX;
- if (mode == VOIDmode)
- mode = GET_MODE (rtl);
- /* Note that for a dynamically sized array, the location we will generate a
- description of here will be the lowest numbered location which is
- actually within the array. That's *not* necessarily the same as the
- zeroth element of the array. */
- rtl = targetm.delegitimize_address (rtl);
- if (mode != GET_MODE (rtl) && GET_MODE (rtl) != VOIDmode)
- return NULL;
- switch (GET_CODE (rtl))
- {
- case POST_INC:
- case POST_DEC:
- case POST_MODIFY:
- return mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode, initialized);
- case SUBREG:
- /* The case of a subreg may arise when we have a local (register)
- variable or a formal (register) parameter which doesn't quite fill
- up an entire register. For now, just assume that it is
- legitimate to make the Dwarf info refer to the whole register which
- contains the given subreg. */
- if (!subreg_lowpart_p (rtl))
- break;
- inner = SUBREG_REG (rtl);
- case TRUNCATE:
- if (inner == NULL_RTX)
- inner = XEXP (rtl, 0);
- if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_CLASS (GET_MODE (inner)) == MODE_INT
- && (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
- #ifdef POINTERS_EXTEND_UNSIGNED
- || (mode == Pmode && mem_mode != VOIDmode)
- #endif
- )
- && GET_MODE_SIZE (GET_MODE (inner)) <= DWARF2_ADDR_SIZE)
- {
- mem_loc_result = mem_loc_descriptor (inner,
- GET_MODE (inner),
- mem_mode, initialized);
- break;
- }
- if (dwarf_strict)
- break;
- if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (inner)))
- break;
- if (GET_MODE_SIZE (mode) != GET_MODE_SIZE (GET_MODE (inner))
- && (GET_MODE_CLASS (mode) != MODE_INT
- || GET_MODE_CLASS (GET_MODE (inner)) != MODE_INT))
- break;
- else
- {
- dw_die_ref type_die;
- dw_loc_descr_ref cvt;
- mem_loc_result = mem_loc_descriptor (inner,
- GET_MODE (inner),
- mem_mode, initialized);
- if (mem_loc_result == NULL)
- break;
- type_die = base_type_for_mode (mode,
- GET_MODE_CLASS (mode) == MODE_INT);
- if (type_die == NULL)
- {
- mem_loc_result = NULL;
- break;
- }
- if (GET_MODE_SIZE (mode)
- != GET_MODE_SIZE (GET_MODE (inner)))
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- else
- cvt = new_loc_descr (DW_OP_GNU_reinterpret, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&mem_loc_result, cvt);
- }
- break;
- case REG:
- if (GET_MODE_CLASS (mode) != MODE_INT
- || (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE
- && rtl != arg_pointer_rtx
- && rtl != frame_pointer_rtx
- #ifdef POINTERS_EXTEND_UNSIGNED
- && (mode != Pmode || mem_mode == VOIDmode)
- #endif
- ))
- {
- dw_die_ref type_die;
- unsigned int dbx_regnum;
- if (dwarf_strict)
- break;
- if (REGNO (rtl) > FIRST_PSEUDO_REGISTER)
- break;
- type_die = base_type_for_mode (mode,
- GET_MODE_CLASS (mode) == MODE_INT);
- if (type_die == NULL)
- break;
- dbx_regnum = dbx_reg_number (rtl);
- if (dbx_regnum == IGNORED_DWARF_REGNUM)
- break;
- mem_loc_result = new_loc_descr (DW_OP_GNU_regval_type,
- dbx_regnum, 0);
- mem_loc_result->dw_loc_oprnd2.val_class = dw_val_class_die_ref;
- mem_loc_result->dw_loc_oprnd2.v.val_die_ref.die = type_die;
- mem_loc_result->dw_loc_oprnd2.v.val_die_ref.external = 0;
- break;
- }
- /* Whenever a register number forms a part of the description of the
- method for calculating the (dynamic) address of a memory resident
- object, DWARF rules require the register number be referred to as
- a "base register". This distinction is not based in any way upon
- what category of register the hardware believes the given register
- belongs to. This is strictly DWARF terminology we're dealing with
- here. Note that in cases where the location of a memory-resident
- data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
- OP_CONST (0)) the actual DWARF location descriptor that we generate
- may just be OP_BASEREG (basereg). This may look deceptively like
- the object in question was allocated to a register (rather than in
- memory) so DWARF consumers need to be aware of the subtle
- distinction between OP_REG and OP_BASEREG. */
- if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
- mem_loc_result = based_loc_descr (rtl, 0, VAR_INIT_STATUS_INITIALIZED);
- else if (stack_realign_drap
- && crtl->drap_reg
- && crtl->args.internal_arg_pointer == rtl
- && REGNO (crtl->drap_reg) < FIRST_PSEUDO_REGISTER)
- {
- /* If RTL is internal_arg_pointer, which has been optimized
- out, use DRAP instead. */
- mem_loc_result = based_loc_descr (crtl->drap_reg, 0,
- VAR_INIT_STATUS_INITIALIZED);
- }
- break;
- case SIGN_EXTEND:
- case ZERO_EXTEND:
- if (GET_MODE_CLASS (mode) != MODE_INT)
- break;
- op0 = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (XEXP (rtl, 0)),
- mem_mode, VAR_INIT_STATUS_INITIALIZED);
- if (op0 == 0)
- break;
- else if (GET_CODE (rtl) == ZERO_EXTEND
- && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
- && GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0)))
- < HOST_BITS_PER_WIDE_INT
- /* If DW_OP_const{1,2,4}u won't be used, it is shorter
- to expand zero extend as two shifts instead of
- masking. */
- && GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) <= 4)
- {
- machine_mode imode = GET_MODE (XEXP (rtl, 0));
- mem_loc_result = op0;
- add_loc_descr (&mem_loc_result,
- int_loc_descriptor (GET_MODE_MASK (imode)));
- add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_and, 0, 0));
- }
- else if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE)
- {
- int shift = DWARF2_ADDR_SIZE
- - GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)));
- shift *= BITS_PER_UNIT;
- if (GET_CODE (rtl) == SIGN_EXTEND)
- op = DW_OP_shra;
- else
- op = DW_OP_shr;
- mem_loc_result = op0;
- add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
- add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
- add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
- add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
- }
- else if (!dwarf_strict)
- {
- dw_die_ref type_die1, type_die2;
- dw_loc_descr_ref cvt;
- type_die1 = base_type_for_mode (GET_MODE (XEXP (rtl, 0)),
- GET_CODE (rtl) == ZERO_EXTEND);
- if (type_die1 == NULL)
- break;
- type_die2 = base_type_for_mode (mode, 1);
- if (type_die2 == NULL)
- break;
- mem_loc_result = op0;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die1;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&mem_loc_result, cvt);
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die2;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&mem_loc_result, cvt);
- }
- break;
- case MEM:
- {
- rtx new_rtl = avoid_constant_pool_reference (rtl);
- if (new_rtl != rtl)
- {
- mem_loc_result = mem_loc_descriptor (new_rtl, mode, mem_mode,
- initialized);
- if (mem_loc_result != NULL)
- return mem_loc_result;
- }
- }
- mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0),
- get_address_mode (rtl), mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (mem_loc_result == NULL)
- mem_loc_result = tls_mem_loc_descriptor (rtl);
- if (mem_loc_result != NULL)
- {
- if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE
- || GET_MODE_CLASS (mode) != MODE_INT)
- {
- dw_die_ref type_die;
- dw_loc_descr_ref deref;
- if (dwarf_strict)
- return NULL;
- type_die
- = base_type_for_mode (mode, GET_MODE_CLASS (mode) == MODE_INT);
- if (type_die == NULL)
- return NULL;
- deref = new_loc_descr (DW_OP_GNU_deref_type,
- GET_MODE_SIZE (mode), 0);
- deref->dw_loc_oprnd2.val_class = dw_val_class_die_ref;
- deref->dw_loc_oprnd2.v.val_die_ref.die = type_die;
- deref->dw_loc_oprnd2.v.val_die_ref.external = 0;
- add_loc_descr (&mem_loc_result, deref);
- }
- else if (GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE)
- add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
- else
- add_loc_descr (&mem_loc_result,
- new_loc_descr (DW_OP_deref_size,
- GET_MODE_SIZE (mode), 0));
- }
- break;
- case LO_SUM:
- return mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode, initialized);
- case LABEL_REF:
- /* Some ports can transform a symbol ref into a label ref, because
- the symbol ref is too far away and has to be dumped into a constant
- pool. */
- case CONST:
- case SYMBOL_REF:
- if ((GET_MODE_CLASS (mode) != MODE_INT
- && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
- || (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE
- #ifdef POINTERS_EXTEND_UNSIGNED
- && (mode != Pmode || mem_mode == VOIDmode)
- #endif
- ))
- break;
- if (GET_CODE (rtl) == SYMBOL_REF
- && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE)
- {
- dw_loc_descr_ref temp;
- /* If this is not defined, we have no way to emit the data. */
- if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
- break;
- temp = new_addr_loc_descr (rtl, dtprel_true);
- mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
- add_loc_descr (&mem_loc_result, temp);
- break;
- }
- if (!const_ok_for_output (rtl))
- break;
- symref:
- mem_loc_result = new_addr_loc_descr (rtl, dtprel_false);
- vec_safe_push (used_rtx_array, rtl);
- break;
- case CONCAT:
- case CONCATN:
- case VAR_LOCATION:
- case DEBUG_IMPLICIT_PTR:
- expansion_failed (NULL_TREE, rtl,
- "CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor");
- return 0;
- case ENTRY_VALUE:
- if (dwarf_strict)
- return NULL;
- if (REG_P (ENTRY_VALUE_EXP (rtl)))
- {
- if (GET_MODE_CLASS (mode) != MODE_INT
- || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)
- op0 = mem_loc_descriptor (ENTRY_VALUE_EXP (rtl), mode,
- VOIDmode, VAR_INIT_STATUS_INITIALIZED);
- else
- {
- unsigned int dbx_regnum = dbx_reg_number (ENTRY_VALUE_EXP (rtl));
- if (dbx_regnum == IGNORED_DWARF_REGNUM)
- return NULL;
- op0 = one_reg_loc_descriptor (dbx_regnum,
- VAR_INIT_STATUS_INITIALIZED);
- }
- }
- else if (MEM_P (ENTRY_VALUE_EXP (rtl))
- && REG_P (XEXP (ENTRY_VALUE_EXP (rtl), 0)))
- {
- op0 = mem_loc_descriptor (ENTRY_VALUE_EXP (rtl), mode,
- VOIDmode, VAR_INIT_STATUS_INITIALIZED);
- if (op0 && op0->dw_loc_opc == DW_OP_fbreg)
- return NULL;
- }
- else
- gcc_unreachable ();
- if (op0 == NULL)
- return NULL;
- mem_loc_result = new_loc_descr (DW_OP_GNU_entry_value, 0, 0);
- mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_loc;
- mem_loc_result->dw_loc_oprnd1.v.val_loc = op0;
- break;
- case DEBUG_PARAMETER_REF:
- mem_loc_result = parameter_ref_descriptor (rtl);
- break;
- case PRE_MODIFY:
- /* Extract the PLUS expression nested inside and fall into
- PLUS code below. */
- rtl = XEXP (rtl, 1);
- goto plus;
- case PRE_INC:
- case PRE_DEC:
- /* Turn these into a PLUS expression and fall into the PLUS code
- below. */
- rtl = gen_rtx_PLUS (mode, XEXP (rtl, 0),
- gen_int_mode (GET_CODE (rtl) == PRE_INC
- ? GET_MODE_UNIT_SIZE (mem_mode)
- : -GET_MODE_UNIT_SIZE (mem_mode),
- mode));
- /* ... fall through ... */
- case PLUS:
- plus:
- if (is_based_loc (rtl)
- && (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
- || XEXP (rtl, 0) == arg_pointer_rtx
- || XEXP (rtl, 0) == frame_pointer_rtx)
- && GET_MODE_CLASS (mode) == MODE_INT)
- mem_loc_result = based_loc_descr (XEXP (rtl, 0),
- INTVAL (XEXP (rtl, 1)),
- VAR_INIT_STATUS_INITIALIZED);
- else
- {
- mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (mem_loc_result == 0)
- break;
- if (CONST_INT_P (XEXP (rtl, 1))
- && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE)
- loc_descr_plus_const (&mem_loc_result, INTVAL (XEXP (rtl, 1)));
- else
- {
- op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op1 == 0)
- return NULL;
- add_loc_descr (&mem_loc_result, op1);
- add_loc_descr (&mem_loc_result,
- new_loc_descr (DW_OP_plus, 0, 0));
- }
- }
- break;
- /* If a pseudo-reg is optimized away, it is possible for it to
- be replaced with a MEM containing a multiply or shift. */
- case MINUS:
- op = DW_OP_minus;
- goto do_binop;
- case MULT:
- op = DW_OP_mul;
- goto do_binop;
- case DIV:
- if (!dwarf_strict
- && GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)
- {
- mem_loc_result = typed_binop (DW_OP_div, rtl,
- base_type_for_mode (mode, 0),
- mode, mem_mode);
- break;
- }
- op = DW_OP_div;
- goto do_binop;
- case UMOD:
- op = DW_OP_mod;
- goto do_binop;
- case ASHIFT:
- op = DW_OP_shl;
- goto do_shift;
- case ASHIFTRT:
- op = DW_OP_shra;
- goto do_shift;
- case LSHIFTRT:
- op = DW_OP_shr;
- goto do_shift;
- do_shift:
- if (GET_MODE_CLASS (mode) != MODE_INT)
- break;
- op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- {
- rtx rtlop1 = XEXP (rtl, 1);
- if (GET_MODE (rtlop1) != VOIDmode
- && GET_MODE_BITSIZE (GET_MODE (rtlop1))
- < GET_MODE_BITSIZE (mode))
- rtlop1 = gen_rtx_ZERO_EXTEND (mode, rtlop1);
- op1 = mem_loc_descriptor (rtlop1, mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- }
- if (op0 == 0 || op1 == 0)
- break;
- mem_loc_result = op0;
- add_loc_descr (&mem_loc_result, op1);
- add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
- break;
- case AND:
- op = DW_OP_and;
- goto do_binop;
- case IOR:
- op = DW_OP_or;
- goto do_binop;
- case XOR:
- op = DW_OP_xor;
- goto do_binop;
- do_binop:
- op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == 0 || op1 == 0)
- break;
- mem_loc_result = op0;
- add_loc_descr (&mem_loc_result, op1);
- add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
- break;
- case MOD:
- if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE && !dwarf_strict)
- {
- mem_loc_result = typed_binop (DW_OP_mod, rtl,
- base_type_for_mode (mode, 0),
- mode, mem_mode);
- break;
- }
- op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == 0 || op1 == 0)
- break;
- mem_loc_result = op0;
- add_loc_descr (&mem_loc_result, op1);
- add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0));
- add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_over, 0, 0));
- add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_div, 0, 0));
- add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
- add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_minus, 0, 0));
- break;
- case UDIV:
- if (!dwarf_strict && GET_MODE_CLASS (mode) == MODE_INT)
- {
- if (GET_MODE_CLASS (mode) > DWARF2_ADDR_SIZE)
- {
- op = DW_OP_div;
- goto do_binop;
- }
- mem_loc_result = typed_binop (DW_OP_div, rtl,
- base_type_for_mode (mode, 1),
- mode, mem_mode);
- }
- break;
- case NOT:
- op = DW_OP_not;
- goto do_unop;
- case ABS:
- op = DW_OP_abs;
- goto do_unop;
- case NEG:
- op = DW_OP_neg;
- goto do_unop;
- do_unop:
- op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == 0)
- break;
- mem_loc_result = op0;
- add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
- break;
- case CONST_INT:
- if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
- #ifdef POINTERS_EXTEND_UNSIGNED
- || (mode == Pmode
- && mem_mode != VOIDmode
- && trunc_int_for_mode (INTVAL (rtl), ptr_mode) == INTVAL (rtl))
- #endif
- )
- {
- mem_loc_result = int_loc_descriptor (INTVAL (rtl));
- break;
- }
- if (!dwarf_strict
- && (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT
- || GET_MODE_BITSIZE (mode) == HOST_BITS_PER_DOUBLE_INT))
- {
- dw_die_ref type_die = base_type_for_mode (mode, 1);
- machine_mode amode;
- if (type_die == NULL)
- return NULL;
- amode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT,
- MODE_INT, 0);
- if (INTVAL (rtl) >= 0
- && amode != BLKmode
- && trunc_int_for_mode (INTVAL (rtl), amode) == INTVAL (rtl)
- /* const DW_OP_GNU_convert <XXX> vs.
- DW_OP_GNU_const_type <XXX, 1, const>. */
- && size_of_int_loc_descriptor (INTVAL (rtl)) + 1 + 1
- < (unsigned long) 1 + 1 + 1 + GET_MODE_SIZE (mode))
- {
- mem_loc_result = int_loc_descriptor (INTVAL (rtl));
- op0 = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- op0->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- op0->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- op0->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&mem_loc_result, op0);
- return mem_loc_result;
- }
- mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0,
- INTVAL (rtl));
- mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0;
- if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT)
- mem_loc_result->dw_loc_oprnd2.val_class = dw_val_class_const;
- else
- {
- mem_loc_result->dw_loc_oprnd2.val_class
- = dw_val_class_const_double;
- mem_loc_result->dw_loc_oprnd2.v.val_double
- = double_int::from_shwi (INTVAL (rtl));
- }
- }
- break;
- case CONST_DOUBLE:
- if (!dwarf_strict)
- {
- dw_die_ref type_die;
- /* Note that if TARGET_SUPPORTS_WIDE_INT == 0, a
- CONST_DOUBLE rtx could represent either a large integer
- or a floating-point constant. If TARGET_SUPPORTS_WIDE_INT != 0,
- the value is always a floating point constant.
- When it is an integer, a CONST_DOUBLE is used whenever
- the constant requires 2 HWIs to be adequately represented.
- We output CONST_DOUBLEs as blocks. */
- if (mode == VOIDmode
- || (GET_MODE (rtl) == VOIDmode
- && GET_MODE_BITSIZE (mode) != HOST_BITS_PER_DOUBLE_INT))
- break;
- type_die = base_type_for_mode (mode,
- GET_MODE_CLASS (mode) == MODE_INT);
- if (type_die == NULL)
- return NULL;
- mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0, 0);
- mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0;
- #if TARGET_SUPPORTS_WIDE_INT == 0
- if (!SCALAR_FLOAT_MODE_P (mode))
- {
- mem_loc_result->dw_loc_oprnd2.val_class
- = dw_val_class_const_double;
- mem_loc_result->dw_loc_oprnd2.v.val_double
- = rtx_to_double_int (rtl);
- }
- else
- #endif
- {
- unsigned int length = GET_MODE_SIZE (mode);
- unsigned char *array = ggc_vec_alloc<unsigned char> (length);
- insert_float (rtl, array);
- mem_loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
- mem_loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4;
- mem_loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
- mem_loc_result->dw_loc_oprnd2.v.val_vec.array = array;
- }
- }
- break;
- case CONST_WIDE_INT:
- if (!dwarf_strict)
- {
- dw_die_ref type_die;
- type_die = base_type_for_mode (mode,
- GET_MODE_CLASS (mode) == MODE_INT);
- if (type_die == NULL)
- return NULL;
- mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0, 0);
- mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0;
- mem_loc_result->dw_loc_oprnd2.val_class
- = dw_val_class_wide_int;
- mem_loc_result->dw_loc_oprnd2.v.val_wide = ggc_alloc<wide_int> ();
- *mem_loc_result->dw_loc_oprnd2.v.val_wide = std::make_pair (rtl, mode);
- }
- break;
- case EQ:
- mem_loc_result = scompare_loc_descriptor (DW_OP_eq, rtl, mem_mode);
- break;
- case GE:
- mem_loc_result = scompare_loc_descriptor (DW_OP_ge, rtl, mem_mode);
- break;
- case GT:
- mem_loc_result = scompare_loc_descriptor (DW_OP_gt, rtl, mem_mode);
- break;
- case LE:
- mem_loc_result = scompare_loc_descriptor (DW_OP_le, rtl, mem_mode);
- break;
- case LT:
- mem_loc_result = scompare_loc_descriptor (DW_OP_lt, rtl, mem_mode);
- break;
- case NE:
- mem_loc_result = scompare_loc_descriptor (DW_OP_ne, rtl, mem_mode);
- break;
- case GEU:
- mem_loc_result = ucompare_loc_descriptor (DW_OP_ge, rtl, mem_mode);
- break;
- case GTU:
- mem_loc_result = ucompare_loc_descriptor (DW_OP_gt, rtl, mem_mode);
- break;
- case LEU:
- mem_loc_result = ucompare_loc_descriptor (DW_OP_le, rtl, mem_mode);
- break;
- case LTU:
- mem_loc_result = ucompare_loc_descriptor (DW_OP_lt, rtl, mem_mode);
- break;
- case UMIN:
- case UMAX:
- if (GET_MODE_CLASS (mode) != MODE_INT)
- break;
- /* FALLTHRU */
- case SMIN:
- case SMAX:
- mem_loc_result = minmax_loc_descriptor (rtl, mode, mem_mode);
- break;
- case ZERO_EXTRACT:
- case SIGN_EXTRACT:
- if (CONST_INT_P (XEXP (rtl, 1))
- && CONST_INT_P (XEXP (rtl, 2))
- && ((unsigned) INTVAL (XEXP (rtl, 1))
- + (unsigned) INTVAL (XEXP (rtl, 2))
- <= GET_MODE_BITSIZE (mode))
- && GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE
- && GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE)
- {
- int shift, size;
- op0 = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (XEXP (rtl, 0)),
- mem_mode, VAR_INIT_STATUS_INITIALIZED);
- if (op0 == 0)
- break;
- if (GET_CODE (rtl) == SIGN_EXTRACT)
- op = DW_OP_shra;
- else
- op = DW_OP_shr;
- mem_loc_result = op0;
- size = INTVAL (XEXP (rtl, 1));
- shift = INTVAL (XEXP (rtl, 2));
- if (BITS_BIG_ENDIAN)
- shift = GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0)))
- - shift - size;
- if (shift + size != (int) DWARF2_ADDR_SIZE)
- {
- add_loc_descr (&mem_loc_result,
- int_loc_descriptor (DWARF2_ADDR_SIZE
- - shift - size));
- add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0));
- }
- if (size != (int) DWARF2_ADDR_SIZE)
- {
- add_loc_descr (&mem_loc_result,
- int_loc_descriptor (DWARF2_ADDR_SIZE - size));
- add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
- }
- }
- break;
- case IF_THEN_ELSE:
- {
- dw_loc_descr_ref op2, bra_node, drop_node;
- op0 = mem_loc_descriptor (XEXP (rtl, 0),
- GET_MODE (XEXP (rtl, 0)) == VOIDmode
- ? word_mode : GET_MODE (XEXP (rtl, 0)),
- mem_mode, VAR_INIT_STATUS_INITIALIZED);
- op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- op2 = mem_loc_descriptor (XEXP (rtl, 2), mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- if (op0 == NULL || op1 == NULL || op2 == NULL)
- break;
- mem_loc_result = op1;
- add_loc_descr (&mem_loc_result, op2);
- add_loc_descr (&mem_loc_result, op0);
- bra_node = new_loc_descr (DW_OP_bra, 0, 0);
- add_loc_descr (&mem_loc_result, bra_node);
- add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_swap, 0, 0));
- drop_node = new_loc_descr (DW_OP_drop, 0, 0);
- add_loc_descr (&mem_loc_result, drop_node);
- bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
- bra_node->dw_loc_oprnd1.v.val_loc = drop_node;
- }
- break;
- case FLOAT_EXTEND:
- case FLOAT_TRUNCATE:
- case FLOAT:
- case UNSIGNED_FLOAT:
- case FIX:
- case UNSIGNED_FIX:
- if (!dwarf_strict)
- {
- dw_die_ref type_die;
- dw_loc_descr_ref cvt;
- op0 = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (XEXP (rtl, 0)),
- mem_mode, VAR_INIT_STATUS_INITIALIZED);
- if (op0 == NULL)
- break;
- if (GET_MODE_CLASS (GET_MODE (XEXP (rtl, 0))) == MODE_INT
- && (GET_CODE (rtl) == FLOAT
- || GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0)))
- <= DWARF2_ADDR_SIZE))
- {
- type_die = base_type_for_mode (GET_MODE (XEXP (rtl, 0)),
- GET_CODE (rtl) == UNSIGNED_FLOAT);
- if (type_die == NULL)
- break;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&op0, cvt);
- }
- type_die = base_type_for_mode (mode, GET_CODE (rtl) == UNSIGNED_FIX);
- if (type_die == NULL)
- break;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
- cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
- cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_loc_descr (&op0, cvt);
- if (GET_MODE_CLASS (mode) == MODE_INT
- && (GET_CODE (rtl) == FIX
- || GET_MODE_SIZE (mode) < DWARF2_ADDR_SIZE))
- {
- op0 = convert_descriptor_to_mode (mode, op0);
- if (op0 == NULL)
- break;
- }
- mem_loc_result = op0;
- }
- break;
- case CLZ:
- case CTZ:
- case FFS:
- mem_loc_result = clz_loc_descriptor (rtl, mode, mem_mode);
- break;
- case POPCOUNT:
- case PARITY:
- mem_loc_result = popcount_loc_descriptor (rtl, mode, mem_mode);
- break;
- case BSWAP:
- mem_loc_result = bswap_loc_descriptor (rtl, mode, mem_mode);
- break;
- case ROTATE:
- case ROTATERT:
- mem_loc_result = rotate_loc_descriptor (rtl, mode, mem_mode);
- break;
- case COMPARE:
- /* In theory, we could implement the above. */
- /* DWARF cannot represent the unsigned compare operations
- natively. */
- case SS_MULT:
- case US_MULT:
- case SS_DIV:
- case US_DIV:
- case SS_PLUS:
- case US_PLUS:
- case SS_MINUS:
- case US_MINUS:
- case SS_NEG:
- case US_NEG:
- case SS_ABS:
- case SS_ASHIFT:
- case US_ASHIFT:
- case SS_TRUNCATE:
- case US_TRUNCATE:
- case UNORDERED:
- case ORDERED:
- case UNEQ:
- case UNGE:
- case UNGT:
- case UNLE:
- case UNLT:
- case LTGT:
- case FRACT_CONVERT:
- case UNSIGNED_FRACT_CONVERT:
- case SAT_FRACT:
- case UNSIGNED_SAT_FRACT:
- case SQRT:
- case ASM_OPERANDS:
- case VEC_MERGE:
- case VEC_SELECT:
- case VEC_CONCAT:
- case VEC_DUPLICATE:
- case UNSPEC:
- case HIGH:
- case FMA:
- case STRICT_LOW_PART:
- case CONST_VECTOR:
- case CONST_FIXED:
- case CLRSB:
- case CLOBBER:
- /* If delegitimize_address couldn't do anything with the UNSPEC, we
- can't express it in the debug info. This can happen e.g. with some
- TLS UNSPECs. */
- break;
- case CONST_STRING:
- resolve_one_addr (&rtl);
- goto symref;
- default:
- #ifdef ENABLE_CHECKING
- print_rtl (stderr, rtl);
- gcc_unreachable ();
- #else
- break;
- #endif
- }
- if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
- add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
- return mem_loc_result;
- }
- /* Return a descriptor that describes the concatenation of two locations.
- This is typically a complex variable. */
- static dw_loc_descr_ref
- concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
- {
- dw_loc_descr_ref cc_loc_result = NULL;
- dw_loc_descr_ref x0_ref
- = loc_descriptor (x0, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
- dw_loc_descr_ref x1_ref
- = loc_descriptor (x1, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
- if (x0_ref == 0 || x1_ref == 0)
- return 0;
- cc_loc_result = x0_ref;
- add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x0)));
- add_loc_descr (&cc_loc_result, x1_ref);
- add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
- if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
- add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
- return cc_loc_result;
- }
- /* Return a descriptor that describes the concatenation of N
- locations. */
- static dw_loc_descr_ref
- concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
- {
- unsigned int i;
- dw_loc_descr_ref cc_loc_result = NULL;
- unsigned int n = XVECLEN (concatn, 0);
- for (i = 0; i < n; ++i)
- {
- dw_loc_descr_ref ref;
- rtx x = XVECEXP (concatn, 0, i);
- ref = loc_descriptor (x, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
- if (ref == NULL)
- return NULL;
- add_loc_descr (&cc_loc_result, ref);
- add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
- }
- if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
- add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
- return cc_loc_result;
- }
- /* Helper function for loc_descriptor. Return DW_OP_GNU_implicit_pointer
- for DEBUG_IMPLICIT_PTR RTL. */
- static dw_loc_descr_ref
- implicit_ptr_descriptor (rtx rtl, HOST_WIDE_INT offset)
- {
- dw_loc_descr_ref ret;
- dw_die_ref ref;
- if (dwarf_strict)
- return NULL;
- gcc_assert (TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == VAR_DECL
- || TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == PARM_DECL
- || TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == RESULT_DECL);
- ref = lookup_decl_die (DEBUG_IMPLICIT_PTR_DECL (rtl));
- ret = new_loc_descr (DW_OP_GNU_implicit_pointer, 0, offset);
- ret->dw_loc_oprnd2.val_class = dw_val_class_const;
- if (ref)
- {
- ret->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- ret->dw_loc_oprnd1.v.val_die_ref.die = ref;
- ret->dw_loc_oprnd1.v.val_die_ref.external = 0;
- }
- else
- {
- ret->dw_loc_oprnd1.val_class = dw_val_class_decl_ref;
- ret->dw_loc_oprnd1.v.val_decl_ref = DEBUG_IMPLICIT_PTR_DECL (rtl);
- }
- return ret;
- }
- /* Output a proper Dwarf location descriptor for a variable or parameter
- which is either allocated in a register or in a memory location. For a
- register, we just generate an OP_REG and the register number. For a
- memory location we provide a Dwarf postfix expression describing how to
- generate the (dynamic) address of the object onto the address stack.
- MODE is mode of the decl if this loc_descriptor is going to be used in
- .debug_loc section where DW_OP_stack_value and DW_OP_implicit_value are
- allowed, VOIDmode otherwise.
- If we don't know how to describe it, return 0. */
- static dw_loc_descr_ref
- loc_descriptor (rtx rtl, machine_mode mode,
- enum var_init_status initialized)
- {
- dw_loc_descr_ref loc_result = NULL;
- switch (GET_CODE (rtl))
- {
- case SUBREG:
- /* The case of a subreg may arise when we have a local (register)
- variable or a formal (register) parameter which doesn't quite fill
- up an entire register. For now, just assume that it is
- legitimate to make the Dwarf info refer to the whole register which
- contains the given subreg. */
- if (REG_P (SUBREG_REG (rtl)) && subreg_lowpart_p (rtl))
- loc_result = loc_descriptor (SUBREG_REG (rtl),
- GET_MODE (SUBREG_REG (rtl)), initialized);
- else
- goto do_default;
- break;
- case REG:
- loc_result = reg_loc_descriptor (rtl, initialized);
- break;
- case MEM:
- loc_result = mem_loc_descriptor (XEXP (rtl, 0), get_address_mode (rtl),
- GET_MODE (rtl), initialized);
- if (loc_result == NULL)
- loc_result = tls_mem_loc_descriptor (rtl);
- if (loc_result == NULL)
- {
- rtx new_rtl = avoid_constant_pool_reference (rtl);
- if (new_rtl != rtl)
- loc_result = loc_descriptor (new_rtl, mode, initialized);
- }
- break;
- case CONCAT:
- loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
- initialized);
- break;
- case CONCATN:
- loc_result = concatn_loc_descriptor (rtl, initialized);
- break;
- case VAR_LOCATION:
- /* Single part. */
- if (GET_CODE (PAT_VAR_LOCATION_LOC (rtl)) != PARALLEL)
- {
- rtx loc = PAT_VAR_LOCATION_LOC (rtl);
- if (GET_CODE (loc) == EXPR_LIST)
- loc = XEXP (loc, 0);
- loc_result = loc_descriptor (loc, mode, initialized);
- break;
- }
- rtl = XEXP (rtl, 1);
- /* FALLTHRU */
- case PARALLEL:
- {
- rtvec par_elems = XVEC (rtl, 0);
- int num_elem = GET_NUM_ELEM (par_elems);
- machine_mode mode;
- int i;
- /* Create the first one, so we have something to add to. */
- loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
- VOIDmode, initialized);
- if (loc_result == NULL)
- return NULL;
- mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
- add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
- for (i = 1; i < num_elem; i++)
- {
- dw_loc_descr_ref temp;
- temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
- VOIDmode, initialized);
- if (temp == NULL)
- return NULL;
- add_loc_descr (&loc_result, temp);
- mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
- add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
- }
- }
- break;
- case CONST_INT:
- if (mode != VOIDmode && mode != BLKmode)
- loc_result = address_of_int_loc_descriptor (GET_MODE_SIZE (mode),
- INTVAL (rtl));
- break;
- case CONST_DOUBLE:
- if (mode == VOIDmode)
- mode = GET_MODE (rtl);
- if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
- {
- gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
- /* Note that a CONST_DOUBLE rtx could represent either an integer
- or a floating-point constant. A CONST_DOUBLE is used whenever
- the constant requires more than one word in order to be
- adequately represented. We output CONST_DOUBLEs as blocks. */
- loc_result = new_loc_descr (DW_OP_implicit_value,
- GET_MODE_SIZE (mode), 0);
- #if TARGET_SUPPORTS_WIDE_INT == 0
- if (!SCALAR_FLOAT_MODE_P (mode))
- {
- loc_result->dw_loc_oprnd2.val_class = dw_val_class_const_double;
- loc_result->dw_loc_oprnd2.v.val_double
- = rtx_to_double_int (rtl);
- }
- else
- #endif
- {
- unsigned int length = GET_MODE_SIZE (mode);
- unsigned char *array = ggc_vec_alloc<unsigned char> (length);
- insert_float (rtl, array);
- loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
- loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4;
- loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
- loc_result->dw_loc_oprnd2.v.val_vec.array = array;
- }
- }
- break;
- case CONST_WIDE_INT:
- if (mode == VOIDmode)
- mode = GET_MODE (rtl);
- if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
- {
- loc_result = new_loc_descr (DW_OP_implicit_value,
- GET_MODE_SIZE (mode), 0);
- loc_result->dw_loc_oprnd2.val_class = dw_val_class_wide_int;
- loc_result->dw_loc_oprnd2.v.val_wide = ggc_alloc<wide_int> ();
- *loc_result->dw_loc_oprnd2.v.val_wide = std::make_pair (rtl, mode);
- }
- break;
- case CONST_VECTOR:
- if (mode == VOIDmode)
- mode = GET_MODE (rtl);
- if (mode != VOIDmode && (dwarf_version >= 4 || !dwarf_strict))
- {
- unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl));
- unsigned int length = CONST_VECTOR_NUNITS (rtl);
- unsigned char *array
- = ggc_vec_alloc<unsigned char> (length * elt_size);
- unsigned int i;
- unsigned char *p;
- machine_mode imode = GET_MODE_INNER (mode);
- gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
- switch (GET_MODE_CLASS (mode))
- {
- case MODE_VECTOR_INT:
- for (i = 0, p = array; i < length; i++, p += elt_size)
- {
- rtx elt = CONST_VECTOR_ELT (rtl, i);
- insert_wide_int (std::make_pair (elt, imode), p, elt_size);
- }
- break;
- case MODE_VECTOR_FLOAT:
- for (i = 0, p = array; i < length; i++, p += elt_size)
- {
- rtx elt = CONST_VECTOR_ELT (rtl, i);
- insert_float (elt, p);
- }
- break;
- default:
- gcc_unreachable ();
- }
- loc_result = new_loc_descr (DW_OP_implicit_value,
- length * elt_size, 0);
- loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
- loc_result->dw_loc_oprnd2.v.val_vec.length = length;
- loc_result->dw_loc_oprnd2.v.val_vec.elt_size = elt_size;
- loc_result->dw_loc_oprnd2.v.val_vec.array = array;
- }
- break;
- case CONST:
- if (mode == VOIDmode
- || CONST_SCALAR_INT_P (XEXP (rtl, 0))
- || CONST_DOUBLE_AS_FLOAT_P (XEXP (rtl, 0))
- || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR)
- {
- loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
- break;
- }
- /* FALLTHROUGH */
- case SYMBOL_REF:
- if (!const_ok_for_output (rtl))
- break;
- case LABEL_REF:
- if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
- && (dwarf_version >= 4 || !dwarf_strict))
- {
- loc_result = new_addr_loc_descr (rtl, dtprel_false);
- add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
- vec_safe_push (used_rtx_array, rtl);
- }
- break;
- case DEBUG_IMPLICIT_PTR:
- loc_result = implicit_ptr_descriptor (rtl, 0);
- break;
- case PLUS:
- if (GET_CODE (XEXP (rtl, 0)) == DEBUG_IMPLICIT_PTR
- && CONST_INT_P (XEXP (rtl, 1)))
- {
- loc_result
- = implicit_ptr_descriptor (XEXP (rtl, 0), INTVAL (XEXP (rtl, 1)));
- break;
- }
- /* FALLTHRU */
- do_default:
- default:
- if ((GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode
- && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE
- && dwarf_version >= 4)
- || (!dwarf_strict && mode != VOIDmode && mode != BLKmode))
- {
- /* Value expression. */
- loc_result = mem_loc_descriptor (rtl, mode, VOIDmode, initialized);
- if (loc_result)
- add_loc_descr (&loc_result,
- new_loc_descr (DW_OP_stack_value, 0, 0));
- }
- break;
- }
- return loc_result;
- }
- /* We need to figure out what section we should use as the base for the
- address ranges where a given location is valid.
- 1. If this particular DECL has a section associated with it, use that.
- 2. If this function has a section associated with it, use that.
- 3. Otherwise, use the text section.
- XXX: If you split a variable across multiple sections, we won't notice. */
- static const char *
- secname_for_decl (const_tree decl)
- {
- const char *secname;
- if (VAR_OR_FUNCTION_DECL_P (decl)
- && (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl) || TREE_STATIC (decl))
- && DECL_SECTION_NAME (decl))
- secname = DECL_SECTION_NAME (decl);
- else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
- secname = DECL_SECTION_NAME (current_function_decl);
- else if (cfun && in_cold_section_p)
- secname = crtl->subsections.cold_section_label;
- else
- secname = text_section_label;
- return secname;
- }
- /* Return true when DECL_BY_REFERENCE is defined and set for DECL. */
- static bool
- decl_by_reference_p (tree decl)
- {
- return ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL
- || TREE_CODE (decl) == VAR_DECL)
- && DECL_BY_REFERENCE (decl));
- }
- /* Helper function for dw_loc_list. Compute proper Dwarf location descriptor
- for VARLOC. */
- static dw_loc_descr_ref
- dw_loc_list_1 (tree loc, rtx varloc, int want_address,
- enum var_init_status initialized)
- {
- int have_address = 0;
- dw_loc_descr_ref descr;
- machine_mode mode;
- if (want_address != 2)
- {
- gcc_assert (GET_CODE (varloc) == VAR_LOCATION);
- /* Single part. */
- if (GET_CODE (PAT_VAR_LOCATION_LOC (varloc)) != PARALLEL)
- {
- varloc = PAT_VAR_LOCATION_LOC (varloc);
- if (GET_CODE (varloc) == EXPR_LIST)
- varloc = XEXP (varloc, 0);
- mode = GET_MODE (varloc);
- if (MEM_P (varloc))
- {
- rtx addr = XEXP (varloc, 0);
- descr = mem_loc_descriptor (addr, get_address_mode (varloc),
- mode, initialized);
- if (descr)
- have_address = 1;
- else
- {
- rtx x = avoid_constant_pool_reference (varloc);
- if (x != varloc)
- descr = mem_loc_descriptor (x, mode, VOIDmode,
- initialized);
- }
- }
- else
- descr = mem_loc_descriptor (varloc, mode, VOIDmode, initialized);
- }
- else
- return 0;
- }
- else
- {
- if (GET_CODE (varloc) == VAR_LOCATION)
- mode = DECL_MODE (PAT_VAR_LOCATION_DECL (varloc));
- else
- mode = DECL_MODE (loc);
- descr = loc_descriptor (varloc, mode, initialized);
- have_address = 1;
- }
- if (!descr)
- return 0;
- if (want_address == 2 && !have_address
- && (dwarf_version >= 4 || !dwarf_strict))
- {
- if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE)
- {
- expansion_failed (loc, NULL_RTX,
- "DWARF address size mismatch");
- return 0;
- }
- add_loc_descr (&descr, new_loc_descr (DW_OP_stack_value, 0, 0));
- have_address = 1;
- }
- /* Show if we can't fill the request for an address. */
- if (want_address && !have_address)
- {
- expansion_failed (loc, NULL_RTX,
- "Want address and only have value");
- return 0;
- }
- /* If we've got an address and don't want one, dereference. */
- if (!want_address && have_address)
- {
- HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
- enum dwarf_location_atom op;
- if (size > DWARF2_ADDR_SIZE || size == -1)
- {
- expansion_failed (loc, NULL_RTX,
- "DWARF address size mismatch");
- return 0;
- }
- else if (size == DWARF2_ADDR_SIZE)
- op = DW_OP_deref;
- else
- op = DW_OP_deref_size;
- add_loc_descr (&descr, new_loc_descr (op, size, 0));
- }
- return descr;
- }
- /* Create a DW_OP_piece or DW_OP_bit_piece for bitsize, or return NULL
- if it is not possible. */
- static dw_loc_descr_ref
- new_loc_descr_op_bit_piece (HOST_WIDE_INT bitsize, HOST_WIDE_INT offset)
- {
- if ((bitsize % BITS_PER_UNIT) == 0 && offset == 0)
- return new_loc_descr (DW_OP_piece, bitsize / BITS_PER_UNIT, 0);
- else if (dwarf_version >= 3 || !dwarf_strict)
- return new_loc_descr (DW_OP_bit_piece, bitsize, offset);
- else
- return NULL;
- }
- /* Helper function for dw_loc_list. Compute proper Dwarf location descriptor
- for VAR_LOC_NOTE for variable DECL that has been optimized by SRA. */
- static dw_loc_descr_ref
- dw_sra_loc_expr (tree decl, rtx loc)
- {
- rtx p;
- unsigned HOST_WIDE_INT padsize = 0;
- dw_loc_descr_ref descr, *descr_tail;
- unsigned HOST_WIDE_INT decl_size;
- rtx varloc;
- enum var_init_status initialized;
- if (DECL_SIZE (decl) == NULL
- || !tree_fits_uhwi_p (DECL_SIZE (decl)))
- return NULL;
- decl_size = tree_to_uhwi (DECL_SIZE (decl));
- descr = NULL;
- descr_tail = &descr;
- for (p = loc; p; p = XEXP (p, 1))
- {
- unsigned HOST_WIDE_INT bitsize = decl_piece_bitsize (p);
- rtx loc_note = *decl_piece_varloc_ptr (p);
- dw_loc_descr_ref cur_descr;
- dw_loc_descr_ref *tail, last = NULL;
- unsigned HOST_WIDE_INT opsize = 0;
- if (loc_note == NULL_RTX
- || NOTE_VAR_LOCATION_LOC (loc_note) == NULL_RTX)
- {
- padsize += bitsize;
- continue;
- }
- initialized = NOTE_VAR_LOCATION_STATUS (loc_note);
- varloc = NOTE_VAR_LOCATION (loc_note);
- cur_descr = dw_loc_list_1 (decl, varloc, 2, initialized);
- if (cur_descr == NULL)
- {
- padsize += bitsize;
- continue;
- }
- /* Check that cur_descr either doesn't use
- DW_OP_*piece operations, or their sum is equal
- to bitsize. Otherwise we can't embed it. */
- for (tail = &cur_descr; *tail != NULL;
- tail = &(*tail)->dw_loc_next)
- if ((*tail)->dw_loc_opc == DW_OP_piece)
- {
- opsize += (*tail)->dw_loc_oprnd1.v.val_unsigned
- * BITS_PER_UNIT;
- last = *tail;
- }
- else if ((*tail)->dw_loc_opc == DW_OP_bit_piece)
- {
- opsize += (*tail)->dw_loc_oprnd1.v.val_unsigned;
- last = *tail;
- }
- if (last != NULL && opsize != bitsize)
- {
- padsize += bitsize;
- /* Discard the current piece of the descriptor and release any
- addr_table entries it uses. */
- remove_loc_list_addr_table_entries (cur_descr);
- continue;
- }
- /* If there is a hole, add DW_OP_*piece after empty DWARF
- expression, which means that those bits are optimized out. */
- if (padsize)
- {
- if (padsize > decl_size)
- {
- remove_loc_list_addr_table_entries (cur_descr);
- goto discard_descr;
- }
- decl_size -= padsize;
- *descr_tail = new_loc_descr_op_bit_piece (padsize, 0);
- if (*descr_tail == NULL)
- {
- remove_loc_list_addr_table_entries (cur_descr);
- goto discard_descr;
- }
- descr_tail = &(*descr_tail)->dw_loc_next;
- padsize = 0;
- }
- *descr_tail = cur_descr;
- descr_tail = tail;
- if (bitsize > decl_size)
- goto discard_descr;
- decl_size -= bitsize;
- if (last == NULL)
- {
- HOST_WIDE_INT offset = 0;
- if (GET_CODE (varloc) == VAR_LOCATION
- && GET_CODE (PAT_VAR_LOCATION_LOC (varloc)) != PARALLEL)
- {
- varloc = PAT_VAR_LOCATION_LOC (varloc);
- if (GET_CODE (varloc) == EXPR_LIST)
- varloc = XEXP (varloc, 0);
- }
- do
- {
- if (GET_CODE (varloc) == CONST
- || GET_CODE (varloc) == SIGN_EXTEND
- || GET_CODE (varloc) == ZERO_EXTEND)
- varloc = XEXP (varloc, 0);
- else if (GET_CODE (varloc) == SUBREG)
- varloc = SUBREG_REG (varloc);
- else
- break;
- }
- while (1);
- /* DW_OP_bit_size offset should be zero for register
- or implicit location descriptions and empty location
- descriptions, but for memory addresses needs big endian
- adjustment. */
- if (MEM_P (varloc))
- {
- unsigned HOST_WIDE_INT memsize
- = MEM_SIZE (varloc) * BITS_PER_UNIT;
- if (memsize != bitsize)
- {
- if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
- && (memsize > BITS_PER_WORD || bitsize > BITS_PER_WORD))
- goto discard_descr;
- if (memsize < bitsize)
- goto discard_descr;
- if (BITS_BIG_ENDIAN)
- offset = memsize - bitsize;
- }
- }
- *descr_tail = new_loc_descr_op_bit_piece (bitsize, offset);
- if (*descr_tail == NULL)
- goto discard_descr;
- descr_tail = &(*descr_tail)->dw_loc_next;
- }
- }
- /* If there were any non-empty expressions, add padding till the end of
- the decl. */
- if (descr != NULL && decl_size != 0)
- {
- *descr_tail = new_loc_descr_op_bit_piece (decl_size, 0);
- if (*descr_tail == NULL)
- goto discard_descr;
- }
- return descr;
- discard_descr:
- /* Discard the descriptor and release any addr_table entries it uses. */
- remove_loc_list_addr_table_entries (descr);
- return NULL;
- }
- /* Return the dwarf representation of the location list LOC_LIST of
- DECL. WANT_ADDRESS has the same meaning as in loc_list_from_tree
- function. */
- static dw_loc_list_ref
- dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
- {
- const char *endname, *secname;
- rtx varloc;
- enum var_init_status initialized;
- struct var_loc_node *node;
- dw_loc_descr_ref descr;
- char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
- dw_loc_list_ref list = NULL;
- dw_loc_list_ref *listp = &list;
- /* Now that we know what section we are using for a base,
- actually construct the list of locations.
- The first location information is what is passed to the
- function that creates the location list, and the remaining
- locations just get added on to that list.
- Note that we only know the start address for a location
- (IE location changes), so to build the range, we use
- the range [current location start, next location start].
- This means we have to special case the last node, and generate
- a range of [last location start, end of function label]. */
- secname = secname_for_decl (decl);
- for (node = loc_list->first; node; node = node->next)
- if (GET_CODE (node->loc) == EXPR_LIST
- || NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX)
- {
- if (GET_CODE (node->loc) == EXPR_LIST)
- {
- /* This requires DW_OP_{,bit_}piece, which is not usable
- inside DWARF expressions. */
- if (want_address != 2)
- continue;
- descr = dw_sra_loc_expr (decl, node->loc);
- if (descr == NULL)
- continue;
- }
- else
- {
- initialized = NOTE_VAR_LOCATION_STATUS (node->loc);
- varloc = NOTE_VAR_LOCATION (node->loc);
- descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
- }
- if (descr)
- {
- bool range_across_switch = false;
- /* If section switch happens in between node->label
- and node->next->label (or end of function) and
- we can't emit it as a single entry list,
- emit two ranges, first one ending at the end
- of first partition and second one starting at the
- beginning of second partition. */
- if (node == loc_list->last_before_switch
- && (node != loc_list->first || loc_list->first->next)
- && current_function_decl)
- {
- endname = cfun->fde->dw_fde_end;
- range_across_switch = true;
- }
- /* The variable has a location between NODE->LABEL and
- NODE->NEXT->LABEL. */
- else if (node->next)
- endname = node->next->label;
- /* If the variable has a location at the last label
- it keeps its location until the end of function. */
- else if (!current_function_decl)
- endname = text_end_label;
- else
- {
- ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
- current_function_funcdef_no);
- endname = ggc_strdup (label_id);
- }
- *listp = new_loc_list (descr, node->label, endname, secname);
- if (TREE_CODE (decl) == PARM_DECL
- && node == loc_list->first
- && NOTE_P (node->loc)
- && strcmp (node->label, endname) == 0)
- (*listp)->force = true;
- listp = &(*listp)->dw_loc_next;
- if (range_across_switch)
- {
- if (GET_CODE (node->loc) == EXPR_LIST)
- descr = dw_sra_loc_expr (decl, node->loc);
- else
- {
- initialized = NOTE_VAR_LOCATION_STATUS (node->loc);
- varloc = NOTE_VAR_LOCATION (node->loc);
- descr = dw_loc_list_1 (decl, varloc, want_address,
- initialized);
- }
- gcc_assert (descr);
- /* The variable has a location between NODE->LABEL and
- NODE->NEXT->LABEL. */
- if (node->next)
- endname = node->next->label;
- else
- endname = cfun->fde->dw_fde_second_end;
- *listp = new_loc_list (descr,
- cfun->fde->dw_fde_second_begin,
- endname, secname);
- listp = &(*listp)->dw_loc_next;
- }
- }
- }
- /* Try to avoid the overhead of a location list emitting a location
- expression instead, but only if we didn't have more than one
- location entry in the first place. If some entries were not
- representable, we don't want to pretend a single entry that was
- applies to the entire scope in which the variable is
- available. */
- if (list && loc_list->first->next)
- gen_llsym (list);
- return list;
- }
- /* Return if the loc_list has only single element and thus can be represented
- as location description. */
- static bool
- single_element_loc_list_p (dw_loc_list_ref list)
- {
- gcc_assert (!list->dw_loc_next || list->ll_symbol);
- return !list->ll_symbol;
- }
- /* To each location in list LIST add loc descr REF. */
- static void
- add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
- {
- dw_loc_descr_ref copy;
- add_loc_descr (&list->expr, ref);
- list = list->dw_loc_next;
- while (list)
- {
- copy = ggc_alloc<dw_loc_descr_node> ();
- memcpy (copy, ref, sizeof (dw_loc_descr_node));
- add_loc_descr (&list->expr, copy);
- while (copy->dw_loc_next)
- {
- dw_loc_descr_ref new_copy = ggc_alloc<dw_loc_descr_node> ();
- memcpy (new_copy, copy->dw_loc_next, sizeof (dw_loc_descr_node));
- copy->dw_loc_next = new_copy;
- copy = new_copy;
- }
- list = list->dw_loc_next;
- }
- }
- /* Given two lists RET and LIST
- produce location list that is result of adding expression in LIST
- to expression in RET on each position in program.
- Might be destructive on both RET and LIST.
- TODO: We handle only simple cases of RET or LIST having at most one
- element. General case would inolve sorting the lists in program order
- and merging them that will need some additional work.
- Adding that will improve quality of debug info especially for SRA-ed
- structures. */
- static void
- add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list)
- {
- if (!list)
- return;
- if (!*ret)
- {
- *ret = list;
- return;
- }
- if (!list->dw_loc_next)
- {
- add_loc_descr_to_each (*ret, list->expr);
- return;
- }
- if (!(*ret)->dw_loc_next)
- {
- add_loc_descr_to_each (list, (*ret)->expr);
- *ret = list;
- return;
- }
- expansion_failed (NULL_TREE, NULL_RTX,
- "Don't know how to merge two non-trivial"
- " location lists.\n");
- *ret = NULL;
- return;
- }
- /* LOC is constant expression. Try a luck, look it up in constant
- pool and return its loc_descr of its address. */
- static dw_loc_descr_ref
- cst_pool_loc_descr (tree loc)
- {
- /* Get an RTL for this, if something has been emitted. */
- rtx rtl = lookup_constant_def (loc);
- if (!rtl || !MEM_P (rtl))
- {
- gcc_assert (!rtl);
- return 0;
- }
- gcc_assert (GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF);
- /* TODO: We might get more coverage if we was actually delaying expansion
- of all expressions till end of compilation when constant pools are fully
- populated. */
- if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (XEXP (rtl, 0))))
- {
- expansion_failed (loc, NULL_RTX,
- "CST value in contant pool but not marked.");
- return 0;
- }
- return mem_loc_descriptor (XEXP (rtl, 0), get_address_mode (rtl),
- GET_MODE (rtl), VAR_INIT_STATUS_INITIALIZED);
- }
- /* Return dw_loc_list representing address of addr_expr LOC
- by looking for inner INDIRECT_REF expression and turning
- it into simple arithmetics.
- See loc_list_from_tree for the meaning of CONTEXT. */
- static dw_loc_list_ref
- loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev,
- const loc_descr_context *context)
- {
- tree obj, offset;
- HOST_WIDE_INT bitsize, bitpos, bytepos;
- machine_mode mode;
- int unsignedp, volatilep = 0;
- dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
- obj = get_inner_reference (TREE_OPERAND (loc, 0),
- &bitsize, &bitpos, &offset, &mode,
- &unsignedp, &volatilep, false);
- STRIP_NOPS (obj);
- if (bitpos % BITS_PER_UNIT)
- {
- expansion_failed (loc, NULL_RTX, "bitfield access");
- return 0;
- }
- if (!INDIRECT_REF_P (obj))
- {
- expansion_failed (obj,
- NULL_RTX, "no indirect ref in inner refrence");
- return 0;
- }
- if (!offset && !bitpos)
- list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1,
- context);
- else if (toplev
- && int_size_in_bytes (TREE_TYPE (loc)) <= DWARF2_ADDR_SIZE
- && (dwarf_version >= 4 || !dwarf_strict))
- {
- list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0, context);
- if (!list_ret)
- return 0;
- if (offset)
- {
- /* Variable offset. */
- list_ret1 = loc_list_from_tree (offset, 0, context);
- if (list_ret1 == 0)
- return 0;
- add_loc_list (&list_ret, list_ret1);
- if (!list_ret)
- return 0;
- add_loc_descr_to_each (list_ret,
- new_loc_descr (DW_OP_plus, 0, 0));
- }
- bytepos = bitpos / BITS_PER_UNIT;
- if (bytepos > 0)
- add_loc_descr_to_each (list_ret,
- new_loc_descr (DW_OP_plus_uconst,
- bytepos, 0));
- else if (bytepos < 0)
- loc_list_plus_const (list_ret, bytepos);
- add_loc_descr_to_each (list_ret,
- new_loc_descr (DW_OP_stack_value, 0, 0));
- }
- return list_ret;
- }
- /* Helper structure for location descriptions generation. */
- struct loc_descr_context
- {
- /* The type that is implicitly referenced by DW_OP_push_object_address, or
- NULL_TREE if DW_OP_push_object_address in invalid for this location
- description. This is used when processing PLACEHOLDER_EXPR nodes. */
- tree context_type;
- /* The ..._DECL node that should be translated as a
- DW_OP_push_object_address operation. */
- tree base_decl;
- };
- /* Generate Dwarf location list representing LOC.
- If WANT_ADDRESS is false, expression computing LOC will be computed
- If WANT_ADDRESS is 1, expression computing address of LOC will be returned
- if WANT_ADDRESS is 2, expression computing address useable in location
- will be returned (i.e. DW_OP_reg can be used
- to refer to register values).
- CONTEXT provides information to customize the location descriptions
- generation. Its context_type field specifies what type is implicitly
- referenced by DW_OP_push_object_address. If it is NULL_TREE, this operation
- will not be generated.
- If CONTEXT is NULL, the behavior is the same as if both context_type and
- base_decl fields were NULL_TREE. */
- static dw_loc_list_ref
- loc_list_from_tree (tree loc, int want_address,
- const struct loc_descr_context *context)
- {
- dw_loc_descr_ref ret = NULL, ret1 = NULL;
- dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
- int have_address = 0;
- enum dwarf_location_atom op;
- /* ??? Most of the time we do not take proper care for sign/zero
- extending the values properly. Hopefully this won't be a real
- problem... */
- if (context != NULL
- && context->base_decl == loc
- && want_address == 0)
- {
- if (dwarf_version >= 3 || !dwarf_strict)
- return new_loc_list (new_loc_descr (DW_OP_push_object_address, 0, 0),
- NULL, NULL, NULL);
- else
- return NULL;
- }
- switch (TREE_CODE (loc))
- {
- case ERROR_MARK:
- expansion_failed (loc, NULL_RTX, "ERROR_MARK");
- return 0;
- case PLACEHOLDER_EXPR:
- /* This case involves extracting fields from an object to determine the
- position of other fields. It is supposed to appear only as the first
- operand of COMPONENT_REF nodes and to reference precisely the type
- that the context allows. */
- if (context != NULL
- && TREE_TYPE (loc) == context->context_type
- && want_address >= 1)
- {
- if (dwarf_version >= 3 || !dwarf_strict)
- {
- ret = new_loc_descr (DW_OP_push_object_address, 0, 0);
- have_address = 1;
- break;
- }
- else
- return NULL;
- }
- else
- expansion_failed (loc, NULL_RTX,
- "PLACEHOLDER_EXPR for an unexpected type");
- break;
- case CALL_EXPR:
- expansion_failed (loc, NULL_RTX, "CALL_EXPR");
- /* There are no opcodes for these operations. */
- return 0;
- case PREINCREMENT_EXPR:
- case PREDECREMENT_EXPR:
- case POSTINCREMENT_EXPR:
- case POSTDECREMENT_EXPR:
- expansion_failed (loc, NULL_RTX, "PRE/POST INDCREMENT/DECREMENT");
- /* There are no opcodes for these operations. */
- return 0;
- case ADDR_EXPR:
- /* If we already want an address, see if there is INDIRECT_REF inside
- e.g. for &this->field. */
- if (want_address)
- {
- list_ret = loc_list_for_address_of_addr_expr_of_indirect_ref
- (loc, want_address == 2, context);
- if (list_ret)
- have_address = 1;
- else if (decl_address_ip_invariant_p (TREE_OPERAND (loc, 0))
- && (ret = cst_pool_loc_descr (loc)))
- have_address = 1;
- }
- /* Otherwise, process the argument and look for the address. */
- if (!list_ret && !ret)
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1, context);
- else
- {
- if (want_address)
- expansion_failed (loc, NULL_RTX, "need address of ADDR_EXPR");
- return NULL;
- }
- break;
- case VAR_DECL:
- if (DECL_THREAD_LOCAL_P (loc))
- {
- rtx rtl;
- enum dwarf_location_atom tls_op;
- enum dtprel_bool dtprel = dtprel_false;
- if (targetm.have_tls)
- {
- /* If this is not defined, we have no way to emit the
- data. */
- if (!targetm.asm_out.output_dwarf_dtprel)
- return 0;
- /* The way DW_OP_GNU_push_tls_address is specified, we
- can only look up addresses of objects in the current
- module. We used DW_OP_addr as first op, but that's
- wrong, because DW_OP_addr is relocated by the debug
- info consumer, while DW_OP_GNU_push_tls_address
- operand shouldn't be. */
- if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
- return 0;
- dtprel = dtprel_true;
- tls_op = DW_OP_GNU_push_tls_address;
- }
- else
- {
- if (!targetm.emutls.debug_form_tls_address
- || !(dwarf_version >= 3 || !dwarf_strict))
- return 0;
- /* We stuffed the control variable into the DECL_VALUE_EXPR
- to signal (via DECL_HAS_VALUE_EXPR_P) that the decl should
- no longer appear in gimple code. We used the control
- variable in specific so that we could pick it up here. */
- loc = DECL_VALUE_EXPR (loc);
- tls_op = DW_OP_form_tls_address;
- }
- rtl = rtl_for_decl_location (loc);
- if (rtl == NULL_RTX)
- return 0;
- if (!MEM_P (rtl))
- return 0;
- rtl = XEXP (rtl, 0);
- if (! CONSTANT_P (rtl))
- return 0;
- ret = new_addr_loc_descr (rtl, dtprel);
- ret1 = new_loc_descr (tls_op, 0, 0);
- add_loc_descr (&ret, ret1);
- have_address = 1;
- break;
- }
- /* FALLTHRU */
- case PARM_DECL:
- case RESULT_DECL:
- if (DECL_HAS_VALUE_EXPR_P (loc))
- return loc_list_from_tree (DECL_VALUE_EXPR (loc),
- want_address, context);
- /* FALLTHRU */
- case FUNCTION_DECL:
- {
- rtx rtl;
- var_loc_list *loc_list = lookup_decl_loc (loc);
- if (loc_list && loc_list->first)
- {
- list_ret = dw_loc_list (loc_list, loc, want_address);
- have_address = want_address != 0;
- break;
- }
- rtl = rtl_for_decl_location (loc);
- if (rtl == NULL_RTX)
- {
- expansion_failed (loc, NULL_RTX, "DECL has no RTL");
- return 0;
- }
- else if (CONST_INT_P (rtl))
- {
- HOST_WIDE_INT val = INTVAL (rtl);
- if (TYPE_UNSIGNED (TREE_TYPE (loc)))
- val &= GET_MODE_MASK (DECL_MODE (loc));
- ret = int_loc_descriptor (val);
- }
- else if (GET_CODE (rtl) == CONST_STRING)
- {
- expansion_failed (loc, NULL_RTX, "CONST_STRING");
- return 0;
- }
- else if (CONSTANT_P (rtl) && const_ok_for_output (rtl))
- ret = new_addr_loc_descr (rtl, dtprel_false);
- else
- {
- machine_mode mode, mem_mode;
- /* Certain constructs can only be represented at top-level. */
- if (want_address == 2)
- {
- ret = loc_descriptor (rtl, VOIDmode,
- VAR_INIT_STATUS_INITIALIZED);
- have_address = 1;
- }
- else
- {
- mode = GET_MODE (rtl);
- mem_mode = VOIDmode;
- if (MEM_P (rtl))
- {
- mem_mode = mode;
- mode = get_address_mode (rtl);
- rtl = XEXP (rtl, 0);
- have_address = 1;
- }
- ret = mem_loc_descriptor (rtl, mode, mem_mode,
- VAR_INIT_STATUS_INITIALIZED);
- }
- if (!ret)
- expansion_failed (loc, rtl,
- "failed to produce loc descriptor for rtl");
- }
- }
- break;
- case MEM_REF:
- if (!integer_zerop (TREE_OPERAND (loc, 1)))
- {
- have_address = 1;
- goto do_plus;
- }
- /* Fallthru. */
- case INDIRECT_REF:
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
- have_address = 1;
- break;
- case TARGET_MEM_REF:
- case SSA_NAME:
- case DEBUG_EXPR_DECL:
- return NULL;
- case COMPOUND_EXPR:
- return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address, context);
- CASE_CONVERT:
- case VIEW_CONVERT_EXPR:
- case SAVE_EXPR:
- case MODIFY_EXPR:
- return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address, context);
- case COMPONENT_REF:
- case BIT_FIELD_REF:
- case ARRAY_REF:
- case ARRAY_RANGE_REF:
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- {
- tree obj, offset;
- HOST_WIDE_INT bitsize, bitpos, bytepos;
- machine_mode mode;
- int unsignedp, volatilep = 0;
- obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
- &unsignedp, &volatilep, false);
- gcc_assert (obj != loc);
- list_ret = loc_list_from_tree (obj,
- want_address == 2
- && !bitpos && !offset ? 2 : 1,
- context);
- /* TODO: We can extract value of the small expression via shifting even
- for nonzero bitpos. */
- if (list_ret == 0)
- return 0;
- if (bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0)
- {
- expansion_failed (loc, NULL_RTX,
- "bitfield access");
- return 0;
- }
- if (offset != NULL_TREE)
- {
- /* Variable offset. */
- list_ret1 = loc_list_from_tree (offset, 0, context);
- if (list_ret1 == 0)
- return 0;
- add_loc_list (&list_ret, list_ret1);
- if (!list_ret)
- return 0;
- add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus, 0, 0));
- }
- bytepos = bitpos / BITS_PER_UNIT;
- if (bytepos > 0)
- add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0));
- else if (bytepos < 0)
- loc_list_plus_const (list_ret, bytepos);
- have_address = 1;
- break;
- }
- case INTEGER_CST:
- if ((want_address || !tree_fits_shwi_p (loc))
- && (ret = cst_pool_loc_descr (loc)))
- have_address = 1;
- else if (want_address == 2
- && tree_fits_shwi_p (loc)
- && (ret = address_of_int_loc_descriptor
- (int_size_in_bytes (TREE_TYPE (loc)),
- tree_to_shwi (loc))))
- have_address = 1;
- else if (tree_fits_shwi_p (loc))
- ret = int_loc_descriptor (tree_to_shwi (loc));
- else
- {
- expansion_failed (loc, NULL_RTX,
- "Integer operand is not host integer");
- return 0;
- }
- break;
- case CONSTRUCTOR:
- case REAL_CST:
- case STRING_CST:
- case COMPLEX_CST:
- if ((ret = cst_pool_loc_descr (loc)))
- have_address = 1;
- else
- /* We can construct small constants here using int_loc_descriptor. */
- expansion_failed (loc, NULL_RTX,
- "constructor or constant not in constant pool");
- break;
- case TRUTH_AND_EXPR:
- case TRUTH_ANDIF_EXPR:
- case BIT_AND_EXPR:
- op = DW_OP_and;
- goto do_binop;
- case TRUTH_XOR_EXPR:
- case BIT_XOR_EXPR:
- op = DW_OP_xor;
- goto do_binop;
- case TRUTH_OR_EXPR:
- case TRUTH_ORIF_EXPR:
- case BIT_IOR_EXPR:
- op = DW_OP_or;
- goto do_binop;
- case FLOOR_DIV_EXPR:
- case CEIL_DIV_EXPR:
- case ROUND_DIV_EXPR:
- case TRUNC_DIV_EXPR:
- if (TYPE_UNSIGNED (TREE_TYPE (loc)))
- return 0;
- op = DW_OP_div;
- goto do_binop;
- case MINUS_EXPR:
- op = DW_OP_minus;
- goto do_binop;
- case FLOOR_MOD_EXPR:
- case CEIL_MOD_EXPR:
- case ROUND_MOD_EXPR:
- case TRUNC_MOD_EXPR:
- if (TYPE_UNSIGNED (TREE_TYPE (loc)))
- {
- op = DW_OP_mod;
- goto do_binop;
- }
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
- list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0, context);
- if (list_ret == 0 || list_ret1 == 0)
- return 0;
- add_loc_list (&list_ret, list_ret1);
- if (list_ret == 0)
- return 0;
- add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0));
- add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_over, 0, 0));
- add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_div, 0, 0));
- add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_mul, 0, 0));
- add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_minus, 0, 0));
- break;
- case MULT_EXPR:
- op = DW_OP_mul;
- goto do_binop;
- case LSHIFT_EXPR:
- op = DW_OP_shl;
- goto do_binop;
- case RSHIFT_EXPR:
- op = (TYPE_UNSIGNED (TREE_TYPE (loc)) ? DW_OP_shr : DW_OP_shra);
- goto do_binop;
- case POINTER_PLUS_EXPR:
- case PLUS_EXPR:
- do_plus:
- if (tree_fits_shwi_p (TREE_OPERAND (loc, 1)))
- {
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
- if (list_ret == 0)
- return 0;
- loc_list_plus_const (list_ret, tree_to_shwi (TREE_OPERAND (loc, 1)));
- break;
- }
- op = DW_OP_plus;
- goto do_binop;
- case LE_EXPR:
- if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
- return 0;
- op = DW_OP_le;
- goto do_binop;
- case GE_EXPR:
- if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
- return 0;
- op = DW_OP_ge;
- goto do_binop;
- case LT_EXPR:
- if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
- return 0;
- op = DW_OP_lt;
- goto do_binop;
- case GT_EXPR:
- if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
- return 0;
- op = DW_OP_gt;
- goto do_binop;
- case EQ_EXPR:
- op = DW_OP_eq;
- goto do_binop;
- case NE_EXPR:
- op = DW_OP_ne;
- goto do_binop;
- do_binop:
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
- list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0, context);
- if (list_ret == 0 || list_ret1 == 0)
- return 0;
- add_loc_list (&list_ret, list_ret1);
- if (list_ret == 0)
- return 0;
- add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0));
- break;
- case TRUTH_NOT_EXPR:
- case BIT_NOT_EXPR:
- op = DW_OP_not;
- goto do_unop;
- case ABS_EXPR:
- op = DW_OP_abs;
- goto do_unop;
- case NEGATE_EXPR:
- op = DW_OP_neg;
- goto do_unop;
- do_unop:
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
- if (list_ret == 0)
- return 0;
- add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0));
- break;
- case MIN_EXPR:
- case MAX_EXPR:
- {
- const enum tree_code code =
- TREE_CODE (loc) == MIN_EXPR ? GT_EXPR : LT_EXPR;
- loc = build3 (COND_EXPR, TREE_TYPE (loc),
- build2 (code, integer_type_node,
- TREE_OPERAND (loc, 0), TREE_OPERAND (loc, 1)),
- TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
- }
- /* ... fall through ... */
- case COND_EXPR:
- {
- dw_loc_descr_ref lhs
- = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0, context);
- dw_loc_list_ref rhs
- = loc_list_from_tree (TREE_OPERAND (loc, 2), 0, context);
- dw_loc_descr_ref bra_node, jump_node, tmp;
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
- if (list_ret == 0 || lhs == 0 || rhs == 0)
- return 0;
- bra_node = new_loc_descr (DW_OP_bra, 0, 0);
- add_loc_descr_to_each (list_ret, bra_node);
- add_loc_list (&list_ret, rhs);
- jump_node = new_loc_descr (DW_OP_skip, 0, 0);
- add_loc_descr_to_each (list_ret, jump_node);
- add_loc_descr_to_each (list_ret, lhs);
- bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
- bra_node->dw_loc_oprnd1.v.val_loc = lhs;
- /* ??? Need a node to point the skip at. Use a nop. */
- tmp = new_loc_descr (DW_OP_nop, 0, 0);
- add_loc_descr_to_each (list_ret, tmp);
- jump_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
- jump_node->dw_loc_oprnd1.v.val_loc = tmp;
- }
- break;
- case FIX_TRUNC_EXPR:
- return 0;
- default:
- /* Leave front-end specific codes as simply unknown. This comes
- up, for instance, with the C STMT_EXPR. */
- if ((unsigned int) TREE_CODE (loc)
- >= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
- {
- expansion_failed (loc, NULL_RTX,
- "language specific tree node");
- return 0;
- }
- #ifdef ENABLE_CHECKING
- /* Otherwise this is a generic code; we should just lists all of
- these explicitly. We forgot one. */
- gcc_unreachable ();
- #else
- /* In a release build, we want to degrade gracefully: better to
- generate incomplete debugging information than to crash. */
- return NULL;
- #endif
- }
- if (!ret && !list_ret)
- return 0;
- if (want_address == 2 && !have_address
- && (dwarf_version >= 4 || !dwarf_strict))
- {
- if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE)
- {
- expansion_failed (loc, NULL_RTX,
- "DWARF address size mismatch");
- return 0;
- }
- if (ret)
- add_loc_descr (&ret, new_loc_descr (DW_OP_stack_value, 0, 0));
- else
- add_loc_descr_to_each (list_ret,
- new_loc_descr (DW_OP_stack_value, 0, 0));
- have_address = 1;
- }
- /* Show if we can't fill the request for an address. */
- if (want_address && !have_address)
- {
- expansion_failed (loc, NULL_RTX,
- "Want address and only have value");
- return 0;
- }
- gcc_assert (!ret || !list_ret);
- /* If we've got an address and don't want one, dereference. */
- if (!want_address && have_address)
- {
- HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
- if (size > DWARF2_ADDR_SIZE || size == -1)
- {
- expansion_failed (loc, NULL_RTX,
- "DWARF address size mismatch");
- return 0;
- }
- else if (size == DWARF2_ADDR_SIZE)
- op = DW_OP_deref;
- else
- op = DW_OP_deref_size;
- if (ret)
- add_loc_descr (&ret, new_loc_descr (op, size, 0));
- else
- add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0));
- }
- if (ret)
- list_ret = new_loc_list (ret, NULL, NULL, NULL);
- return list_ret;
- }
- /* Same as above but return only single location expression. */
- static dw_loc_descr_ref
- loc_descriptor_from_tree (tree loc, int want_address,
- const struct loc_descr_context *context)
- {
- dw_loc_list_ref ret = loc_list_from_tree (loc, want_address, context);
- if (!ret)
- return NULL;
- if (ret->dw_loc_next)
- {
- expansion_failed (loc, NULL_RTX,
- "Location list where only loc descriptor needed");
- return NULL;
- }
- return ret->expr;
- }
- /* Given a value, round it up to the lowest multiple of `boundary'
- which is not less than the value itself. */
- static inline HOST_WIDE_INT
- ceiling (HOST_WIDE_INT value, unsigned int boundary)
- {
- return (((value + boundary - 1) / boundary) * boundary);
- }
- /* Given a pointer to what is assumed to be a FIELD_DECL node, return a
- pointer to the declared type for the relevant field variable, or return
- `integer_type_node' if the given node turns out to be an
- ERROR_MARK node. */
- static inline tree
- field_type (const_tree decl)
- {
- tree type;
- if (TREE_CODE (decl) == ERROR_MARK)
- return integer_type_node;
- type = DECL_BIT_FIELD_TYPE (decl);
- if (type == NULL_TREE)
- type = TREE_TYPE (decl);
- return type;
- }
- /* Given a pointer to a tree node, return the alignment in bits for
- it, or else return BITS_PER_WORD if the node actually turns out to
- be an ERROR_MARK node. */
- static inline unsigned
- simple_type_align_in_bits (const_tree type)
- {
- return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;
- }
- static inline unsigned
- simple_decl_align_in_bits (const_tree decl)
- {
- return (TREE_CODE (decl) != ERROR_MARK) ? DECL_ALIGN (decl) : BITS_PER_WORD;
- }
- /* Return the result of rounding T up to ALIGN. */
- static inline offset_int
- round_up_to_align (const offset_int &t, unsigned int align)
- {
- return wi::udiv_trunc (t + align - 1, align) * align;
- }
- /* Given a pointer to a FIELD_DECL, compute and return the byte offset of the
- lowest addressed byte of the "containing object" for the given FIELD_DECL,
- or return 0 if we are unable to determine what that offset is, either
- because the argument turns out to be a pointer to an ERROR_MARK node, or
- because the offset is actually variable. (We can't handle the latter case
- just yet). */
- static HOST_WIDE_INT
- field_byte_offset (const_tree decl)
- {
- offset_int object_offset_in_bits;
- offset_int object_offset_in_bytes;
- offset_int bitpos_int;
- if (TREE_CODE (decl) == ERROR_MARK)
- return 0;
- gcc_assert (TREE_CODE (decl) == FIELD_DECL);
- /* We cannot yet cope with fields whose positions are variable, so
- for now, when we see such things, we simply return 0. Someday, we may
- be able to handle such cases, but it will be damn difficult. */
- if (TREE_CODE (bit_position (decl)) != INTEGER_CST)
- return 0;
- bitpos_int = wi::to_offset (bit_position (decl));
- #ifdef PCC_BITFIELD_TYPE_MATTERS
- if (PCC_BITFIELD_TYPE_MATTERS)
- {
- tree type;
- tree field_size_tree;
- offset_int deepest_bitpos;
- offset_int field_size_in_bits;
- unsigned int type_align_in_bits;
- unsigned int decl_align_in_bits;
- offset_int type_size_in_bits;
- type = field_type (decl);
- type_size_in_bits = offset_int_type_size_in_bits (type);
- type_align_in_bits = simple_type_align_in_bits (type);
- field_size_tree = DECL_SIZE (decl);
- /* The size could be unspecified if there was an error, or for
- a flexible array member. */
- if (!field_size_tree)
- field_size_tree = bitsize_zero_node;
- /* If the size of the field is not constant, use the type size. */
- if (TREE_CODE (field_size_tree) == INTEGER_CST)
- field_size_in_bits = wi::to_offset (field_size_tree);
- else
- field_size_in_bits = type_size_in_bits;
- decl_align_in_bits = simple_decl_align_in_bits (decl);
- /* The GCC front-end doesn't make any attempt to keep track of the
- starting bit offset (relative to the start of the containing
- structure type) of the hypothetical "containing object" for a
- bit-field. Thus, when computing the byte offset value for the
- start of the "containing object" of a bit-field, we must deduce
- this information on our own. This can be rather tricky to do in
- some cases. For example, handling the following structure type
- definition when compiling for an i386/i486 target (which only
- aligns long long's to 32-bit boundaries) can be very tricky:
- struct S { int field1; long long field2:31; };
- Fortunately, there is a simple rule-of-thumb which can be used
- in such cases. When compiling for an i386/i486, GCC will
- allocate 8 bytes for the structure shown above. It decides to
- do this based upon one simple rule for bit-field allocation.
- GCC allocates each "containing object" for each bit-field at
- the first (i.e. lowest addressed) legitimate alignment boundary
- (based upon the required minimum alignment for the declared
- type of the field) which it can possibly use, subject to the
- condition that there is still enough available space remaining
- in the containing object (when allocated at the selected point)
- to fully accommodate all of the bits of the bit-field itself.
- This simple rule makes it obvious why GCC allocates 8 bytes for
- each object of the structure type shown above. When looking
- for a place to allocate the "containing object" for `field2',
- the compiler simply tries to allocate a 64-bit "containing
- object" at each successive 32-bit boundary (starting at zero)
- until it finds a place to allocate that 64- bit field such that
- at least 31 contiguous (and previously unallocated) bits remain
- within that selected 64 bit field. (As it turns out, for the
- example above, the compiler finds it is OK to allocate the
- "containing object" 64-bit field at bit-offset zero within the
- structure type.)
- Here we attempt to work backwards from the limited set of facts
- we're given, and we try to deduce from those facts, where GCC
- must have believed that the containing object started (within
- the structure type). The value we deduce is then used (by the
- callers of this routine) to generate DW_AT_location and
- DW_AT_bit_offset attributes for fields (both bit-fields and, in
- the case of DW_AT_location, regular fields as well). */
- /* Figure out the bit-distance from the start of the structure to
- the "deepest" bit of the bit-field. */
- deepest_bitpos = bitpos_int + field_size_in_bits;
- /* This is the tricky part. Use some fancy footwork to deduce
- where the lowest addressed bit of the containing object must
- be. */
- object_offset_in_bits = deepest_bitpos - type_size_in_bits;
- /* Round up to type_align by default. This works best for
- bitfields. */
- object_offset_in_bits
- = round_up_to_align (object_offset_in_bits, type_align_in_bits);
- if (wi::gtu_p (object_offset_in_bits, bitpos_int))
- {
- object_offset_in_bits = deepest_bitpos - type_size_in_bits;
- /* Round up to decl_align instead. */
- object_offset_in_bits
- = round_up_to_align (object_offset_in_bits, decl_align_in_bits);
- }
- }
- else
- #endif /* PCC_BITFIELD_TYPE_MATTERS */
- object_offset_in_bits = bitpos_int;
- object_offset_in_bytes
- = wi::lrshift (object_offset_in_bits, LOG2_BITS_PER_UNIT);
- return object_offset_in_bytes.to_shwi ();
- }
- /* The following routines define various Dwarf attributes and any data
- associated with them. */
- /* Add a location description attribute value to a DIE.
- This emits location attributes suitable for whole variables and
- whole parameters. Note that the location attributes for struct fields are
- generated by the routine `data_member_location_attribute' below. */
- static inline void
- add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
- dw_loc_list_ref descr)
- {
- if (descr == 0)
- return;
- if (single_element_loc_list_p (descr))
- add_AT_loc (die, attr_kind, descr->expr);
- else
- add_AT_loc_list (die, attr_kind, descr);
- }
- /* Add DW_AT_accessibility attribute to DIE if needed. */
- static void
- add_accessibility_attribute (dw_die_ref die, tree decl)
- {
- /* In DWARF3+ the default is DW_ACCESS_private only in DW_TAG_class_type
- children, otherwise the default is DW_ACCESS_public. In DWARF2
- the default has always been DW_ACCESS_public. */
- if (TREE_PROTECTED (decl))
- add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
- else if (TREE_PRIVATE (decl))
- {
- if (dwarf_version == 2
- || die->die_parent == NULL
- || die->die_parent->die_tag != DW_TAG_class_type)
- add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_private);
- }
- else if (dwarf_version > 2
- && die->die_parent
- && die->die_parent->die_tag == DW_TAG_class_type)
- add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
- }
- /* Attach the specialized form of location attribute used for data members of
- struct and union types. In the special case of a FIELD_DECL node which
- represents a bit-field, the "offset" part of this special location
- descriptor must indicate the distance in bytes from the lowest-addressed
- byte of the containing struct or union type to the lowest-addressed byte of
- the "containing object" for the bit-field. (See the `field_byte_offset'
- function above).
- For any given bit-field, the "containing object" is a hypothetical object
- (of some integral or enum type) within which the given bit-field lives. The
- type of this hypothetical "containing object" is always the same as the
- declared type of the individual bit-field itself (for GCC anyway... the
- DWARF spec doesn't actually mandate this). Note that it is the size (in
- bytes) of the hypothetical "containing object" which will be given in the
- DW_AT_byte_size attribute for this bit-field. (See the
- `byte_size_attribute' function below.) It is also used when calculating the
- value of the DW_AT_bit_offset attribute. (See the `bit_offset_attribute'
- function below.) */
- static void
- add_data_member_location_attribute (dw_die_ref die, tree decl)
- {
- HOST_WIDE_INT offset;
- dw_loc_descr_ref loc_descr = 0;
- if (TREE_CODE (decl) == TREE_BINFO)
- {
- /* We're working on the TAG_inheritance for a base class. */
- if (BINFO_VIRTUAL_P (decl) && is_cxx ())
- {
- /* For C++ virtual bases we can't just use BINFO_OFFSET, as they
- aren't at a fixed offset from all (sub)objects of the same
- type. We need to extract the appropriate offset from our
- vtable. The following dwarf expression means
- BaseAddr = ObAddr + *((*ObAddr) - Offset)
- This is specific to the V3 ABI, of course. */
- dw_loc_descr_ref tmp;
- /* Make a copy of the object address. */
- tmp = new_loc_descr (DW_OP_dup, 0, 0);
- add_loc_descr (&loc_descr, tmp);
- /* Extract the vtable address. */
- tmp = new_loc_descr (DW_OP_deref, 0, 0);
- add_loc_descr (&loc_descr, tmp);
- /* Calculate the address of the offset. */
- offset = tree_to_shwi (BINFO_VPTR_FIELD (decl));
- gcc_assert (offset < 0);
- tmp = int_loc_descriptor (-offset);
- add_loc_descr (&loc_descr, tmp);
- tmp = new_loc_descr (DW_OP_minus, 0, 0);
- add_loc_descr (&loc_descr, tmp);
- /* Extract the offset. */
- tmp = new_loc_descr (DW_OP_deref, 0, 0);
- add_loc_descr (&loc_descr, tmp);
- /* Add it to the object address. */
- tmp = new_loc_descr (DW_OP_plus, 0, 0);
- add_loc_descr (&loc_descr, tmp);
- }
- else
- offset = tree_to_shwi (BINFO_OFFSET (decl));
- }
- else
- offset = field_byte_offset (decl);
- if (! loc_descr)
- {
- if (dwarf_version > 2)
- {
- /* Don't need to output a location expression, just the constant. */
- if (offset < 0)
- add_AT_int (die, DW_AT_data_member_location, offset);
- else
- add_AT_unsigned (die, DW_AT_data_member_location, offset);
- return;
- }
- else
- {
- enum dwarf_location_atom op;
- /* The DWARF2 standard says that we should assume that the structure
- address is already on the stack, so we can specify a structure
- field address by using DW_OP_plus_uconst. */
- op = DW_OP_plus_uconst;
- loc_descr = new_loc_descr (op, offset, 0);
- }
- }
- add_AT_loc (die, DW_AT_data_member_location, loc_descr);
- }
- /* Writes integer values to dw_vec_const array. */
- static void
- insert_int (HOST_WIDE_INT val, unsigned int size, unsigned char *dest)
- {
- while (size != 0)
- {
- *dest++ = val & 0xff;
- val >>= 8;
- --size;
- }
- }
- /* Reads integers from dw_vec_const array. Inverse of insert_int. */
- static HOST_WIDE_INT
- extract_int (const unsigned char *src, unsigned int size)
- {
- HOST_WIDE_INT val = 0;
- src += size;
- while (size != 0)
- {
- val <<= 8;
- val |= *--src & 0xff;
- --size;
- }
- return val;
- }
- /* Writes wide_int values to dw_vec_const array. */
- static void
- insert_wide_int (const wide_int &val, unsigned char *dest, int elt_size)
- {
- int i;
- if (elt_size <= HOST_BITS_PER_WIDE_INT/BITS_PER_UNIT)
- {
- insert_int ((HOST_WIDE_INT) val.elt (0), elt_size, dest);
- return;
- }
- /* We'd have to extend this code to support odd sizes. */
- gcc_assert (elt_size % (HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT) == 0);
- int n = elt_size / (HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT);
- if (WORDS_BIG_ENDIAN)
- for (i = n - 1; i >= 0; i--)
- {
- insert_int ((HOST_WIDE_INT) val.elt (i), sizeof (HOST_WIDE_INT), dest);
- dest += sizeof (HOST_WIDE_INT);
- }
- else
- for (i = 0; i < n; i++)
- {
- insert_int ((HOST_WIDE_INT) val.elt (i), sizeof (HOST_WIDE_INT), dest);
- dest += sizeof (HOST_WIDE_INT);
- }
- }
- /* Writes floating point values to dw_vec_const array. */
- static void
- insert_float (const_rtx rtl, unsigned char *array)
- {
- REAL_VALUE_TYPE rv;
- long val[4];
- int i;
- REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
- real_to_target (val, &rv, GET_MODE (rtl));
- /* real_to_target puts 32-bit pieces in each long. Pack them. */
- for (i = 0; i < GET_MODE_SIZE (GET_MODE (rtl)) / 4; i++)
- {
- insert_int (val[i], 4, array);
- array += 4;
- }
- }
- /* Attach a DW_AT_const_value attribute for a variable or a parameter which
- does not have a "location" either in memory or in a register. These
- things can arise in GNU C when a constant is passed as an actual parameter
- to an inlined function. They can also arise in C++ where declared
- constants do not necessarily get memory "homes". */
- static bool
- add_const_value_attribute (dw_die_ref die, rtx rtl)
- {
- switch (GET_CODE (rtl))
- {
- case CONST_INT:
- {
- HOST_WIDE_INT val = INTVAL (rtl);
- if (val < 0)
- add_AT_int (die, DW_AT_const_value, val);
- else
- add_AT_unsigned (die, DW_AT_const_value, (unsigned HOST_WIDE_INT) val);
- }
- return true;
- case CONST_WIDE_INT:
- add_AT_wide (die, DW_AT_const_value,
- std::make_pair (rtl, GET_MODE (rtl)));
- return true;
- case CONST_DOUBLE:
- /* Note that a CONST_DOUBLE rtx could represent either an integer or a
- floating-point constant. A CONST_DOUBLE is used whenever the
- constant requires more than one word in order to be adequately
- represented. */
- {
- machine_mode mode = GET_MODE (rtl);
- if (TARGET_SUPPORTS_WIDE_INT == 0 && !SCALAR_FLOAT_MODE_P (mode))
- add_AT_double (die, DW_AT_const_value,
- CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
- else
- {
- unsigned int length = GET_MODE_SIZE (mode);
- unsigned char *array = ggc_vec_alloc<unsigned char> (length);
- insert_float (rtl, array);
- add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
- }
- }
- return true;
- case CONST_VECTOR:
- {
- machine_mode mode = GET_MODE (rtl);
- unsigned int elt_size = GET_MODE_UNIT_SIZE (mode);
- unsigned int length = CONST_VECTOR_NUNITS (rtl);
- unsigned char *array
- = ggc_vec_alloc<unsigned char> (length * elt_size);
- unsigned int i;
- unsigned char *p;
- machine_mode imode = GET_MODE_INNER (mode);
- switch (GET_MODE_CLASS (mode))
- {
- case MODE_VECTOR_INT:
- for (i = 0, p = array; i < length; i++, p += elt_size)
- {
- rtx elt = CONST_VECTOR_ELT (rtl, i);
- insert_wide_int (std::make_pair (elt, imode), p, elt_size);
- }
- break;
- case MODE_VECTOR_FLOAT:
- for (i = 0, p = array; i < length; i++, p += elt_size)
- {
- rtx elt = CONST_VECTOR_ELT (rtl, i);
- insert_float (elt, p);
- }
- break;
- default:
- gcc_unreachable ();
- }
- add_AT_vec (die, DW_AT_const_value, length, elt_size, array);
- }
- return true;
- case CONST_STRING:
- if (dwarf_version >= 4 || !dwarf_strict)
- {
- dw_loc_descr_ref loc_result;
- resolve_one_addr (&rtl);
- rtl_addr:
- loc_result = new_addr_loc_descr (rtl, dtprel_false);
- add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
- add_AT_loc (die, DW_AT_location, loc_result);
- vec_safe_push (used_rtx_array, rtl);
- return true;
- }
- return false;
- case CONST:
- if (CONSTANT_P (XEXP (rtl, 0)))
- return add_const_value_attribute (die, XEXP (rtl, 0));
- /* FALLTHROUGH */
- case SYMBOL_REF:
- if (!const_ok_for_output (rtl))
- return false;
- case LABEL_REF:
- if (dwarf_version >= 4 || !dwarf_strict)
- goto rtl_addr;
- return false;
- case PLUS:
- /* In cases where an inlined instance of an inline function is passed
- the address of an `auto' variable (which is local to the caller) we
- can get a situation where the DECL_RTL of the artificial local
- variable (for the inlining) which acts as a stand-in for the
- corresponding formal parameter (of the inline function) will look
- like (plus:SI (reg:SI FRAME_PTR) (const_int ...)). This is not
- exactly a compile-time constant expression, but it isn't the address
- of the (artificial) local variable either. Rather, it represents the
- *value* which the artificial local variable always has during its
- lifetime. We currently have no way to represent such quasi-constant
- values in Dwarf, so for now we just punt and generate nothing. */
- return false;
- case HIGH:
- case CONST_FIXED:
- return false;
- case MEM:
- if (GET_CODE (XEXP (rtl, 0)) == CONST_STRING
- && MEM_READONLY_P (rtl)
- && GET_MODE (rtl) == BLKmode)
- {
- add_AT_string (die, DW_AT_const_value, XSTR (XEXP (rtl, 0), 0));
- return true;
- }
- return false;
- default:
- /* No other kinds of rtx should be possible here. */
- gcc_unreachable ();
- }
- return false;
- }
- /* Determine whether the evaluation of EXPR references any variables
- or functions which aren't otherwise used (and therefore may not be
- output). */
- static tree
- reference_to_unused (tree * tp, int * walk_subtrees,
- void * data ATTRIBUTE_UNUSED)
- {
- if (! EXPR_P (*tp) && ! CONSTANT_CLASS_P (*tp))
- *walk_subtrees = 0;
- if (DECL_P (*tp) && ! TREE_PUBLIC (*tp) && ! TREE_USED (*tp)
- && ! TREE_ASM_WRITTEN (*tp))
- return *tp;
- /* ??? The C++ FE emits debug information for using decls, so
- putting gcc_unreachable here falls over. See PR31899. For now
- be conservative. */
- else if (!symtab->global_info_ready
- && (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL))
- return *tp;
- else if (TREE_CODE (*tp) == VAR_DECL)
- {
- varpool_node *node = varpool_node::get (*tp);
- if (!node || !node->definition)
- return *tp;
- }
- else if (TREE_CODE (*tp) == FUNCTION_DECL
- && (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp)))
- {
- /* The call graph machinery must have finished analyzing,
- optimizing and gimplifying the CU by now.
- So if *TP has no call graph node associated
- to it, it means *TP will not be emitted. */
- if (!cgraph_node::get (*tp))
- return *tp;
- }
- else if (TREE_CODE (*tp) == STRING_CST && !TREE_ASM_WRITTEN (*tp))
- return *tp;
- return NULL_TREE;
- }
- /* Generate an RTL constant from a decl initializer INIT with decl type TYPE,
- for use in a later add_const_value_attribute call. */
- static rtx
- rtl_for_decl_init (tree init, tree type)
- {
- rtx rtl = NULL_RTX;
- STRIP_NOPS (init);
- /* If a variable is initialized with a string constant without embedded
- zeros, build CONST_STRING. */
- if (TREE_CODE (init) == STRING_CST && TREE_CODE (type) == ARRAY_TYPE)
- {
- tree enttype = TREE_TYPE (type);
- tree domain = TYPE_DOMAIN (type);
- machine_mode mode = TYPE_MODE (enttype);
- if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == 1
- && domain
- && integer_zerop (TYPE_MIN_VALUE (domain))
- && compare_tree_int (TYPE_MAX_VALUE (domain),
- TREE_STRING_LENGTH (init) - 1) == 0
- && ((size_t) TREE_STRING_LENGTH (init)
- == strlen (TREE_STRING_POINTER (init)) + 1))
- {
- rtl = gen_rtx_CONST_STRING (VOIDmode,
- ggc_strdup (TREE_STRING_POINTER (init)));
- rtl = gen_rtx_MEM (BLKmode, rtl);
- MEM_READONLY_P (rtl) = 1;
- }
- }
- /* Other aggregates, and complex values, could be represented using
- CONCAT: FIXME! */
- else if (AGGREGATE_TYPE_P (type)
- || (TREE_CODE (init) == VIEW_CONVERT_EXPR
- && AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (init, 0))))
- || TREE_CODE (type) == COMPLEX_TYPE)
- ;
- /* Vectors only work if their mode is supported by the target.
- FIXME: generic vectors ought to work too. */
- else if (TREE_CODE (type) == VECTOR_TYPE
- && !VECTOR_MODE_P (TYPE_MODE (type)))
- ;
- /* If the initializer is something that we know will expand into an
- immediate RTL constant, expand it now. We must be careful not to
- reference variables which won't be output. */
- else if (initializer_constant_valid_p (init, type)
- && ! walk_tree (&init, reference_to_unused, NULL, NULL))
- {
- /* Convert vector CONSTRUCTOR initializers to VECTOR_CST if
- possible. */
- if (TREE_CODE (type) == VECTOR_TYPE)
- switch (TREE_CODE (init))
- {
- case VECTOR_CST:
- break;
- case CONSTRUCTOR:
- if (TREE_CONSTANT (init))
- {
- vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (init);
- bool constant_p = true;
- tree value;
- unsigned HOST_WIDE_INT ix;
- /* Even when ctor is constant, it might contain non-*_CST
- elements (e.g. { 1.0/0.0 - 1.0/0.0, 0.0 }) and those don't
- belong into VECTOR_CST nodes. */
- FOR_EACH_CONSTRUCTOR_VALUE (elts, ix, value)
- if (!CONSTANT_CLASS_P (value))
- {
- constant_p = false;
- break;
- }
- if (constant_p)
- {
- init = build_vector_from_ctor (type, elts);
- break;
- }
- }
- /* FALLTHRU */
- default:
- return NULL;
- }
- rtl = expand_expr (init, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
- /* If expand_expr returns a MEM, it wasn't immediate. */
- gcc_assert (!rtl || !MEM_P (rtl));
- }
- return rtl;
- }
- /* Generate RTL for the variable DECL to represent its location. */
- static rtx
- rtl_for_decl_location (tree decl)
- {
- rtx rtl;
- /* Here we have to decide where we are going to say the parameter "lives"
- (as far as the debugger is concerned). We only have a couple of
- choices. GCC provides us with DECL_RTL and with DECL_INCOMING_RTL.
- DECL_RTL normally indicates where the parameter lives during most of the
- activation of the function. If optimization is enabled however, this
- could be either NULL or else a pseudo-reg. Both of those cases indicate
- that the parameter doesn't really live anywhere (as far as the code
- generation parts of GCC are concerned) during most of the function's
- activation. That will happen (for example) if the parameter is never
- referenced within the function.
- We could just generate a location descriptor here for all non-NULL
- non-pseudo values of DECL_RTL and ignore all of the rest, but we can be
- a little nicer than that if we also consider DECL_INCOMING_RTL in cases
- where DECL_RTL is NULL or is a pseudo-reg.
- Note however that we can only get away with using DECL_INCOMING_RTL as
- a backup substitute for DECL_RTL in certain limited cases. In cases
- where DECL_ARG_TYPE (decl) indicates the same type as TREE_TYPE (decl),
- we can be sure that the parameter was passed using the same type as it is
- declared to have within the function, and that its DECL_INCOMING_RTL
- points us to a place where a value of that type is passed.
- In cases where DECL_ARG_TYPE (decl) and TREE_TYPE (decl) are different,
- we cannot (in general) use DECL_INCOMING_RTL as a substitute for DECL_RTL
- because in these cases DECL_INCOMING_RTL points us to a value of some
- type which is *different* from the type of the parameter itself. Thus,
- if we tried to use DECL_INCOMING_RTL to generate a location attribute in
- such cases, the debugger would end up (for example) trying to fetch a
- `float' from a place which actually contains the first part of a
- `double'. That would lead to really incorrect and confusing
- output at debug-time.
- So, in general, we *do not* use DECL_INCOMING_RTL as a backup for DECL_RTL
- in cases where DECL_ARG_TYPE (decl) != TREE_TYPE (decl). There
- are a couple of exceptions however. On little-endian machines we can
- get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE (decl) is
- not the same as TREE_TYPE (decl), but only when DECL_ARG_TYPE (decl) is
- an integral type that is smaller than TREE_TYPE (decl). These cases arise
- when (on a little-endian machine) a non-prototyped function has a
- parameter declared to be of type `short' or `char'. In such cases,
- TREE_TYPE (decl) will be `short' or `char', DECL_ARG_TYPE (decl) will
- be `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the
- passed `int' value. If the debugger then uses that address to fetch
- a `short' or a `char' (on a little-endian machine) the result will be
- the correct data, so we allow for such exceptional cases below.
- Note that our goal here is to describe the place where the given formal
- parameter lives during most of the function's activation (i.e. between the
- end of the prologue and the start of the epilogue). We'll do that as best
- as we can. Note however that if the given formal parameter is modified
- sometime during the execution of the function, then a stack backtrace (at
- debug-time) will show the function as having been called with the *new*
- value rather than the value which was originally passed in. This happens
- rarely enough that it is not a major problem, but it *is* a problem, and
- I'd like to fix it.
- A future version of dwarf2out.c may generate two additional attributes for
- any given DW_TAG_formal_parameter DIE which will describe the "passed
- type" and the "passed location" for the given formal parameter in addition
- to the attributes we now generate to indicate the "declared type" and the
- "active location" for each parameter. This additional set of attributes
- could be used by debuggers for stack backtraces. Separately, note that
- sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL can be NULL also.
- This happens (for example) for inlined-instances of inline function formal
- parameters which are never referenced. This really shouldn't be
- happening. All PARM_DECL nodes should get valid non-NULL
- DECL_INCOMING_RTL values. FIXME. */
- /* Use DECL_RTL as the "location" unless we find something better. */
- rtl = DECL_RTL_IF_SET (decl);
- /* When generating abstract instances, ignore everything except
- constants, symbols living in memory, and symbols living in
- fixed registers. */
- if (! reload_completed)
- {
- if (rtl
- && (CONSTANT_P (rtl)
- || (MEM_P (rtl)
- && CONSTANT_P (XEXP (rtl, 0)))
- || (REG_P (rtl)
- && TREE_CODE (decl) == VAR_DECL
- && TREE_STATIC (decl))))
- {
- rtl = targetm.delegitimize_address (rtl);
- return rtl;
- }
- rtl = NULL_RTX;
- }
- else if (TREE_CODE (decl) == PARM_DECL)
- {
- if (rtl == NULL_RTX
- || is_pseudo_reg (rtl)
- || (MEM_P (rtl)
- && is_pseudo_reg (XEXP (rtl, 0))
- && DECL_INCOMING_RTL (decl)
- && MEM_P (DECL_INCOMING_RTL (decl))
- && GET_MODE (rtl) == GET_MODE (DECL_INCOMING_RTL (decl))))
- {
- tree declared_type = TREE_TYPE (decl);
- tree passed_type = DECL_ARG_TYPE (decl);
- machine_mode dmode = TYPE_MODE (declared_type);
- machine_mode pmode = TYPE_MODE (passed_type);
- /* This decl represents a formal parameter which was optimized out.
- Note that DECL_INCOMING_RTL may be NULL in here, but we handle
- all cases where (rtl == NULL_RTX) just below. */
- if (dmode == pmode)
- rtl = DECL_INCOMING_RTL (decl);
- else if ((rtl == NULL_RTX || is_pseudo_reg (rtl))
- && SCALAR_INT_MODE_P (dmode)
- && GET_MODE_SIZE (dmode) <= GET_MODE_SIZE (pmode)
- && DECL_INCOMING_RTL (decl))
- {
- rtx inc = DECL_INCOMING_RTL (decl);
- if (REG_P (inc))
- rtl = inc;
- else if (MEM_P (inc))
- {
- if (BYTES_BIG_ENDIAN)
- rtl = adjust_address_nv (inc, dmode,
- GET_MODE_SIZE (pmode)
- - GET_MODE_SIZE (dmode));
- else
- rtl = inc;
- }
- }
- }
- /* If the parm was passed in registers, but lives on the stack, then
- make a big endian correction if the mode of the type of the
- parameter is not the same as the mode of the rtl. */
- /* ??? This is the same series of checks that are made in dbxout.c before
- we reach the big endian correction code there. It isn't clear if all
- of these checks are necessary here, but keeping them all is the safe
- thing to do. */
- else if (MEM_P (rtl)
- && XEXP (rtl, 0) != const0_rtx
- && ! CONSTANT_P (XEXP (rtl, 0))
- /* Not passed in memory. */
- && !MEM_P (DECL_INCOMING_RTL (decl))
- /* Not passed by invisible reference. */
- && (!REG_P (XEXP (rtl, 0))
- || REGNO (XEXP (rtl, 0)) == HARD_FRAME_POINTER_REGNUM
- || REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM
- #if !HARD_FRAME_POINTER_IS_ARG_POINTER
- || REGNO (XEXP (rtl, 0)) == ARG_POINTER_REGNUM
- #endif
- )
- /* Big endian correction check. */
- && BYTES_BIG_ENDIAN
- && TYPE_MODE (TREE_TYPE (decl)) != GET_MODE (rtl)
- && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)))
- < UNITS_PER_WORD))
- {
- machine_mode addr_mode = get_address_mode (rtl);
- int offset = (UNITS_PER_WORD
- - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl))));
- rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
- plus_constant (addr_mode, XEXP (rtl, 0), offset));
- }
- }
- else if (TREE_CODE (decl) == VAR_DECL
- && rtl
- && MEM_P (rtl)
- && GET_MODE (rtl) != TYPE_MODE (TREE_TYPE (decl))
- && BYTES_BIG_ENDIAN)
- {
- machine_mode addr_mode = get_address_mode (rtl);
- int rsize = GET_MODE_SIZE (GET_MODE (rtl));
- int dsize = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)));
- /* If a variable is declared "register" yet is smaller than
- a register, then if we store the variable to memory, it
- looks like we're storing a register-sized value, when in
- fact we are not. We need to adjust the offset of the
- storage location to reflect the actual value's bytes,
- else gdb will not be able to display it. */
- if (rsize > dsize)
- rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
- plus_constant (addr_mode, XEXP (rtl, 0),
- rsize - dsize));
- }
- /* A variable with no DECL_RTL but a DECL_INITIAL is a compile-time constant,
- and will have been substituted directly into all expressions that use it.
- C does not have such a concept, but C++ and other languages do. */
- if (!rtl && TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
- rtl = rtl_for_decl_init (DECL_INITIAL (decl), TREE_TYPE (decl));
- if (rtl)
- rtl = targetm.delegitimize_address (rtl);
- /* If we don't look past the constant pool, we risk emitting a
- reference to a constant pool entry that isn't referenced from
- code, and thus is not emitted. */
- if (rtl)
- rtl = avoid_constant_pool_reference (rtl);
- /* Try harder to get a rtl. If this symbol ends up not being emitted
- in the current CU, resolve_addr will remove the expression referencing
- it. */
- if (rtl == NULL_RTX
- && TREE_CODE (decl) == VAR_DECL
- && !DECL_EXTERNAL (decl)
- && TREE_STATIC (decl)
- && DECL_NAME (decl)
- && !DECL_HARD_REGISTER (decl)
- && DECL_MODE (decl) != VOIDmode)
- {
- rtl = make_decl_rtl_for_debug (decl);
- if (!MEM_P (rtl)
- || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF
- || SYMBOL_REF_DECL (XEXP (rtl, 0)) != decl)
- rtl = NULL_RTX;
- }
- return rtl;
- }
- /* Check whether decl is a Fortran COMMON symbol. If not, NULL_TREE is
- returned. If so, the decl for the COMMON block is returned, and the
- value is the offset into the common block for the symbol. */
- static tree
- fortran_common (tree decl, HOST_WIDE_INT *value)
- {
- tree val_expr, cvar;
- machine_mode mode;
- HOST_WIDE_INT bitsize, bitpos;
- tree offset;
- int unsignedp, volatilep = 0;
- /* If the decl isn't a VAR_DECL, or if it isn't static, or if
- it does not have a value (the offset into the common area), or if it
- is thread local (as opposed to global) then it isn't common, and shouldn't
- be handled as such. */
- if (TREE_CODE (decl) != VAR_DECL
- || !TREE_STATIC (decl)
- || !DECL_HAS_VALUE_EXPR_P (decl)
- || !is_fortran ())
- return NULL_TREE;
- val_expr = DECL_VALUE_EXPR (decl);
- if (TREE_CODE (val_expr) != COMPONENT_REF)
- return NULL_TREE;
- cvar = get_inner_reference (val_expr, &bitsize, &bitpos, &offset,
- &mode, &unsignedp, &volatilep, true);
- if (cvar == NULL_TREE
- || TREE_CODE (cvar) != VAR_DECL
- || DECL_ARTIFICIAL (cvar)
- || !TREE_PUBLIC (cvar))
- return NULL_TREE;
- *value = 0;
- if (offset != NULL)
- {
- if (!tree_fits_shwi_p (offset))
- return NULL_TREE;
- *value = tree_to_shwi (offset);
- }
- if (bitpos != 0)
- *value += bitpos / BITS_PER_UNIT;
- return cvar;
- }
- /* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value
- data attribute for a variable or a parameter. We generate the
- DW_AT_const_value attribute only in those cases where the given variable
- or parameter does not have a true "location" either in memory or in a
- register. This can happen (for example) when a constant is passed as an
- actual argument in a call to an inline function. (It's possible that
- these things can crop up in other ways also.) Note that one type of
- constant value which can be passed into an inlined function is a constant
- pointer. This can happen for example if an actual argument in an inlined
- function call evaluates to a compile-time constant address.
- CACHE_P is true if it is worth caching the location list for DECL,
- so that future calls can reuse it rather than regenerate it from scratch.
- This is true for BLOCK_NONLOCALIZED_VARS in inlined subroutines,
- since we will need to refer to them each time the function is inlined. */
- static bool
- add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p,
- enum dwarf_attribute attr)
- {
- rtx rtl;
- dw_loc_list_ref list;
- var_loc_list *loc_list;
- cached_dw_loc_list *cache;
- if (TREE_CODE (decl) == ERROR_MARK)
- return false;
- gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
- || TREE_CODE (decl) == RESULT_DECL);
- /* Try to get some constant RTL for this decl, and use that as the value of
- the location. */
- rtl = rtl_for_decl_location (decl);
- if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
- && add_const_value_attribute (die, rtl))
- return true;
- /* See if we have single element location list that is equivalent to
- a constant value. That way we are better to use add_const_value_attribute
- rather than expanding constant value equivalent. */
- loc_list = lookup_decl_loc (decl);
- if (loc_list
- && loc_list->first
- && loc_list->first->next == NULL
- && NOTE_P (loc_list->first->loc)
- && NOTE_VAR_LOCATION (loc_list->first->loc)
- && NOTE_VAR_LOCATION_LOC (loc_list->first->loc))
- {
- struct var_loc_node *node;
- node = loc_list->first;
- rtl = NOTE_VAR_LOCATION_LOC (node->loc);
- if (GET_CODE (rtl) == EXPR_LIST)
- rtl = XEXP (rtl, 0);
- if ((CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
- && add_const_value_attribute (die, rtl))
- return true;
- }
- /* If this decl is from BLOCK_NONLOCALIZED_VARS, we might need its
- list several times. See if we've already cached the contents. */
- list = NULL;
- if (loc_list == NULL || cached_dw_loc_list_table == NULL)
- cache_p = false;
- if (cache_p)
- {
- cache = cached_dw_loc_list_table->find_with_hash (decl, DECL_UID (decl));
- if (cache)
- list = cache->loc_list;
- }
- if (list == NULL)
- {
- list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2,
- NULL);
- /* It is usually worth caching this result if the decl is from
- BLOCK_NONLOCALIZED_VARS and if the list has at least two elements. */
- if (cache_p && list && list->dw_loc_next)
- {
- cached_dw_loc_list **slot
- = cached_dw_loc_list_table->find_slot_with_hash (decl,
- DECL_UID (decl),
- INSERT);
- cache = ggc_cleared_alloc<cached_dw_loc_list> ();
- cache->decl_id = DECL_UID (decl);
- cache->loc_list = list;
- *slot = cache;
- }
- }
- if (list)
- {
- add_AT_location_description (die, attr, list);
- return true;
- }
- /* None of that worked, so it must not really have a location;
- try adding a constant value attribute from the DECL_INITIAL. */
- return tree_add_const_value_attribute_for_decl (die, decl);
- }
- /* Add VARIABLE and DIE into deferred locations list. */
- static void
- defer_location (tree variable, dw_die_ref die)
- {
- deferred_locations entry;
- entry.variable = variable;
- entry.die = die;
- vec_safe_push (deferred_locations_list, entry);
- }
- /* Helper function for tree_add_const_value_attribute. Natively encode
- initializer INIT into an array. Return true if successful. */
- static bool
- native_encode_initializer (tree init, unsigned char *array, int size)
- {
- tree type;
- if (init == NULL_TREE)
- return false;
- STRIP_NOPS (init);
- switch (TREE_CODE (init))
- {
- case STRING_CST:
- type = TREE_TYPE (init);
- if (TREE_CODE (type) == ARRAY_TYPE)
- {
- tree enttype = TREE_TYPE (type);
- machine_mode mode = TYPE_MODE (enttype);
- if (GET_MODE_CLASS (mode) != MODE_INT || GET_MODE_SIZE (mode) != 1)
- return false;
- if (int_size_in_bytes (type) != size)
- return false;
- if (size > TREE_STRING_LENGTH (init))
- {
- memcpy (array, TREE_STRING_POINTER (init),
- TREE_STRING_LENGTH (init));
- memset (array + TREE_STRING_LENGTH (init),
- '\0', size - TREE_STRING_LENGTH (init));
- }
- else
- memcpy (array, TREE_STRING_POINTER (init), size);
- return true;
- }
- return false;
- case CONSTRUCTOR:
- type = TREE_TYPE (init);
- if (int_size_in_bytes (type) != size)
- return false;
- if (TREE_CODE (type) == ARRAY_TYPE)
- {
- HOST_WIDE_INT min_index;
- unsigned HOST_WIDE_INT cnt;
- int curpos = 0, fieldsize;
- constructor_elt *ce;
- if (TYPE_DOMAIN (type) == NULL_TREE
- || !tree_fits_shwi_p (TYPE_MIN_VALUE (TYPE_DOMAIN (type))))
- return false;
- fieldsize = int_size_in_bytes (TREE_TYPE (type));
- if (fieldsize <= 0)
- return false;
- min_index = tree_to_shwi (TYPE_MIN_VALUE (TYPE_DOMAIN (type)));
- memset (array, '\0', size);
- FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (init), cnt, ce)
- {
- tree val = ce->value;
- tree index = ce->index;
- int pos = curpos;
- if (index && TREE_CODE (index) == RANGE_EXPR)
- pos = (tree_to_shwi (TREE_OPERAND (index, 0)) - min_index)
- * fieldsize;
- else if (index)
- pos = (tree_to_shwi (index) - min_index) * fieldsize;
- if (val)
- {
- STRIP_NOPS (val);
- if (!native_encode_initializer (val, array + pos, fieldsize))
- return false;
- }
- curpos = pos + fieldsize;
- if (index && TREE_CODE (index) == RANGE_EXPR)
- {
- int count = tree_to_shwi (TREE_OPERAND (index, 1))
- - tree_to_shwi (TREE_OPERAND (index, 0));
- while (count-- > 0)
- {
- if (val)
- memcpy (array + curpos, array + pos, fieldsize);
- curpos += fieldsize;
- }
- }
- gcc_assert (curpos <= size);
- }
- return true;
- }
- else if (TREE_CODE (type) == RECORD_TYPE
- || TREE_CODE (type) == UNION_TYPE)
- {
- tree field = NULL_TREE;
- unsigned HOST_WIDE_INT cnt;
- constructor_elt *ce;
- if (int_size_in_bytes (type) != size)
- return false;
- if (TREE_CODE (type) == RECORD_TYPE)
- field = TYPE_FIELDS (type);
- FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (init), cnt, ce)
- {
- tree val = ce->value;
- int pos, fieldsize;
- if (ce->index != 0)
- field = ce->index;
- if (val)
- STRIP_NOPS (val);
- if (field == NULL_TREE || DECL_BIT_FIELD (field))
- return false;
- if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
- && TYPE_DOMAIN (TREE_TYPE (field))
- && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
- return false;
- else if (DECL_SIZE_UNIT (field) == NULL_TREE
- || !tree_fits_shwi_p (DECL_SIZE_UNIT (field)))
- return false;
- fieldsize = tree_to_shwi (DECL_SIZE_UNIT (field));
- pos = int_byte_position (field);
- gcc_assert (pos + fieldsize <= size);
- if (val
- && !native_encode_initializer (val, array + pos, fieldsize))
- return false;
- }
- return true;
- }
- return false;
- case VIEW_CONVERT_EXPR:
- case NON_LVALUE_EXPR:
- return native_encode_initializer (TREE_OPERAND (init, 0), array, size);
- default:
- return native_encode_expr (init, array, size) == size;
- }
- }
- /* Attach a DW_AT_const_value attribute to DIE. The value of the
- attribute is the const value T. */
- static bool
- tree_add_const_value_attribute (dw_die_ref die, tree t)
- {
- tree init;
- tree type = TREE_TYPE (t);
- rtx rtl;
- if (!t || !TREE_TYPE (t) || TREE_TYPE (t) == error_mark_node)
- return false;
- init = t;
- gcc_assert (!DECL_P (init));
- rtl = rtl_for_decl_init (init, type);
- if (rtl)
- return add_const_value_attribute (die, rtl);
- /* If the host and target are sane, try harder. */
- else if (CHAR_BIT == 8 && BITS_PER_UNIT == 8
- && initializer_constant_valid_p (init, type))
- {
- HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (init));
- if (size > 0 && (int) size == size)
- {
- unsigned char *array = ggc_cleared_vec_alloc<unsigned char> (size);
- if (native_encode_initializer (init, array, size))
- {
- add_AT_vec (die, DW_AT_const_value, size, 1, array);
- return true;
- }
- ggc_free (array);
- }
- }
- return false;
- }
- /* Attach a DW_AT_const_value attribute to VAR_DIE. The value of the
- attribute is the const value of T, where T is an integral constant
- variable with static storage duration
- (so it can't be a PARM_DECL or a RESULT_DECL). */
- static bool
- tree_add_const_value_attribute_for_decl (dw_die_ref var_die, tree decl)
- {
- if (!decl
- || (TREE_CODE (decl) != VAR_DECL
- && TREE_CODE (decl) != CONST_DECL)
- || (TREE_CODE (decl) == VAR_DECL
- && !TREE_STATIC (decl)))
- return false;
- if (TREE_READONLY (decl)
- && ! TREE_THIS_VOLATILE (decl)
- && DECL_INITIAL (decl))
- /* OK */;
- else
- return false;
- /* Don't add DW_AT_const_value if abstract origin already has one. */
- if (get_AT (var_die, DW_AT_const_value))
- return false;
- return tree_add_const_value_attribute (var_die, DECL_INITIAL (decl));
- }
- /* Convert the CFI instructions for the current function into a
- location list. This is used for DW_AT_frame_base when we targeting
- a dwarf2 consumer that does not support the dwarf3
- DW_OP_call_frame_cfa. OFFSET is a constant to be added to all CFA
- expressions. */
- static dw_loc_list_ref
- convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
- {
- int ix;
- dw_fde_ref fde;
- dw_loc_list_ref list, *list_tail;
- dw_cfi_ref cfi;
- dw_cfa_location last_cfa, next_cfa;
- const char *start_label, *last_label, *section;
- dw_cfa_location remember;
- fde = cfun->fde;
- gcc_assert (fde != NULL);
- section = secname_for_decl (current_function_decl);
- list_tail = &list;
- list = NULL;
- memset (&next_cfa, 0, sizeof (next_cfa));
- next_cfa.reg = INVALID_REGNUM;
- remember = next_cfa;
- start_label = fde->dw_fde_begin;
- /* ??? Bald assumption that the CIE opcode list does not contain
- advance opcodes. */
- FOR_EACH_VEC_ELT (*cie_cfi_vec, ix, cfi)
- lookup_cfa_1 (cfi, &next_cfa, &remember);
- last_cfa = next_cfa;
- last_label = start_label;
- if (fde->dw_fde_second_begin && fde->dw_fde_switch_cfi_index == 0)
- {
- /* If the first partition contained no CFI adjustments, the
- CIE opcodes apply to the whole first partition. */
- *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- fde->dw_fde_begin, fde->dw_fde_end, section);
- list_tail =&(*list_tail)->dw_loc_next;
- start_label = last_label = fde->dw_fde_second_begin;
- }
- FOR_EACH_VEC_SAFE_ELT (fde->dw_fde_cfi, ix, cfi)
- {
- switch (cfi->dw_cfi_opc)
- {
- case DW_CFA_set_loc:
- case DW_CFA_advance_loc1:
- case DW_CFA_advance_loc2:
- case DW_CFA_advance_loc4:
- if (!cfa_equal_p (&last_cfa, &next_cfa))
- {
- *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
- list_tail = &(*list_tail)->dw_loc_next;
- last_cfa = next_cfa;
- start_label = last_label;
- }
- last_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
- break;
- case DW_CFA_advance_loc:
- /* The encoding is complex enough that we should never emit this. */
- gcc_unreachable ();
- default:
- lookup_cfa_1 (cfi, &next_cfa, &remember);
- break;
- }
- if (ix + 1 == fde->dw_fde_switch_cfi_index)
- {
- if (!cfa_equal_p (&last_cfa, &next_cfa))
- {
- *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
- list_tail = &(*list_tail)->dw_loc_next;
- last_cfa = next_cfa;
- start_label = last_label;
- }
- *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, fde->dw_fde_end, section);
- list_tail = &(*list_tail)->dw_loc_next;
- start_label = last_label = fde->dw_fde_second_begin;
- }
- }
- if (!cfa_equal_p (&last_cfa, &next_cfa))
- {
- *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
- list_tail = &(*list_tail)->dw_loc_next;
- start_label = last_label;
- }
- *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
- start_label,
- fde->dw_fde_second_begin
- ? fde->dw_fde_second_end : fde->dw_fde_end,
- section);
- if (list && list->dw_loc_next)
- gen_llsym (list);
- return list;
- }
- /* Compute a displacement from the "steady-state frame pointer" to the
- frame base (often the same as the CFA), and store it in
- frame_pointer_fb_offset. OFFSET is added to the displacement
- before the latter is negated. */
- static void
- compute_frame_pointer_to_fb_displacement (HOST_WIDE_INT offset)
- {
- rtx reg, elim;
- #ifdef FRAME_POINTER_CFA_OFFSET
- reg = frame_pointer_rtx;
- offset += FRAME_POINTER_CFA_OFFSET (current_function_decl);
- #else
- reg = arg_pointer_rtx;
- offset += ARG_POINTER_CFA_OFFSET (current_function_decl);
- #endif
- elim = (ira_use_lra_p
- ? lra_eliminate_regs (reg, VOIDmode, NULL_RTX)
- : eliminate_regs (reg, VOIDmode, NULL_RTX));
- if (GET_CODE (elim) == PLUS)
- {
- offset += INTVAL (XEXP (elim, 1));
- elim = XEXP (elim, 0);
- }
- frame_pointer_fb_offset = -offset;
- /* ??? AVR doesn't set up valid eliminations when there is no stack frame
- in which to eliminate. This is because it's stack pointer isn't
- directly accessible as a register within the ISA. To work around
- this, assume that while we cannot provide a proper value for
- frame_pointer_fb_offset, we won't need one either. */
- frame_pointer_fb_offset_valid
- = ((SUPPORTS_STACK_ALIGNMENT
- && (elim == hard_frame_pointer_rtx
- || elim == stack_pointer_rtx))
- || elim == (frame_pointer_needed
- ? hard_frame_pointer_rtx
- : stack_pointer_rtx));
- }
- /* Generate a DW_AT_name attribute given some string value to be included as
- the value of the attribute. */
- static void
- add_name_attribute (dw_die_ref die, const char *name_string)
- {
- if (name_string != NULL && *name_string != 0)
- {
- if (demangle_name_func)
- name_string = (*demangle_name_func) (name_string);
- add_AT_string (die, DW_AT_name, name_string);
- }
- }
- /* Retrieve the descriptive type of TYPE, if any, make sure it has a
- DIE and attach a DW_AT_GNAT_descriptive_type attribute to the DIE
- of TYPE accordingly.
- ??? This is a temporary measure until after we're able to generate
- regular DWARF for the complex Ada type system. */
- static void
- add_gnat_descriptive_type_attribute (dw_die_ref die, tree type,
- dw_die_ref context_die)
- {
- tree dtype;
- dw_die_ref dtype_die;
- if (!lang_hooks.types.descriptive_type)
- return;
- dtype = lang_hooks.types.descriptive_type (type);
- if (!dtype)
- return;
- dtype_die = lookup_type_die (dtype);
- if (!dtype_die)
- {
- gen_type_die (dtype, context_die);
- dtype_die = lookup_type_die (dtype);
- gcc_assert (dtype_die);
- }
- add_AT_die_ref (die, DW_AT_GNAT_descriptive_type, dtype_die);
- }
- /* Retrieve the comp_dir string suitable for use with DW_AT_comp_dir. */
- static const char *
- comp_dir_string (void)
- {
- const char *wd;
- char *wd1;
- static const char *cached_wd = NULL;
- if (cached_wd != NULL)
- return cached_wd;
- wd = get_src_pwd ();
- if (wd == NULL)
- return NULL;
- if (DWARF2_DIR_SHOULD_END_WITH_SEPARATOR)
- {
- int wdlen;
- wdlen = strlen (wd);
- wd1 = ggc_vec_alloc<char> (wdlen + 2);
- strcpy (wd1, wd);
- wd1 [wdlen] = DIR_SEPARATOR;
- wd1 [wdlen + 1] = 0;
- wd = wd1;
- }
- cached_wd = remap_debug_filename (wd);
- return cached_wd;
- }
- /* Generate a DW_AT_comp_dir attribute for DIE. */
- static void
- add_comp_dir_attribute (dw_die_ref die)
- {
- const char * wd = comp_dir_string ();
- if (wd != NULL)
- add_AT_string (die, DW_AT_comp_dir, wd);
- }
- /* Given a tree node VALUE describing a scalar attribute ATTR (i.e. a bound, a
- pointer computation, ...), output a representation for that bound according
- to the accepted FORMS (see enum dw_scalar_form) and add it to DIE. See
- loc_list_from_tree for the meaning of CONTEXT. */
- static void
- add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value,
- int forms, const struct loc_descr_context *context)
- {
- dw_die_ref ctx, decl_die;
- dw_loc_list_ref list;
- bool strip_conversions = true;
- while (strip_conversions)
- switch (TREE_CODE (value))
- {
- case ERROR_MARK:
- case SAVE_EXPR:
- return;
- CASE_CONVERT:
- case VIEW_CONVERT_EXPR:
- value = TREE_OPERAND (value, 0);
- break;
- default:
- strip_conversions = false;
- break;
- }
- /* If possible and permitted, output the attribute as a constant. */
- if ((forms & dw_scalar_form_constant) != 0
- && TREE_CODE (value) == INTEGER_CST)
- {
- unsigned int prec = simple_type_size_in_bits (TREE_TYPE (value));
- /* If HOST_WIDE_INT is big enough then represent the bound as
- a constant value. We need to choose a form based on
- whether the type is signed or unsigned. We cannot just
- call add_AT_unsigned if the value itself is positive
- (add_AT_unsigned might add the unsigned value encoded as
- DW_FORM_data[1248]). Some DWARF consumers will lookup the
- bounds type and then sign extend any unsigned values found
- for signed types. This is needed only for
- DW_AT_{lower,upper}_bound, since for most other attributes,
- consumers will treat DW_FORM_data[1248] as unsigned values,
- regardless of the underlying type. */
- if (prec <= HOST_BITS_PER_WIDE_INT
- || tree_fits_uhwi_p (value))
- {
- if (TYPE_UNSIGNED (TREE_TYPE (value)))
- add_AT_unsigned (die, attr, TREE_INT_CST_LOW (value));
- else
- add_AT_int (die, attr, TREE_INT_CST_LOW (value));
- }
- else
- /* Otherwise represent the bound as an unsigned value with
- the precision of its type. The precision and signedness
- of the type will be necessary to re-interpret it
- unambiguously. */
- add_AT_wide (die, attr, value);
- return;
- }
- /* Otherwise, if it's possible and permitted too, output a reference to
- another DIE. */
- if ((forms & dw_scalar_form_reference) != 0)
- {
- tree decl = NULL_TREE;
- /* Some type attributes reference an outer type. For instance, the upper
- bound of an array may reference an embedding record (this happens in
- Ada). */
- if (TREE_CODE (value) == COMPONENT_REF
- && TREE_CODE (TREE_OPERAND (value, 0)) == PLACEHOLDER_EXPR
- && TREE_CODE (TREE_OPERAND (value, 1)) == FIELD_DECL)
- decl = TREE_OPERAND (value, 1);
- else if (TREE_CODE (value) == VAR_DECL
- || TREE_CODE (value) == PARM_DECL
- || TREE_CODE (value) == RESULT_DECL)
- decl = value;
- if (decl != NULL_TREE)
- {
- dw_die_ref decl_die = lookup_decl_die (decl);
- /* ??? Can this happen, or should the variable have been bound
- first? Probably it can, since I imagine that we try to create
- the types of parameters in the order in which they exist in
- the list, and won't have created a forward reference to a
- later parameter. */
- if (decl_die != NULL)
- {
- add_AT_die_ref (die, attr, decl_die);
- return;
- }
- }
- }
- /* Last chance: try to create a stack operation procedure to evaluate the
- value. Do nothing if even that is not possible or permitted. */
- if ((forms & dw_scalar_form_exprloc) == 0)
- return;
- list = loc_list_from_tree (value, 2, context);
- if (list == NULL || single_element_loc_list_p (list))
- {
- /* If this attribute is not a reference nor constant, it is
- a DWARF expression rather than location description. For that
- loc_list_from_tree (value, 0, &context) is needed. */
- dw_loc_list_ref list2 = loc_list_from_tree (value, 0, context);
- if (list2 && single_element_loc_list_p (list2))
- {
- add_AT_loc (die, attr, list2->expr);
- return;
- }
- }
- /* If that failed to give a single element location list, fall back to
- outputting this as a reference... still if permitted. */
- if (list == NULL || (forms & dw_scalar_form_reference) == 0)
- return;
- if (current_function_decl == 0)
- ctx = comp_unit_die ();
- else
- ctx = lookup_decl_die (current_function_decl);
- decl_die = new_die (DW_TAG_variable, ctx, value);
- add_AT_flag (decl_die, DW_AT_artificial, 1);
- add_type_attribute (decl_die, TREE_TYPE (value), TYPE_QUAL_CONST, ctx);
- add_AT_location_description (decl_die, DW_AT_location, list);
- add_AT_die_ref (die, attr, decl_die);
- }
- /* Return the default for DW_AT_lower_bound, or -1 if there is not any
- default. */
- static int
- lower_bound_default (void)
- {
- switch (get_AT_unsigned (comp_unit_die (), DW_AT_language))
- {
- case DW_LANG_C:
- case DW_LANG_C89:
- case DW_LANG_C99:
- case DW_LANG_C11:
- case DW_LANG_C_plus_plus:
- case DW_LANG_C_plus_plus_11:
- case DW_LANG_C_plus_plus_14:
- case DW_LANG_ObjC:
- case DW_LANG_ObjC_plus_plus:
- case DW_LANG_Java:
- return 0;
- case DW_LANG_Fortran77:
- case DW_LANG_Fortran90:
- case DW_LANG_Fortran95:
- case DW_LANG_Fortran03:
- case DW_LANG_Fortran08:
- return 1;
- case DW_LANG_UPC:
- case DW_LANG_D:
- case DW_LANG_Python:
- return dwarf_version >= 4 ? 0 : -1;
- case DW_LANG_Ada95:
- case DW_LANG_Ada83:
- case DW_LANG_Cobol74:
- case DW_LANG_Cobol85:
- case DW_LANG_Pascal83:
- case DW_LANG_Modula2:
- case DW_LANG_PLI:
- return dwarf_version >= 4 ? 1 : -1;
- default:
- return -1;
- }
- }
- /* Given a tree node describing an array bound (either lower or upper) output
- a representation for that bound. */
- static void
- add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr,
- tree bound, const struct loc_descr_context *context)
- {
- int dflt;
- while (1)
- switch (TREE_CODE (bound))
- {
- /* Strip all conversions. */
- CASE_CONVERT:
- case VIEW_CONVERT_EXPR:
- bound = TREE_OPERAND (bound, 0);
- break;
- /* All fixed-bounds are represented by INTEGER_CST nodes. Lower bounds
- are even omitted when they are the default. */
- case INTEGER_CST:
- /* If the value for this bound is the default one, we can even omit the
- attribute. */
- if (bound_attr == DW_AT_lower_bound
- && tree_fits_shwi_p (bound)
- && (dflt = lower_bound_default ()) != -1
- && tree_to_shwi (bound) == dflt)
- return;
- /* FALLTHRU */
- default:
- add_scalar_info (subrange_die, bound_attr, bound,
- dw_scalar_form_constant
- | dw_scalar_form_exprloc
- | dw_scalar_form_reference,
- context);
- return;
- }
- }
- /* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing
- possibly nested array subscripts in a flat sequence if COLLAPSE_P is true.
- Note that the block of subscript information for an array type also
- includes information about the element type of the given array type. */
- static void
- add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
- {
- unsigned dimension_number;
- tree lower, upper;
- dw_die_ref subrange_die;
- for (dimension_number = 0;
- TREE_CODE (type) == ARRAY_TYPE && (dimension_number == 0 || collapse_p);
- type = TREE_TYPE (type), dimension_number++)
- {
- tree domain = TYPE_DOMAIN (type);
- if (TYPE_STRING_FLAG (type) && is_fortran () && dimension_number > 0)
- break;
- /* Arrays come in three flavors: Unspecified bounds, fixed bounds,
- and (in GNU C only) variable bounds. Handle all three forms
- here. */
- subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
- if (domain)
- {
- /* We have an array type with specified bounds. */
- lower = TYPE_MIN_VALUE (domain);
- upper = TYPE_MAX_VALUE (domain);
- /* Define the index type. */
- if (TREE_TYPE (domain))
- {
- /* ??? This is probably an Ada unnamed subrange type. Ignore the
- TREE_TYPE field. We can't emit debug info for this
- because it is an unnamed integral type. */
- if (TREE_CODE (domain) == INTEGER_TYPE
- && TYPE_NAME (domain) == NULL_TREE
- && TREE_CODE (TREE_TYPE (domain)) == INTEGER_TYPE
- && TYPE_NAME (TREE_TYPE (domain)) == NULL_TREE)
- ;
- else
- add_type_attribute (subrange_die, TREE_TYPE (domain),
- TYPE_UNQUALIFIED, type_die);
- }
- /* ??? If upper is NULL, the array has unspecified length,
- but it does have a lower bound. This happens with Fortran
- dimension arr(N:*)
- Since the debugger is definitely going to need to know N
- to produce useful results, go ahead and output the lower
- bound solo, and hope the debugger can cope. */
- add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL);
- if (upper)
- add_bound_info (subrange_die, DW_AT_upper_bound, upper, NULL);
- }
- /* Otherwise we have an array type with an unspecified length. The
- DWARF-2 spec does not say how to handle this; let's just leave out the
- bounds. */
- }
- }
- /* Add a DW_AT_byte_size attribute to DIE with TREE_NODE's size. */
- static void
- add_byte_size_attribute (dw_die_ref die, tree tree_node)
- {
- dw_die_ref decl_die;
- HOST_WIDE_INT size;
- switch (TREE_CODE (tree_node))
- {
- case ERROR_MARK:
- size = 0;
- break;
- case ENUMERAL_TYPE:
- case RECORD_TYPE:
- case UNION_TYPE:
- case QUAL_UNION_TYPE:
- if (TREE_CODE (TYPE_SIZE_UNIT (tree_node)) == VAR_DECL
- && (decl_die = lookup_decl_die (TYPE_SIZE_UNIT (tree_node))))
- {
- add_AT_die_ref (die, DW_AT_byte_size, decl_die);
- return;
- }
- size = int_size_in_bytes (tree_node);
- break;
- case FIELD_DECL:
- /* For a data member of a struct or union, the DW_AT_byte_size is
- generally given as the number of bytes normally allocated for an
- object of the *declared* type of the member itself. This is true
- even for bit-fields. */
- size = int_size_in_bytes (field_type (tree_node));
- break;
- default:
- gcc_unreachable ();
- }
- /* Note that `size' might be -1 when we get to this point. If it is, that
- indicates that the byte size of the entity in question is variable. We
- have no good way of expressing this fact in Dwarf at the present time,
- when location description was not used by the caller code instead. */
- if (size >= 0)
- add_AT_unsigned (die, DW_AT_byte_size, size);
- }
- /* For a FIELD_DECL node which represents a bit-field, output an attribute
- which specifies the distance in bits from the highest order bit of the
- "containing object" for the bit-field to the highest order bit of the
- bit-field itself.
- For any given bit-field, the "containing object" is a hypothetical object
- (of some integral or enum type) within which the given bit-field lives. The
- type of this hypothetical "containing object" is always the same as the
- declared type of the individual bit-field itself. The determination of the
- exact location of the "containing object" for a bit-field is rather
- complicated. It's handled by the `field_byte_offset' function (above).
- Note that it is the size (in bytes) of the hypothetical "containing object"
- which will be given in the DW_AT_byte_size attribute for this bit-field.
- (See `byte_size_attribute' above). */
- static inline void
- add_bit_offset_attribute (dw_die_ref die, tree decl)
- {
- HOST_WIDE_INT object_offset_in_bytes = field_byte_offset (decl);
- tree type = DECL_BIT_FIELD_TYPE (decl);
- HOST_WIDE_INT bitpos_int;
- HOST_WIDE_INT highest_order_object_bit_offset;
- HOST_WIDE_INT highest_order_field_bit_offset;
- HOST_WIDE_INT bit_offset;
- /* Must be a field and a bit field. */
- gcc_assert (type && TREE_CODE (decl) == FIELD_DECL);
- /* We can't yet handle bit-fields whose offsets are variable, so if we
- encounter such things, just return without generating any attribute
- whatsoever. Likewise for variable or too large size. */
- if (! tree_fits_shwi_p (bit_position (decl))
- || ! tree_fits_uhwi_p (DECL_SIZE (decl)))
- return;
- bitpos_int = int_bit_position (decl);
- /* Note that the bit offset is always the distance (in bits) from the
- highest-order bit of the "containing object" to the highest-order bit of
- the bit-field itself. Since the "high-order end" of any object or field
- is different on big-endian and little-endian machines, the computation
- below must take account of these differences. */
- highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT;
- highest_order_field_bit_offset = bitpos_int;
- if (! BYTES_BIG_ENDIAN)
- {
- highest_order_field_bit_offset += tree_to_shwi (DECL_SIZE (decl));
- highest_order_object_bit_offset += simple_type_size_in_bits (type);
- }
- bit_offset
- = (! BYTES_BIG_ENDIAN
- ? highest_order_object_bit_offset - highest_order_field_bit_offset
- : highest_order_field_bit_offset - highest_order_object_bit_offset);
- if (bit_offset < 0)
- add_AT_int (die, DW_AT_bit_offset, bit_offset);
- else
- add_AT_unsigned (die, DW_AT_bit_offset, (unsigned HOST_WIDE_INT) bit_offset);
- }
- /* For a FIELD_DECL node which represents a bit field, output an attribute
- which specifies the length in bits of the given field. */
- static inline void
- add_bit_size_attribute (dw_die_ref die, tree decl)
- {
- /* Must be a field and a bit field. */
- gcc_assert (TREE_CODE (decl) == FIELD_DECL
- && DECL_BIT_FIELD_TYPE (decl));
- if (tree_fits_uhwi_p (DECL_SIZE (decl)))
- add_AT_unsigned (die, DW_AT_bit_size, tree_to_uhwi (DECL_SIZE (decl)));
- }
- /* If the compiled language is ANSI C, then add a 'prototyped'
- attribute, if arg types are given for the parameters of a function. */
- static inline void
- add_prototyped_attribute (dw_die_ref die, tree func_type)
- {
- switch (get_AT_unsigned (comp_unit_die (), DW_AT_language))
- {
- case DW_LANG_C:
- case DW_LANG_C89:
- case DW_LANG_C99:
- case DW_LANG_C11:
- case DW_LANG_ObjC:
- if (prototype_p (func_type))
- add_AT_flag (die, DW_AT_prototyped, 1);
- break;
- default:
- break;
- }
- }
- /* Add an 'abstract_origin' attribute below a given DIE. The DIE is found
- by looking in either the type declaration or object declaration
- equate table. */
- static inline dw_die_ref
- add_abstract_origin_attribute (dw_die_ref die, tree origin)
- {
- dw_die_ref origin_die = NULL;
- if (TREE_CODE (origin) != FUNCTION_DECL)
- {
- /* We may have gotten separated from the block for the inlined
- function, if we're in an exception handler or some such; make
- sure that the abstract function has been written out.
- Doing this for nested functions is wrong, however; functions are
- distinct units, and our context might not even be inline. */
- tree fn = origin;
- if (TYPE_P (fn))
- fn = TYPE_STUB_DECL (fn);
- fn = decl_function_context (fn);
- if (fn)
- dwarf2out_abstract_function (fn);
- }
- if (DECL_P (origin))
- origin_die = lookup_decl_die (origin);
- else if (TYPE_P (origin))
- origin_die = lookup_type_die (origin);
- /* XXX: Functions that are never lowered don't always have correct block
- trees (in the case of java, they simply have no block tree, in some other
- languages). For these functions, there is nothing we can really do to
- output correct debug info for inlined functions in all cases. Rather
- than die, we'll just produce deficient debug info now, in that we will
- have variables without a proper abstract origin. In the future, when all
- functions are lowered, we should re-add a gcc_assert (origin_die)
- here. */
- if (origin_die)
- add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
- return origin_die;
- }
- /* We do not currently support the pure_virtual attribute. */
- static inline void
- add_pure_or_virtual_attribute (dw_die_ref die, tree func_decl)
- {
- if (DECL_VINDEX (func_decl))
- {
- add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
- if (tree_fits_shwi_p (DECL_VINDEX (func_decl)))
- add_AT_loc (die, DW_AT_vtable_elem_location,
- new_loc_descr (DW_OP_constu,
- tree_to_shwi (DECL_VINDEX (func_decl)),
- 0));
- /* GNU extension: Record what type this method came from originally. */
- if (debug_info_level > DINFO_LEVEL_TERSE
- && DECL_CONTEXT (func_decl))
- add_AT_die_ref (die, DW_AT_containing_type,
- lookup_type_die (DECL_CONTEXT (func_decl)));
- }
- }
- /* Add a DW_AT_linkage_name or DW_AT_MIPS_linkage_name attribute for the
- given decl. This used to be a vendor extension until after DWARF 4
- standardized it. */
- static void
- add_linkage_attr (dw_die_ref die, tree decl)
- {
- const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- /* Mimic what assemble_name_raw does with a leading '*'. */
- if (name[0] == '*')
- name = &name[1];
- if (dwarf_version >= 4)
- add_AT_string (die, DW_AT_linkage_name, name);
- else
- add_AT_string (die, DW_AT_MIPS_linkage_name, name);
- }
- /* Add source coordinate attributes for the given decl. */
- static void
- add_src_coords_attributes (dw_die_ref die, tree decl)
- {
- expanded_location s;
- if (LOCATION_LOCUS (DECL_SOURCE_LOCATION (decl)) == UNKNOWN_LOCATION)
- return;
- s = expand_location (DECL_SOURCE_LOCATION (decl));
- add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file));
- add_AT_unsigned (die, DW_AT_decl_line, s.line);
- }
- /* Add DW_AT_{,MIPS_}linkage_name attribute for the given decl. */
- static void
- add_linkage_name (dw_die_ref die, tree decl)
- {
- if (debug_info_level > DINFO_LEVEL_NONE
- && (TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
- && TREE_PUBLIC (decl)
- && !(TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl))
- && die->die_tag != DW_TAG_member)
- {
- /* Defer until we have an assembler name set. */
- if (!DECL_ASSEMBLER_NAME_SET_P (decl))
- {
- limbo_die_node *asm_name;
- asm_name = ggc_cleared_alloc<limbo_die_node> ();
- asm_name->die = die;
- asm_name->created_for = decl;
- asm_name->next = deferred_asm_name;
- deferred_asm_name = asm_name;
- }
- else if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
- add_linkage_attr (die, decl);
- }
- }
- /* Add a DW_AT_name attribute and source coordinate attribute for the
- given decl, but only if it actually has a name. */
- static void
- add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
- {
- tree decl_name;
- decl_name = DECL_NAME (decl);
- if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL)
- {
- const char *name = dwarf2_name (decl, 0);
- if (name)
- add_name_attribute (die, name);
- if (! DECL_ARTIFICIAL (decl))
- add_src_coords_attributes (die, decl);
- add_linkage_name (die, decl);
- }
- #ifdef VMS_DEBUGGING_INFO
- /* Get the function's name, as described by its RTL. This may be different
- from the DECL_NAME name used in the source file. */
- if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
- {
- add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
- XEXP (DECL_RTL (decl), 0), false);
- vec_safe_push (used_rtx_array, XEXP (DECL_RTL (decl), 0));
- }
- #endif /* VMS_DEBUGGING_INFO */
- }
- #ifdef VMS_DEBUGGING_INFO
- /* Output the debug main pointer die for VMS */
- void
- dwarf2out_vms_debug_main_pointer (void)
- {
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- dw_die_ref die;
- /* Allocate the VMS debug main subprogram die. */
- die = ggc_cleared_alloc<die_node> ();
- die->die_tag = DW_TAG_subprogram;
- add_name_attribute (die, VMS_DEBUG_MAIN_POINTER);
- ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
- current_function_funcdef_no);
- add_AT_lbl_id (die, DW_AT_entry_pc, label);
- /* Make it the first child of comp_unit_die (). */
- die->die_parent = comp_unit_die ();
- if (comp_unit_die ()->die_child)
- {
- die->die_sib = comp_unit_die ()->die_child->die_sib;
- comp_unit_die ()->die_child->die_sib = die;
- }
- else
- {
- die->die_sib = die;
- comp_unit_die ()->die_child = die;
- }
- }
- #endif /* VMS_DEBUGGING_INFO */
- /* Push a new declaration scope. */
- static void
- push_decl_scope (tree scope)
- {
- vec_safe_push (decl_scope_table, scope);
- }
- /* Pop a declaration scope. */
- static inline void
- pop_decl_scope (void)
- {
- decl_scope_table->pop ();
- }
- /* walk_tree helper function for uses_local_type, below. */
- static tree
- uses_local_type_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
- {
- if (!TYPE_P (*tp))
- *walk_subtrees = 0;
- else
- {
- tree name = TYPE_NAME (*tp);
- if (name && DECL_P (name) && decl_function_context (name))
- return *tp;
- }
- return NULL_TREE;
- }
- /* If TYPE involves a function-local type (including a local typedef to a
- non-local type), returns that type; otherwise returns NULL_TREE. */
- static tree
- uses_local_type (tree type)
- {
- tree used = walk_tree_without_duplicates (&type, uses_local_type_r, NULL);
- return used;
- }
- /* Return the DIE for the scope that immediately contains this type.
- Non-named types that do not involve a function-local type get global
- scope. Named types nested in namespaces or other types get their
- containing scope. All other types (i.e. function-local named types) get
- the current active scope. */
- static dw_die_ref
- scope_die_for (tree t, dw_die_ref context_die)
- {
- dw_die_ref scope_die = NULL;
- tree containing_scope;
- /* Non-types always go in the current scope. */
- gcc_assert (TYPE_P (t));
- /* Use the scope of the typedef, rather than the scope of the type
- it refers to. */
- if (TYPE_NAME (t) && DECL_P (TYPE_NAME (t)))
- containing_scope = DECL_CONTEXT (TYPE_NAME (t));
- else
- containing_scope = TYPE_CONTEXT (t);
- /* Use the containing namespace if there is one. */
- if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL)
- {
- if (context_die == lookup_decl_die (containing_scope))
- /* OK */;
- else if (debug_info_level > DINFO_LEVEL_TERSE)
- context_die = get_context_die (containing_scope);
- else
- containing_scope = NULL_TREE;
- }
- /* Ignore function type "scopes" from the C frontend. They mean that
- a tagged type is local to a parmlist of a function declarator, but
- that isn't useful to DWARF. */
- if (containing_scope && TREE_CODE (containing_scope) == FUNCTION_TYPE)
- containing_scope = NULL_TREE;
- if (SCOPE_FILE_SCOPE_P (containing_scope))
- {
- /* If T uses a local type keep it local as well, to avoid references
- to function-local DIEs from outside the function. */
- if (current_function_decl && uses_local_type (t))
- scope_die = context_die;
- else
- scope_die = comp_unit_die ();
- }
- else if (TYPE_P (containing_scope))
- {
- /* For types, we can just look up the appropriate DIE. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
- scope_die = get_context_die (containing_scope);
- else
- {
- scope_die = lookup_type_die_strip_naming_typedef (containing_scope);
- if (scope_die == NULL)
- scope_die = comp_unit_die ();
- }
- }
- else
- scope_die = context_die;
- return scope_die;
- }
- /* Returns nonzero if CONTEXT_DIE is internal to a function. */
- static inline int
- local_scope_p (dw_die_ref context_die)
- {
- for (; context_die; context_die = context_die->die_parent)
- if (context_die->die_tag == DW_TAG_inlined_subroutine
- || context_die->die_tag == DW_TAG_subprogram)
- return 1;
- return 0;
- }
- /* Returns nonzero if CONTEXT_DIE is a class. */
- static inline int
- class_scope_p (dw_die_ref context_die)
- {
- return (context_die
- && (context_die->die_tag == DW_TAG_structure_type
- || context_die->die_tag == DW_TAG_class_type
- || context_die->die_tag == DW_TAG_interface_type
- || context_die->die_tag == DW_TAG_union_type));
- }
- /* Returns nonzero if CONTEXT_DIE is a class or namespace, for deciding
- whether or not to treat a DIE in this context as a declaration. */
- static inline int
- class_or_namespace_scope_p (dw_die_ref context_die)
- {
- return (class_scope_p (context_die)
- || (context_die && context_die->die_tag == DW_TAG_namespace));
- }
- /* Many forms of DIEs require a "type description" attribute. This
- routine locates the proper "type descriptor" die for the type given
- by 'type' plus any additional qualifiers given by 'cv_quals', and
- adds a DW_AT_type attribute below the given die. */
- static void
- add_type_attribute (dw_die_ref object_die, tree type, int cv_quals,
- dw_die_ref context_die)
- {
- enum tree_code code = TREE_CODE (type);
- dw_die_ref type_die = NULL;
- /* ??? If this type is an unnamed subrange type of an integral, floating-point
- or fixed-point type, use the inner type. This is because we have no
- support for unnamed types in base_type_die. This can happen if this is
- an Ada subrange type. Correct solution is emit a subrange type die. */
- if ((code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE)
- && TREE_TYPE (type) != 0 && TYPE_NAME (type) == 0)
- type = TREE_TYPE (type), code = TREE_CODE (type);
- if (code == ERROR_MARK
- /* Handle a special case. For functions whose return type is void, we
- generate *no* type attribute. (Note that no object may have type
- `void', so this only applies to function return types). */
- || code == VOID_TYPE)
- return;
- type_die = modified_type_die (type,
- cv_quals | TYPE_QUALS_NO_ADDR_SPACE (type),
- context_die);
- if (type_die != NULL)
- add_AT_die_ref (object_die, DW_AT_type, type_die);
- }
- /* Given an object die, add the calling convention attribute for the
- function call type. */
- static void
- add_calling_convention_attribute (dw_die_ref subr_die, tree decl)
- {
- enum dwarf_calling_convention value = DW_CC_normal;
- value = ((enum dwarf_calling_convention)
- targetm.dwarf_calling_convention (TREE_TYPE (decl)));
- if (is_fortran ()
- && !strcmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), "MAIN__"))
- {
- /* DWARF 2 doesn't provide a way to identify a program's source-level
- entry point. DW_AT_calling_convention attributes are only meant
- to describe functions' calling conventions. However, lacking a
- better way to signal the Fortran main program, we used this for
- a long time, following existing custom. Now, DWARF 4 has
- DW_AT_main_subprogram, which we add below, but some tools still
- rely on the old way, which we thus keep. */
- value = DW_CC_program;
- if (dwarf_version >= 4 || !dwarf_strict)
- add_AT_flag (subr_die, DW_AT_main_subprogram, 1);
- }
- /* Only add the attribute if the backend requests it, and
- is not DW_CC_normal. */
- if (value && (value != DW_CC_normal))
- add_AT_unsigned (subr_die, DW_AT_calling_convention, value);
- }
- /* Given a tree pointer to a struct, class, union, or enum type node, return
- a pointer to the (string) tag name for the given type, or zero if the type
- was declared without a tag. */
- static const char *
- type_tag (const_tree type)
- {
- const char *name = 0;
- if (TYPE_NAME (type) != 0)
- {
- tree t = 0;
- /* Find the IDENTIFIER_NODE for the type name. */
- if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE
- && !TYPE_NAMELESS (type))
- t = TYPE_NAME (type);
- /* The g++ front end makes the TYPE_NAME of *each* tagged type point to
- a TYPE_DECL node, regardless of whether or not a `typedef' was
- involved. */
- else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
- && ! DECL_IGNORED_P (TYPE_NAME (type)))
- {
- /* We want to be extra verbose. Don't call dwarf_name if
- DECL_NAME isn't set. The default hook for decl_printable_name
- doesn't like that, and in this context it's correct to return
- 0, instead of "<anonymous>" or the like. */
- if (DECL_NAME (TYPE_NAME (type))
- && !DECL_NAMELESS (TYPE_NAME (type)))
- name = lang_hooks.dwarf_name (TYPE_NAME (type), 2);
- }
- /* Now get the name as a string, or invent one. */
- if (!name && t != 0)
- name = IDENTIFIER_POINTER (t);
- }
- return (name == 0 || *name == '\0') ? 0 : name;
- }
- /* Return the type associated with a data member, make a special check
- for bit field types. */
- static inline tree
- member_declared_type (const_tree member)
- {
- return (DECL_BIT_FIELD_TYPE (member)
- ? DECL_BIT_FIELD_TYPE (member) : TREE_TYPE (member));
- }
- /* Get the decl's label, as described by its RTL. This may be different
- from the DECL_NAME name used in the source file. */
- #if 0
- static const char *
- decl_start_label (tree decl)
- {
- rtx x;
- const char *fnname;
- x = DECL_RTL (decl);
- gcc_assert (MEM_P (x));
- x = XEXP (x, 0);
- gcc_assert (GET_CODE (x) == SYMBOL_REF);
- fnname = XSTR (x, 0);
- return fnname;
- }
- #endif
- /* These routines generate the internal representation of the DIE's for
- the compilation unit. Debugging information is collected by walking
- the declaration trees passed in from dwarf2out_decl(). */
- static void
- gen_array_type_die (tree type, dw_die_ref context_die)
- {
- dw_die_ref scope_die = scope_die_for (type, context_die);
- dw_die_ref array_die;
- /* GNU compilers represent multidimensional array types as sequences of one
- dimensional array types whose element types are themselves array types.
- We sometimes squish that down to a single array_type DIE with multiple
- subscripts in the Dwarf debugging info. The draft Dwarf specification
- say that we are allowed to do this kind of compression in C, because
- there is no difference between an array of arrays and a multidimensional
- array. We don't do this for Ada to remain as close as possible to the
- actual representation, which is especially important against the language
- flexibilty wrt arrays of variable size. */
- bool collapse_nested_arrays = !is_ada ();
- tree element_type;
- /* Emit DW_TAG_string_type for Fortran character types (with kind 1 only, as
- DW_TAG_string_type doesn't have DW_AT_type attribute). */
- if (TYPE_STRING_FLAG (type)
- && TREE_CODE (type) == ARRAY_TYPE
- && is_fortran ()
- && TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (char_type_node))
- {
- HOST_WIDE_INT size;
- array_die = new_die (DW_TAG_string_type, scope_die, type);
- add_name_attribute (array_die, type_tag (type));
- equate_type_number_to_die (type, array_die);
- size = int_size_in_bytes (type);
- if (size >= 0)
- add_AT_unsigned (array_die, DW_AT_byte_size, size);
- else if (TYPE_DOMAIN (type) != NULL_TREE
- && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
- && DECL_P (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
- {
- tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
- dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2, NULL);
- size = int_size_in_bytes (TREE_TYPE (szdecl));
- if (loc && size > 0)
- {
- add_AT_location_description (array_die, DW_AT_string_length, loc);
- if (size != DWARF2_ADDR_SIZE)
- add_AT_unsigned (array_die, DW_AT_byte_size, size);
- }
- }
- return;
- }
- array_die = new_die (DW_TAG_array_type, scope_die, type);
- add_name_attribute (array_die, type_tag (type));
- equate_type_number_to_die (type, array_die);
- if (TREE_CODE (type) == VECTOR_TYPE)
- add_AT_flag (array_die, DW_AT_GNU_vector, 1);
- /* For Fortran multidimensional arrays use DW_ORD_col_major ordering. */
- if (is_fortran ()
- && TREE_CODE (type) == ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE
- && !TYPE_STRING_FLAG (TREE_TYPE (type)))
- add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_col_major);
- #if 0
- /* We default the array ordering. SDB will probably do
- the right things even if DW_AT_ordering is not present. It's not even
- an issue until we start to get into multidimensional arrays anyway. If
- SDB is ever caught doing the Wrong Thing for multi-dimensional arrays,
- then we'll have to put the DW_AT_ordering attribute back in. (But if
- and when we find out that we need to put these in, we will only do so
- for multidimensional arrays. */
- add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major);
- #endif
- if (TREE_CODE (type) == VECTOR_TYPE)
- {
- /* For VECTOR_TYPEs we use an array die with appropriate bounds. */
- dw_die_ref subrange_die = new_die (DW_TAG_subrange_type, array_die, NULL);
- add_bound_info (subrange_die, DW_AT_lower_bound, size_zero_node, NULL);
- add_bound_info (subrange_die, DW_AT_upper_bound,
- size_int (TYPE_VECTOR_SUBPARTS (type) - 1), NULL);
- }
- else
- add_subscript_info (array_die, type, collapse_nested_arrays);
- /* Add representation of the type of the elements of this array type and
- emit the corresponding DIE if we haven't done it already. */
- element_type = TREE_TYPE (type);
- if (collapse_nested_arrays)
- while (TREE_CODE (element_type) == ARRAY_TYPE)
- {
- if (TYPE_STRING_FLAG (element_type) && is_fortran ())
- break;
- element_type = TREE_TYPE (element_type);
- }
- add_type_attribute (array_die, element_type, TYPE_UNQUALIFIED, context_die);
- add_gnat_descriptive_type_attribute (array_die, type, context_die);
- if (TYPE_ARTIFICIAL (type))
- add_AT_flag (array_die, DW_AT_artificial, 1);
- if (get_AT (array_die, DW_AT_name))
- add_pubtype (type, array_die);
- }
- /* This routine generates DIE for array with hidden descriptor, details
- are filled into *info by a langhook. */
- static void
- gen_descr_array_type_die (tree type, struct array_descr_info *info,
- dw_die_ref context_die)
- {
- const dw_die_ref scope_die = scope_die_for (type, context_die);
- const dw_die_ref array_die = new_die (DW_TAG_array_type, scope_die, type);
- const struct loc_descr_context context = { type, info->base_decl };
- int dim;
- add_name_attribute (array_die, type_tag (type));
- equate_type_number_to_die (type, array_die);
- if (info->ndimensions > 1)
- switch (info->ordering)
- {
- case array_descr_ordering_row_major:
- add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major);
- break;
- case array_descr_ordering_column_major:
- add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_col_major);
- break;
- default:
- break;
- }
- if (dwarf_version >= 3 || !dwarf_strict)
- {
- if (info->data_location)
- add_scalar_info (array_die, DW_AT_data_location, info->data_location,
- dw_scalar_form_exprloc, &context);
- if (info->associated)
- add_scalar_info (array_die, DW_AT_associated, info->associated,
- dw_scalar_form_constant
- | dw_scalar_form_exprloc
- | dw_scalar_form_reference, &context);
- if (info->allocated)
- add_scalar_info (array_die, DW_AT_allocated, info->allocated,
- dw_scalar_form_constant
- | dw_scalar_form_exprloc
- | dw_scalar_form_reference, &context);
- }
- add_gnat_descriptive_type_attribute (array_die, type, context_die);
- for (dim = 0; dim < info->ndimensions; dim++)
- {
- dw_die_ref subrange_die
- = new_die (DW_TAG_subrange_type, array_die, NULL);
- if (info->dimen[dim].bounds_type)
- add_type_attribute (subrange_die,
- info->dimen[dim].bounds_type, 0,
- context_die);
- if (info->dimen[dim].lower_bound)
- add_bound_info (subrange_die, DW_AT_lower_bound,
- info->dimen[dim].lower_bound, &context);
- if (info->dimen[dim].upper_bound)
- add_bound_info (subrange_die, DW_AT_upper_bound,
- info->dimen[dim].upper_bound, &context);
- if ((dwarf_version >= 3 || !dwarf_strict) && info->dimen[dim].stride)
- add_scalar_info (subrange_die, DW_AT_byte_stride,
- info->dimen[dim].stride,
- dw_scalar_form_constant
- | dw_scalar_form_exprloc
- | dw_scalar_form_reference,
- &context);
- }
- gen_type_die (info->element_type, context_die);
- add_type_attribute (array_die, info->element_type, TYPE_UNQUALIFIED,
- context_die);
- if (get_AT (array_die, DW_AT_name))
- add_pubtype (type, array_die);
- }
- #if 0
- static void
- gen_entry_point_die (tree decl, dw_die_ref context_die)
- {
- tree origin = decl_ultimate_origin (decl);
- dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die, decl);
- if (origin != NULL)
- add_abstract_origin_attribute (decl_die, origin);
- else
- {
- add_name_and_src_coords_attributes (decl_die, decl);
- add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)),
- TYPE_UNQUALIFIED, context_die);
- }
- if (DECL_ABSTRACT_P (decl))
- equate_decl_number_to_die (decl, decl_die);
- else
- add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
- }
- #endif
- /* Walk through the list of incomplete types again, trying once more to
- emit full debugging info for them. */
- static void
- retry_incomplete_types (void)
- {
- int i;
- for (i = vec_safe_length (incomplete_types) - 1; i >= 0; i--)
- if (should_emit_struct_debug ((*incomplete_types)[i], DINFO_USAGE_DIR_USE))
- gen_type_die ((*incomplete_types)[i], comp_unit_die ());
- }
- /* Determine what tag to use for a record type. */
- static enum dwarf_tag
- record_type_tag (tree type)
- {
- if (! lang_hooks.types.classify_record)
- return DW_TAG_structure_type;
- switch (lang_hooks.types.classify_record (type))
- {
- case RECORD_IS_STRUCT:
- return DW_TAG_structure_type;
- case RECORD_IS_CLASS:
- return DW_TAG_class_type;
- case RECORD_IS_INTERFACE:
- if (dwarf_version >= 3 || !dwarf_strict)
- return DW_TAG_interface_type;
- return DW_TAG_structure_type;
- default:
- gcc_unreachable ();
- }
- }
- /* Generate a DIE to represent an enumeration type. Note that these DIEs
- include all of the information about the enumeration values also. Each
- enumerated type name/value is listed as a child of the enumerated type
- DIE. */
- static dw_die_ref
- gen_enumeration_type_die (tree type, dw_die_ref context_die)
- {
- dw_die_ref type_die = lookup_type_die (type);
- if (type_die == NULL)
- {
- type_die = new_die (DW_TAG_enumeration_type,
- scope_die_for (type, context_die), type);
- equate_type_number_to_die (type, type_die);
- add_name_attribute (type_die, type_tag (type));
- if (dwarf_version >= 4 || !dwarf_strict)
- {
- if (ENUM_IS_SCOPED (type))
- add_AT_flag (type_die, DW_AT_enum_class, 1);
- if (ENUM_IS_OPAQUE (type))
- add_AT_flag (type_die, DW_AT_declaration, 1);
- }
- }
- else if (! TYPE_SIZE (type))
- return type_die;
- else
- remove_AT (type_die, DW_AT_declaration);
- /* Handle a GNU C/C++ extension, i.e. incomplete enum types. If the
- given enum type is incomplete, do not generate the DW_AT_byte_size
- attribute or the DW_AT_element_list attribute. */
- if (TYPE_SIZE (type))
- {
- tree link;
- TREE_ASM_WRITTEN (type) = 1;
- add_byte_size_attribute (type_die, type);
- if (dwarf_version >= 3 || !dwarf_strict)
- {
- tree underlying = lang_hooks.types.enum_underlying_base_type (type);
- add_type_attribute (type_die, underlying, TYPE_UNQUALIFIED,
- context_die);
- }
- if (TYPE_STUB_DECL (type) != NULL_TREE)
- {
- add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
- add_accessibility_attribute (type_die, TYPE_STUB_DECL (type));
- }
- /* If the first reference to this type was as the return type of an
- inline function, then it may not have a parent. Fix this now. */
- if (type_die->die_parent == NULL)
- add_child_die (scope_die_for (type, context_die), type_die);
- for (link = TYPE_VALUES (type);
- link != NULL; link = TREE_CHAIN (link))
- {
- dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die, link);
- tree value = TREE_VALUE (link);
- add_name_attribute (enum_die,
- IDENTIFIER_POINTER (TREE_PURPOSE (link)));
- if (TREE_CODE (value) == CONST_DECL)
- value = DECL_INITIAL (value);
- if (simple_type_size_in_bits (TREE_TYPE (value))
- <= HOST_BITS_PER_WIDE_INT || tree_fits_shwi_p (value))
- {
- /* For constant forms created by add_AT_unsigned DWARF
- consumers (GDB, elfutils, etc.) always zero extend
- the value. Only when the actual value is negative
- do we need to use add_AT_int to generate a constant
- form that can represent negative values. */
- HOST_WIDE_INT val = TREE_INT_CST_LOW (value);
- if (TYPE_UNSIGNED (TREE_TYPE (value)) || val >= 0)
- add_AT_unsigned (enum_die, DW_AT_const_value,
- (unsigned HOST_WIDE_INT) val);
- else
- add_AT_int (enum_die, DW_AT_const_value, val);
- }
- else
- /* Enumeration constants may be wider than HOST_WIDE_INT. Handle
- that here. TODO: This should be re-worked to use correct
- signed/unsigned double tags for all cases. */
- add_AT_wide (enum_die, DW_AT_const_value, value);
- }
- add_gnat_descriptive_type_attribute (type_die, type, context_die);
- if (TYPE_ARTIFICIAL (type))
- add_AT_flag (type_die, DW_AT_artificial, 1);
- }
- else
- add_AT_flag (type_die, DW_AT_declaration, 1);
- add_pubtype (type, type_die);
- return type_die;
- }
- /* Generate a DIE to represent either a real live formal parameter decl or to
- represent just the type of some formal parameter position in some function
- type.
- Note that this routine is a bit unusual because its argument may be a
- ..._DECL node (i.e. either a PARM_DECL or perhaps a VAR_DECL which
- represents an inlining of some PARM_DECL) or else some sort of a ..._TYPE
- node. If it's the former then this function is being called to output a
- DIE to represent a formal parameter object (or some inlining thereof). If
- it's the latter, then this function is only being called to output a
- DW_TAG_formal_parameter DIE to stand as a placeholder for some formal
- argument type of some subprogram type.
- If EMIT_NAME_P is true, name and source coordinate attributes
- are emitted. */
- static dw_die_ref
- gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
- dw_die_ref context_die)
- {
- tree node_or_origin = node ? node : origin;
- tree ultimate_origin;
- dw_die_ref parm_die
- = new_die (DW_TAG_formal_parameter, context_die, node);
- switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin)))
- {
- case tcc_declaration:
- ultimate_origin = decl_ultimate_origin (node_or_origin);
- if (node || ultimate_origin)
- origin = ultimate_origin;
- if (origin != NULL)
- add_abstract_origin_attribute (parm_die, origin);
- else if (emit_name_p)
- add_name_and_src_coords_attributes (parm_die, node);
- if (origin == NULL
- || (! DECL_ABSTRACT_P (node_or_origin)
- && variably_modified_type_p (TREE_TYPE (node_or_origin),
- decl_function_context
- (node_or_origin))))
- {
- tree type = TREE_TYPE (node_or_origin);
- if (decl_by_reference_p (node_or_origin))
- add_type_attribute (parm_die, TREE_TYPE (type),
- TYPE_UNQUALIFIED, context_die);
- else
- add_type_attribute (parm_die, type,
- decl_quals (node_or_origin),
- context_die);
- }
- if (origin == NULL && DECL_ARTIFICIAL (node))
- add_AT_flag (parm_die, DW_AT_artificial, 1);
- if (node && node != origin)
- equate_decl_number_to_die (node, parm_die);
- if (! DECL_ABSTRACT_P (node_or_origin))
- add_location_or_const_value_attribute (parm_die, node_or_origin,
- node == NULL, DW_AT_location);
- break;
- case tcc_type:
- /* We were called with some kind of a ..._TYPE node. */
- add_type_attribute (parm_die, node_or_origin, TYPE_UNQUALIFIED,
- context_die);
- break;
- default:
- gcc_unreachable ();
- }
- return parm_die;
- }
- /* Generate and return a DW_TAG_GNU_formal_parameter_pack. Also generate
- children DW_TAG_formal_parameter DIEs representing the arguments of the
- parameter pack.
- PARM_PACK must be a function parameter pack.
- PACK_ARG is the first argument of the parameter pack. Its TREE_CHAIN
- must point to the subsequent arguments of the function PACK_ARG belongs to.
- SUBR_DIE is the DIE of the function PACK_ARG belongs to.
- If NEXT_ARG is non NULL, *NEXT_ARG is set to the function argument
- following the last one for which a DIE was generated. */
- static dw_die_ref
- gen_formal_parameter_pack_die (tree parm_pack,
- tree pack_arg,
- dw_die_ref subr_die,
- tree *next_arg)
- {
- tree arg;
- dw_die_ref parm_pack_die;
- gcc_assert (parm_pack
- && lang_hooks.function_parameter_pack_p (parm_pack)
- && subr_die);
- parm_pack_die = new_die (DW_TAG_GNU_formal_parameter_pack, subr_die, parm_pack);
- add_src_coords_attributes (parm_pack_die, parm_pack);
- for (arg = pack_arg; arg; arg = DECL_CHAIN (arg))
- {
- if (! lang_hooks.decls.function_parm_expanded_from_pack_p (arg,
- parm_pack))
- break;
- gen_formal_parameter_die (arg, NULL,
- false /* Don't emit name attribute. */,
- parm_pack_die);
- }
- if (next_arg)
- *next_arg = arg;
- return parm_pack_die;
- }
- /* Generate a special type of DIE used as a stand-in for a trailing ellipsis
- at the end of an (ANSI prototyped) formal parameters list. */
- static void
- gen_unspecified_parameters_die (tree decl_or_type, dw_die_ref context_die)
- {
- new_die (DW_TAG_unspecified_parameters, context_die, decl_or_type);
- }
- /* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a
- DW_TAG_unspecified_parameters DIE) to represent the types of the formal
- parameters as specified in some function type specification (except for
- those which appear as part of a function *definition*). */
- static void
- gen_formal_types_die (tree function_or_method_type, dw_die_ref context_die)
- {
- tree link;
- tree formal_type = NULL;
- tree first_parm_type;
- tree arg;
- if (TREE_CODE (function_or_method_type) == FUNCTION_DECL)
- {
- arg = DECL_ARGUMENTS (function_or_method_type);
- function_or_method_type = TREE_TYPE (function_or_method_type);
- }
- else
- arg = NULL_TREE;
- first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
- /* Make our first pass over the list of formal parameter types and output a
- DW_TAG_formal_parameter DIE for each one. */
- for (link = first_parm_type; link; )
- {
- dw_die_ref parm_die;
- formal_type = TREE_VALUE (link);
- if (formal_type == void_type_node)
- break;
- /* Output a (nameless) DIE to represent the formal parameter itself. */
- if (!POINTER_BOUNDS_TYPE_P (formal_type))
- {
- parm_die = gen_formal_parameter_die (formal_type, NULL,
- true /* Emit name attribute. */,
- context_die);
- if (TREE_CODE (function_or_method_type) == METHOD_TYPE
- && link == first_parm_type)
- {
- add_AT_flag (parm_die, DW_AT_artificial, 1);
- if (dwarf_version >= 3 || !dwarf_strict)
- add_AT_die_ref (context_die, DW_AT_object_pointer, parm_die);
- }
- else if (arg && DECL_ARTIFICIAL (arg))
- add_AT_flag (parm_die, DW_AT_artificial, 1);
- }
- link = TREE_CHAIN (link);
- if (arg)
- arg = DECL_CHAIN (arg);
- }
- /* If this function type has an ellipsis, add a
- DW_TAG_unspecified_parameters DIE to the end of the parameter list. */
- if (formal_type != void_type_node)
- gen_unspecified_parameters_die (function_or_method_type, context_die);
- /* Make our second (and final) pass over the list of formal parameter types
- and output DIEs to represent those types (as necessary). */
- for (link = TYPE_ARG_TYPES (function_or_method_type);
- link && TREE_VALUE (link);
- link = TREE_CHAIN (link))
- gen_type_die (TREE_VALUE (link), context_die);
- }
- /* We want to generate the DIE for TYPE so that we can generate the
- die for MEMBER, which has been defined; we will need to refer back
- to the member declaration nested within TYPE. If we're trying to
- generate minimal debug info for TYPE, processing TYPE won't do the
- trick; we need to attach the member declaration by hand. */
- static void
- gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
- {
- gen_type_die (type, context_die);
- /* If we're trying to avoid duplicate debug info, we may not have
- emitted the member decl for this function. Emit it now. */
- if (TYPE_STUB_DECL (type)
- && TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
- && ! lookup_decl_die (member))
- {
- dw_die_ref type_die;
- gcc_assert (!decl_ultimate_origin (member));
- push_decl_scope (type);
- type_die = lookup_type_die_strip_naming_typedef (type);
- if (TREE_CODE (member) == FUNCTION_DECL)
- gen_subprogram_die (member, type_die);
- else if (TREE_CODE (member) == FIELD_DECL)
- {
- /* Ignore the nameless fields that are used to skip bits but handle
- C++ anonymous unions and structs. */
- if (DECL_NAME (member) != NULL_TREE
- || TREE_CODE (TREE_TYPE (member)) == UNION_TYPE
- || TREE_CODE (TREE_TYPE (member)) == RECORD_TYPE)
- {
- gen_type_die (member_declared_type (member), type_die);
- gen_field_die (member, type_die);
- }
- }
- else
- gen_variable_die (member, NULL_TREE, type_die);
- pop_decl_scope ();
- }
- }
- /* Forward declare these functions, because they are mutually recursive
- with their set_block_* pairing functions. */
- static void set_decl_origin_self (tree);
- static void set_decl_abstract_flags (tree, vec<tree> &);
- /* Given a pointer to some BLOCK node, if the BLOCK_ABSTRACT_ORIGIN for the
- given BLOCK node is NULL, set the BLOCK_ABSTRACT_ORIGIN for the node so
- that it points to the node itself, thus indicating that the node is its
- own (abstract) origin. Additionally, if the BLOCK_ABSTRACT_ORIGIN for
- the given node is NULL, recursively descend the decl/block tree which
- it is the root of, and for each other ..._DECL or BLOCK node contained
- therein whose DECL_ABSTRACT_ORIGINs or BLOCK_ABSTRACT_ORIGINs are also
- still NULL, set *their* DECL_ABSTRACT_ORIGIN or BLOCK_ABSTRACT_ORIGIN
- values to point to themselves. */
- static void
- set_block_origin_self (tree stmt)
- {
- if (BLOCK_ABSTRACT_ORIGIN (stmt) == NULL_TREE)
- {
- BLOCK_ABSTRACT_ORIGIN (stmt) = stmt;
- {
- tree local_decl;
- for (local_decl = BLOCK_VARS (stmt);
- local_decl != NULL_TREE;
- local_decl = DECL_CHAIN (local_decl))
- /* Do not recurse on nested functions since the inlining status
- of parent and child can be different as per the DWARF spec. */
- if (TREE_CODE (local_decl) != FUNCTION_DECL
- && !DECL_EXTERNAL (local_decl))
- set_decl_origin_self (local_decl);
- }
- {
- tree subblock;
- for (subblock = BLOCK_SUBBLOCKS (stmt);
- subblock != NULL_TREE;
- subblock = BLOCK_CHAIN (subblock))
- set_block_origin_self (subblock); /* Recurse. */
- }
- }
- }
- /* Given a pointer to some ..._DECL node, if the DECL_ABSTRACT_ORIGIN for
- the given ..._DECL node is NULL, set the DECL_ABSTRACT_ORIGIN for the
- node to so that it points to the node itself, thus indicating that the
- node represents its own (abstract) origin. Additionally, if the
- DECL_ABSTRACT_ORIGIN for the given node is NULL, recursively descend
- the decl/block tree of which the given node is the root of, and for
- each other ..._DECL or BLOCK node contained therein whose
- DECL_ABSTRACT_ORIGINs or BLOCK_ABSTRACT_ORIGINs are also still NULL,
- set *their* DECL_ABSTRACT_ORIGIN or BLOCK_ABSTRACT_ORIGIN values to
- point to themselves. */
- static void
- set_decl_origin_self (tree decl)
- {
- if (DECL_ABSTRACT_ORIGIN (decl) == NULL_TREE)
- {
- DECL_ABSTRACT_ORIGIN (decl) = decl;
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- tree arg;
- for (arg = DECL_ARGUMENTS (decl); arg; arg = DECL_CHAIN (arg))
- DECL_ABSTRACT_ORIGIN (arg) = arg;
- if (DECL_INITIAL (decl) != NULL_TREE
- && DECL_INITIAL (decl) != error_mark_node)
- set_block_origin_self (DECL_INITIAL (decl));
- }
- }
- }
- /* Given a pointer to some BLOCK node, set the BLOCK_ABSTRACT flag to 1
- and if it wasn't 1 before, push it to abstract_vec vector.
- For all local decls and all local sub-blocks (recursively) do it
- too. */
- static void
- set_block_abstract_flags (tree stmt, vec<tree> &abstract_vec)
- {
- tree local_decl;
- tree subblock;
- unsigned int i;
- if (!BLOCK_ABSTRACT (stmt))
- {
- abstract_vec.safe_push (stmt);
- BLOCK_ABSTRACT (stmt) = 1;
- }
- for (local_decl = BLOCK_VARS (stmt);
- local_decl != NULL_TREE;
- local_decl = DECL_CHAIN (local_decl))
- if (! DECL_EXTERNAL (local_decl))
- set_decl_abstract_flags (local_decl, abstract_vec);
- for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
- {
- local_decl = BLOCK_NONLOCALIZED_VAR (stmt, i);
- if ((TREE_CODE (local_decl) == VAR_DECL && !TREE_STATIC (local_decl))
- || TREE_CODE (local_decl) == PARM_DECL)
- set_decl_abstract_flags (local_decl, abstract_vec);
- }
- for (subblock = BLOCK_SUBBLOCKS (stmt);
- subblock != NULL_TREE;
- subblock = BLOCK_CHAIN (subblock))
- set_block_abstract_flags (subblock, abstract_vec);
- }
- /* Given a pointer to some ..._DECL node, set DECL_ABSTRACT_P flag on it
- to 1 and if it wasn't 1 before, push to abstract_vec vector.
- In the case where the decl is a FUNCTION_DECL also set the abstract
- flags for all of the parameters, local vars, local
- blocks and sub-blocks (recursively). */
- static void
- set_decl_abstract_flags (tree decl, vec<tree> &abstract_vec)
- {
- if (!DECL_ABSTRACT_P (decl))
- {
- abstract_vec.safe_push (decl);
- DECL_ABSTRACT_P (decl) = 1;
- }
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- tree arg;
- for (arg = DECL_ARGUMENTS (decl); arg; arg = DECL_CHAIN (arg))
- if (!DECL_ABSTRACT_P (arg))
- {
- abstract_vec.safe_push (arg);
- DECL_ABSTRACT_P (arg) = 1;
- }
- if (DECL_INITIAL (decl) != NULL_TREE
- && DECL_INITIAL (decl) != error_mark_node)
- set_block_abstract_flags (DECL_INITIAL (decl), abstract_vec);
- }
- }
- /* Generate the DWARF2 info for the "abstract" instance of a function which we
- may later generate inlined and/or out-of-line instances of. */
- static void
- dwarf2out_abstract_function (tree decl)
- {
- dw_die_ref old_die;
- tree save_fn;
- tree context;
- hash_table<decl_loc_hasher> *old_decl_loc_table;
- hash_table<dw_loc_list_hasher> *old_cached_dw_loc_list_table;
- int old_call_site_count, old_tail_call_site_count;
- struct call_arg_loc_node *old_call_arg_locations;
- /* Make sure we have the actual abstract inline, not a clone. */
- decl = DECL_ORIGIN (decl);
- old_die = lookup_decl_die (decl);
- if (old_die && get_AT (old_die, DW_AT_inline))
- /* We've already generated the abstract instance. */
- return;
- /* We can be called while recursively when seeing block defining inlined subroutine
- DIE. Be sure to not clobber the outer location table nor use it or we would
- get locations in abstract instantces. */
- old_decl_loc_table = decl_loc_table;
- decl_loc_table = NULL;
- old_cached_dw_loc_list_table = cached_dw_loc_list_table;
- cached_dw_loc_list_table = NULL;
- old_call_arg_locations = call_arg_locations;
- call_arg_locations = NULL;
- old_call_site_count = call_site_count;
- call_site_count = -1;
- old_tail_call_site_count = tail_call_site_count;
- tail_call_site_count = -1;
- /* Be sure we've emitted the in-class declaration DIE (if any) first, so
- we don't get confused by DECL_ABSTRACT_P. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
- {
- context = decl_class_context (decl);
- if (context)
- gen_type_die_for_member
- (context, decl, decl_function_context (decl) ? NULL : comp_unit_die ());
- }
- /* Pretend we've just finished compiling this function. */
- save_fn = current_function_decl;
- current_function_decl = decl;
- auto_vec<tree, 64> abstract_vec;
- set_decl_abstract_flags (decl, abstract_vec);
- dwarf2out_decl (decl);
- unsigned int i;
- tree t;
- FOR_EACH_VEC_ELT (abstract_vec, i, t)
- if (TREE_CODE (t) == BLOCK)
- BLOCK_ABSTRACT (t) = 0;
- else
- DECL_ABSTRACT_P (t) = 0;
- current_function_decl = save_fn;
- decl_loc_table = old_decl_loc_table;
- cached_dw_loc_list_table = old_cached_dw_loc_list_table;
- call_arg_locations = old_call_arg_locations;
- call_site_count = old_call_site_count;
- tail_call_site_count = old_tail_call_site_count;
- }
- /* Helper function of premark_used_types() which gets called through
- htab_traverse.
- Marks the DIE of a given type in *SLOT as perennial, so it never gets
- marked as unused by prune_unused_types. */
- bool
- premark_used_types_helper (tree const &type, void *)
- {
- dw_die_ref die;
- die = lookup_type_die (type);
- if (die != NULL)
- die->die_perennial_p = 1;
- return true;
- }
- /* Helper function of premark_types_used_by_global_vars which gets called
- through htab_traverse.
- Marks the DIE of a given type in *SLOT as perennial, so it never gets
- marked as unused by prune_unused_types. The DIE of the type is marked
- only if the global variable using the type will actually be emitted. */
- int
- premark_types_used_by_global_vars_helper (types_used_by_vars_entry **slot,
- void *)
- {
- struct types_used_by_vars_entry *entry;
- dw_die_ref die;
- entry = (struct types_used_by_vars_entry *) *slot;
- gcc_assert (entry->type != NULL
- && entry->var_decl != NULL);
- die = lookup_type_die (entry->type);
- if (die)
- {
- /* Ask cgraph if the global variable really is to be emitted.
- If yes, then we'll keep the DIE of ENTRY->TYPE. */
- varpool_node *node = varpool_node::get (entry->var_decl);
- if (node && node->definition)
- {
- die->die_perennial_p = 1;
- /* Keep the parent DIEs as well. */
- while ((die = die->die_parent) && die->die_perennial_p == 0)
- die->die_perennial_p = 1;
- }
- }
- return 1;
- }
- /* Mark all members of used_types_hash as perennial. */
- static void
- premark_used_types (struct function *fun)
- {
- if (fun && fun->used_types_hash)
- fun->used_types_hash->traverse<void *, premark_used_types_helper> (NULL);
- }
- /* Mark all members of types_used_by_vars_entry as perennial. */
- static void
- premark_types_used_by_global_vars (void)
- {
- if (types_used_by_vars_hash)
- types_used_by_vars_hash
- ->traverse<void *, premark_types_used_by_global_vars_helper> (NULL);
- }
- /* Generate a DW_TAG_GNU_call_site DIE in function DECL under SUBR_DIE
- for CA_LOC call arg loc node. */
- static dw_die_ref
- gen_call_site_die (tree decl, dw_die_ref subr_die,
- struct call_arg_loc_node *ca_loc)
- {
- dw_die_ref stmt_die = NULL, die;
- tree block = ca_loc->block;
- while (block
- && block != DECL_INITIAL (decl)
- && TREE_CODE (block) == BLOCK)
- {
- if (block_map.length () > BLOCK_NUMBER (block))
- stmt_die = block_map[BLOCK_NUMBER (block)];
- if (stmt_die)
- break;
- block = BLOCK_SUPERCONTEXT (block);
- }
- if (stmt_die == NULL)
- stmt_die = subr_die;
- die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
- add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
- if (ca_loc->tail_call_p)
- add_AT_flag (die, DW_AT_GNU_tail_call, 1);
- if (ca_loc->symbol_ref)
- {
- dw_die_ref tdie = lookup_decl_die (SYMBOL_REF_DECL (ca_loc->symbol_ref));
- if (tdie)
- add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
- else
- add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref, false);
- }
- return die;
- }
- /* Generate a DIE to represent a declared function (either file-scope or
- block-local). */
- static void
- gen_subprogram_die (tree decl, dw_die_ref context_die)
- {
- tree origin = decl_ultimate_origin (decl);
- dw_die_ref subr_die;
- tree outer_scope;
- dw_die_ref old_die = lookup_decl_die (decl);
- int declaration = (current_function_decl != decl
- || class_or_namespace_scope_p (context_die));
- premark_used_types (DECL_STRUCT_FUNCTION (decl));
- /* It is possible to have both DECL_ABSTRACT_P and DECLARATION be true if we
- started to generate the abstract instance of an inline, decided to output
- its containing class, and proceeded to emit the declaration of the inline
- from the member list for the class. If so, DECLARATION takes priority;
- we'll get back to the abstract instance when done with the class. */
- /* The class-scope declaration DIE must be the primary DIE. */
- if (origin && declaration && class_or_namespace_scope_p (context_die))
- {
- origin = NULL;
- gcc_assert (!old_die);
- }
- /* Now that the C++ front end lazily declares artificial member fns, we
- might need to retrofit the declaration into its class. */
- if (!declaration && !origin && !old_die
- && DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))
- && !class_or_namespace_scope_p (context_die)
- && debug_info_level > DINFO_LEVEL_TERSE)
- old_die = force_decl_die (decl);
- if (origin != NULL)
- {
- gcc_assert (!declaration || local_scope_p (context_die));
- /* Fixup die_parent for the abstract instance of a nested
- inline function. */
- if (old_die && old_die->die_parent == NULL)
- add_child_die (context_die, old_die);
- subr_die = new_die (DW_TAG_subprogram, context_die, decl);
- add_abstract_origin_attribute (subr_die, origin);
- /* This is where the actual code for a cloned function is.
- Let's emit linkage name attribute for it. This helps
- debuggers to e.g, set breakpoints into
- constructors/destructors when the user asks "break
- K::K". */
- add_linkage_name (subr_die, decl);
- }
- else if (old_die)
- {
- expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
- struct dwarf_file_data * file_index = lookup_filename (s.file);
- if (!get_AT_flag (old_die, DW_AT_declaration)
- /* We can have a normal definition following an inline one in the
- case of redefinition of GNU C extern inlines.
- It seems reasonable to use AT_specification in this case. */
- && !get_AT (old_die, DW_AT_inline))
- {
- /* Detect and ignore this case, where we are trying to output
- something we have already output. */
- return;
- }
- /* If the definition comes from the same place as the declaration,
- maybe use the old DIE. We always want the DIE for this function
- that has the *_pc attributes to be under comp_unit_die so the
- debugger can find it. We also need to do this for abstract
- instances of inlines, since the spec requires the out-of-line copy
- to have the same parent. For local class methods, this doesn't
- apply; we just use the old DIE. */
- if ((is_cu_die (old_die->die_parent) || context_die == NULL)
- && (DECL_ARTIFICIAL (decl)
- || (get_AT_file (old_die, DW_AT_decl_file) == file_index
- && (get_AT_unsigned (old_die, DW_AT_decl_line)
- == (unsigned) s.line))))
- {
- subr_die = old_die;
- /* Clear out the declaration attribute and the formal parameters.
- Do not remove all children, because it is possible that this
- declaration die was forced using force_decl_die(). In such
- cases die that forced declaration die (e.g. TAG_imported_module)
- is one of the children that we do not want to remove. */
- remove_AT (subr_die, DW_AT_declaration);
- remove_AT (subr_die, DW_AT_object_pointer);
- remove_child_TAG (subr_die, DW_TAG_formal_parameter);
- }
- else
- {
- subr_die = new_die (DW_TAG_subprogram, context_die, decl);
- add_AT_specification (subr_die, old_die);
- add_pubname (decl, subr_die);
- if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
- add_AT_file (subr_die, DW_AT_decl_file, file_index);
- if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
- add_AT_unsigned (subr_die, DW_AT_decl_line, s.line);
- /* If the prototype had an 'auto' or 'decltype(auto)' return type,
- emit the real type on the definition die. */
- if (is_cxx() && debug_info_level > DINFO_LEVEL_TERSE)
- {
- dw_die_ref die = get_AT_ref (old_die, DW_AT_type);
- if (die == auto_die || die == decltype_auto_die)
- add_type_attribute (subr_die, TREE_TYPE (TREE_TYPE (decl)),
- TYPE_UNQUALIFIED, context_die);
- }
- }
- }
- else
- {
- subr_die = new_die (DW_TAG_subprogram, context_die, decl);
- if (TREE_PUBLIC (decl))
- add_AT_flag (subr_die, DW_AT_external, 1);
- add_name_and_src_coords_attributes (subr_die, decl);
- add_pubname (decl, subr_die);
- if (debug_info_level > DINFO_LEVEL_TERSE)
- {
- add_prototyped_attribute (subr_die, TREE_TYPE (decl));
- add_type_attribute (subr_die, TREE_TYPE (TREE_TYPE (decl)),
- TYPE_UNQUALIFIED, context_die);
- }
- add_pure_or_virtual_attribute (subr_die, decl);
- if (DECL_ARTIFICIAL (decl))
- add_AT_flag (subr_die, DW_AT_artificial, 1);
- if (TREE_THIS_VOLATILE (decl) && (dwarf_version >= 5 || !dwarf_strict))
- add_AT_flag (subr_die, DW_AT_noreturn, 1);
- add_accessibility_attribute (subr_die, decl);
- }
- if (declaration)
- {
- if (!old_die || !get_AT (old_die, DW_AT_inline))
- {
- add_AT_flag (subr_die, DW_AT_declaration, 1);
- /* If this is an explicit function declaration then generate
- a DW_AT_explicit attribute. */
- if (lang_hooks.decls.function_decl_explicit_p (decl)
- && (dwarf_version >= 3 || !dwarf_strict))
- add_AT_flag (subr_die, DW_AT_explicit, 1);
- /* If this is a C++11 deleted special function member then generate
- a DW_AT_GNU_deleted attribute. */
- if (lang_hooks.decls.function_decl_deleted_p (decl)
- && (! dwarf_strict))
- add_AT_flag (subr_die, DW_AT_GNU_deleted, 1);
- /* The first time we see a member function, it is in the context of
- the class to which it belongs. We make sure of this by emitting
- the class first. The next time is the definition, which is
- handled above. The two may come from the same source text.
- Note that force_decl_die() forces function declaration die. It is
- later reused to represent definition. */
- equate_decl_number_to_die (decl, subr_die);
- }
- }
- else if (DECL_ABSTRACT_P (decl))
- {
- if (DECL_DECLARED_INLINE_P (decl))
- {
- if (cgraph_function_possibly_inlined_p (decl))
- add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
- else
- add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_not_inlined);
- }
- else
- {
- if (cgraph_function_possibly_inlined_p (decl))
- add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
- else
- add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_not_inlined);
- }
- if (DECL_DECLARED_INLINE_P (decl)
- && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
- add_AT_flag (subr_die, DW_AT_artificial, 1);
- equate_decl_number_to_die (decl, subr_die);
- }
- else if (!DECL_EXTERNAL (decl))
- {
- HOST_WIDE_INT cfa_fb_offset;
- struct function *fun = DECL_STRUCT_FUNCTION (decl);
- if (!old_die || !get_AT (old_die, DW_AT_inline))
- equate_decl_number_to_die (decl, subr_die);
- gcc_checking_assert (fun);
- if (!flag_reorder_blocks_and_partition)
- {
- dw_fde_ref fde = fun->fde;
- if (fde->dw_fde_begin)
- {
- /* We have already generated the labels. */
- add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
- fde->dw_fde_end, false);
- }
- else
- {
- /* Create start/end labels and add the range. */
- char label_id_low[MAX_ARTIFICIAL_LABEL_BYTES];
- char label_id_high[MAX_ARTIFICIAL_LABEL_BYTES];
- ASM_GENERATE_INTERNAL_LABEL (label_id_low, FUNC_BEGIN_LABEL,
- current_function_funcdef_no);
- ASM_GENERATE_INTERNAL_LABEL (label_id_high, FUNC_END_LABEL,
- current_function_funcdef_no);
- add_AT_low_high_pc (subr_die, label_id_low, label_id_high,
- false);
- }
- #if VMS_DEBUGGING_INFO
- /* HP OpenVMS Industry Standard 64: DWARF Extensions
- Section 2.3 Prologue and Epilogue Attributes:
- When a breakpoint is set on entry to a function, it is generally
- desirable for execution to be suspended, not on the very first
- instruction of the function, but rather at a point after the
- function's frame has been set up, after any language defined local
- declaration processing has been completed, and before execution of
- the first statement of the function begins. Debuggers generally
- cannot properly determine where this point is. Similarly for a
- breakpoint set on exit from a function. The prologue and epilogue
- attributes allow a compiler to communicate the location(s) to use. */
- {
- if (fde->dw_fde_vms_end_prologue)
- add_AT_vms_delta (subr_die, DW_AT_HP_prologue,
- fde->dw_fde_begin, fde->dw_fde_vms_end_prologue);
- if (fde->dw_fde_vms_begin_epilogue)
- add_AT_vms_delta (subr_die, DW_AT_HP_epilogue,
- fde->dw_fde_begin, fde->dw_fde_vms_begin_epilogue);
- }
- #endif
- }
- else
- {
- /* Generate pubnames entries for the split function code ranges. */
- dw_fde_ref fde = fun->fde;
- if (fde->dw_fde_second_begin)
- {
- if (dwarf_version >= 3 || !dwarf_strict)
- {
- /* We should use ranges for non-contiguous code section
- addresses. Use the actual code range for the initial
- section, since the HOT/COLD labels might precede an
- alignment offset. */
- bool range_list_added = false;
- add_ranges_by_labels (subr_die, fde->dw_fde_begin,
- fde->dw_fde_end, &range_list_added,
- false);
- add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
- fde->dw_fde_second_end,
- &range_list_added, false);
- if (range_list_added)
- add_ranges (NULL);
- }
- else
- {
- /* There is no real support in DW2 for this .. so we make
- a work-around. First, emit the pub name for the segment
- containing the function label. Then make and emit a
- simplified subprogram DIE for the second segment with the
- name pre-fixed by __hot/cold_sect_of_. We use the same
- linkage name for the second die so that gdb will find both
- sections when given "b foo". */
- const char *name = NULL;
- tree decl_name = DECL_NAME (decl);
- dw_die_ref seg_die;
- /* Do the 'primary' section. */
- add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
- fde->dw_fde_end, false);
- /* Build a minimal DIE for the secondary section. */
- seg_die = new_die (DW_TAG_subprogram,
- subr_die->die_parent, decl);
- if (TREE_PUBLIC (decl))
- add_AT_flag (seg_die, DW_AT_external, 1);
- if (decl_name != NULL
- && IDENTIFIER_POINTER (decl_name) != NULL)
- {
- name = dwarf2_name (decl, 1);
- if (! DECL_ARTIFICIAL (decl))
- add_src_coords_attributes (seg_die, decl);
- add_linkage_name (seg_die, decl);
- }
- gcc_assert (name != NULL);
- add_pure_or_virtual_attribute (seg_die, decl);
- if (DECL_ARTIFICIAL (decl))
- add_AT_flag (seg_die, DW_AT_artificial, 1);
- name = concat ("__second_sect_of_", name, NULL);
- add_AT_low_high_pc (seg_die, fde->dw_fde_second_begin,
- fde->dw_fde_second_end, false);
- add_name_attribute (seg_die, name);
- if (want_pubnames ())
- add_pubname_string (name, seg_die);
- }
- }
- else
- add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end,
- false);
- }
- cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
- /* We define the "frame base" as the function's CFA. This is more
- convenient for several reasons: (1) It's stable across the prologue
- and epilogue, which makes it better than just a frame pointer,
- (2) With dwarf3, there exists a one-byte encoding that allows us
- to reference the .debug_frame data by proxy, but failing that,
- (3) We can at least reuse the code inspection and interpretation
- code that determines the CFA position at various points in the
- function. */
- if (dwarf_version >= 3 && targetm.debug_unwind_info () == UI_DWARF2)
- {
- dw_loc_descr_ref op = new_loc_descr (DW_OP_call_frame_cfa, 0, 0);
- add_AT_loc (subr_die, DW_AT_frame_base, op);
- }
- else
- {
- dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset);
- if (list->dw_loc_next)
- add_AT_loc_list (subr_die, DW_AT_frame_base, list);
- else
- add_AT_loc (subr_die, DW_AT_frame_base, list->expr);
- }
- /* Compute a displacement from the "steady-state frame pointer" to
- the CFA. The former is what all stack slots and argument slots
- will reference in the rtl; the latter is what we've told the
- debugger about. We'll need to adjust all frame_base references
- by this displacement. */
- compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
- if (fun->static_chain_decl)
- add_AT_location_description (subr_die, DW_AT_static_link,
- loc_list_from_tree (fun->static_chain_decl, 2, NULL));
- }
- /* Generate child dies for template paramaters. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
- gen_generic_params_dies (decl);
- /* Now output descriptions of the arguments for this function. This gets
- (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
- for a FUNCTION_DECL doesn't indicate cases where there was a trailing
- `...' at the end of the formal parameter list. In order to find out if
- there was a trailing ellipsis or not, we must instead look at the type
- associated with the FUNCTION_DECL. This will be a node of type
- FUNCTION_TYPE. If the chain of type nodes hanging off of this
- FUNCTION_TYPE node ends with a void_type_node then there should *not* be
- an ellipsis at the end. */
- /* In the case where we are describing a mere function declaration, all we
- need to do here (and all we *can* do here) is to describe the *types* of
- its formal parameters. */
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- ;
- else if (declaration)
- gen_formal_types_die (decl, subr_die);
- else
- {
- /* Generate DIEs to represent all known formal parameters. */
- tree parm = DECL_ARGUMENTS (decl);
- tree generic_decl = lang_hooks.decls.get_generic_function_decl (decl);
- tree generic_decl_parm = generic_decl
- ? DECL_ARGUMENTS (generic_decl)
- : NULL;
- /* Now we want to walk the list of parameters of the function and
- emit their relevant DIEs.
- We consider the case of DECL being an instance of a generic function
- as well as it being a normal function.
- If DECL is an instance of a generic function we walk the
- parameters of the generic function declaration _and_ the parameters of
- DECL itself. This is useful because we want to emit specific DIEs for
- function parameter packs and those are declared as part of the
- generic function declaration. In that particular case,
- the parameter pack yields a DW_TAG_GNU_formal_parameter_pack DIE.
- That DIE has children DIEs representing the set of arguments
- of the pack. Note that the set of pack arguments can be empty.
- In that case, the DW_TAG_GNU_formal_parameter_pack DIE will not have any
- children DIE.
- Otherwise, we just consider the parameters of DECL. */
- while (generic_decl_parm || parm)
- {
- if (generic_decl_parm
- && lang_hooks.function_parameter_pack_p (generic_decl_parm))
- gen_formal_parameter_pack_die (generic_decl_parm,
- parm, subr_die,
- &parm);
- else if (parm && !POINTER_BOUNDS_P (parm))
- {
- dw_die_ref parm_die = gen_decl_die (parm, NULL, subr_die);
- if (parm == DECL_ARGUMENTS (decl)
- && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
- && parm_die
- && (dwarf_version >= 3 || !dwarf_strict))
- add_AT_die_ref (subr_die, DW_AT_object_pointer, parm_die);
- parm = DECL_CHAIN (parm);
- }
- else if (parm)
- parm = DECL_CHAIN (parm);
- if (generic_decl_parm)
- generic_decl_parm = DECL_CHAIN (generic_decl_parm);
- }
- /* Decide whether we need an unspecified_parameters DIE at the end.
- There are 2 more cases to do this for: 1) the ansi ... declaration -
- this is detectable when the end of the arg list is not a
- void_type_node 2) an unprototyped function declaration (not a
- definition). This just means that we have no info about the
- parameters at all. */
- if (prototype_p (TREE_TYPE (decl)))
- {
- /* This is the prototyped case, check for.... */
- if (stdarg_p (TREE_TYPE (decl)))
- gen_unspecified_parameters_die (decl, subr_die);
- }
- else if (DECL_INITIAL (decl) == NULL_TREE)
- gen_unspecified_parameters_die (decl, subr_die);
- }
- /* Output Dwarf info for all of the stuff within the body of the function
- (if it has one - it may be just a declaration). */
- outer_scope = DECL_INITIAL (decl);
- /* OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
- a function. This BLOCK actually represents the outermost binding contour
- for the function, i.e. the contour in which the function's formal
- parameters and labels get declared. Curiously, it appears that the front
- end doesn't actually put the PARM_DECL nodes for the current function onto
- the BLOCK_VARS list for this outer scope, but are strung off of the
- DECL_ARGUMENTS list for the function instead.
- The BLOCK_VARS list for the `outer_scope' does provide us with a list of
- the LABEL_DECL nodes for the function however, and we output DWARF info
- for those in decls_for_scope. Just within the `outer_scope' there will be
- a BLOCK node representing the function's outermost pair of curly braces,
- and any blocks used for the base and member initializers of a C++
- constructor function. */
- if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
- {
- int call_site_note_count = 0;
- int tail_call_site_note_count = 0;
- /* Emit a DW_TAG_variable DIE for a named return value. */
- if (DECL_NAME (DECL_RESULT (decl)))
- gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
- decls_for_scope (outer_scope, subr_die);
- if (call_arg_locations && !dwarf_strict)
- {
- struct call_arg_loc_node *ca_loc;
- for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next)
- {
- dw_die_ref die = NULL;
- rtx tloc = NULL_RTX, tlocc = NULL_RTX;
- rtx arg, next_arg;
- for (arg = NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note);
- arg; arg = next_arg)
- {
- dw_loc_descr_ref reg, val;
- machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1));
- dw_die_ref cdie, tdie = NULL;
- next_arg = XEXP (arg, 1);
- if (REG_P (XEXP (XEXP (arg, 0), 0))
- && next_arg
- && MEM_P (XEXP (XEXP (next_arg, 0), 0))
- && REG_P (XEXP (XEXP (XEXP (next_arg, 0), 0), 0))
- && REGNO (XEXP (XEXP (arg, 0), 0))
- == REGNO (XEXP (XEXP (XEXP (next_arg, 0), 0), 0)))
- next_arg = XEXP (next_arg, 1);
- if (mode == VOIDmode)
- {
- mode = GET_MODE (XEXP (XEXP (arg, 0), 0));
- if (mode == VOIDmode)
- mode = GET_MODE (XEXP (arg, 0));
- }
- if (mode == VOIDmode || mode == BLKmode)
- continue;
- if (XEXP (XEXP (arg, 0), 0) == pc_rtx)
- {
- gcc_assert (ca_loc->symbol_ref == NULL_RTX);
- tloc = XEXP (XEXP (arg, 0), 1);
- continue;
- }
- else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER
- && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx)
- {
- gcc_assert (ca_loc->symbol_ref == NULL_RTX);
- tlocc = XEXP (XEXP (arg, 0), 1);
- continue;
- }
- reg = NULL;
- if (REG_P (XEXP (XEXP (arg, 0), 0)))
- reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0),
- VAR_INIT_STATUS_INITIALIZED);
- else if (MEM_P (XEXP (XEXP (arg, 0), 0)))
- {
- rtx mem = XEXP (XEXP (arg, 0), 0);
- reg = mem_loc_descriptor (XEXP (mem, 0),
- get_address_mode (mem),
- GET_MODE (mem),
- VAR_INIT_STATUS_INITIALIZED);
- }
- else if (GET_CODE (XEXP (XEXP (arg, 0), 0))
- == DEBUG_PARAMETER_REF)
- {
- tree tdecl
- = DEBUG_PARAMETER_REF_DECL (XEXP (XEXP (arg, 0), 0));
- tdie = lookup_decl_die (tdecl);
- if (tdie == NULL)
- continue;
- }
- else
- continue;
- if (reg == NULL
- && GET_CODE (XEXP (XEXP (arg, 0), 0))
- != DEBUG_PARAMETER_REF)
- continue;
- val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), mode,
- VOIDmode,
- VAR_INIT_STATUS_INITIALIZED);
- if (val == NULL)
- continue;
- if (die == NULL)
- die = gen_call_site_die (decl, subr_die, ca_loc);
- cdie = new_die (DW_TAG_GNU_call_site_parameter, die,
- NULL_TREE);
- if (reg != NULL)
- add_AT_loc (cdie, DW_AT_location, reg);
- else if (tdie != NULL)
- add_AT_die_ref (cdie, DW_AT_abstract_origin, tdie);
- add_AT_loc (cdie, DW_AT_GNU_call_site_value, val);
- if (next_arg != XEXP (arg, 1))
- {
- mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 1));
- if (mode == VOIDmode)
- mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 0));
- val = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 1),
- 0), 1),
- mode, VOIDmode,
- VAR_INIT_STATUS_INITIALIZED);
- if (val != NULL)
- add_AT_loc (cdie, DW_AT_GNU_call_site_data_value, val);
- }
- }
- if (die == NULL
- && (ca_loc->symbol_ref || tloc))
- die = gen_call_site_die (decl, subr_die, ca_loc);
- if (die != NULL && (tloc != NULL_RTX || tlocc != NULL_RTX))
- {
- dw_loc_descr_ref tval = NULL;
- if (tloc != NULL_RTX)
- tval = mem_loc_descriptor (tloc,
- GET_MODE (tloc) == VOIDmode
- ? Pmode : GET_MODE (tloc),
- VOIDmode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tval)
- add_AT_loc (die, DW_AT_GNU_call_site_target, tval);
- else if (tlocc != NULL_RTX)
- {
- tval = mem_loc_descriptor (tlocc,
- GET_MODE (tlocc) == VOIDmode
- ? Pmode : GET_MODE (tlocc),
- VOIDmode,
- VAR_INIT_STATUS_INITIALIZED);
- if (tval)
- add_AT_loc (die, DW_AT_GNU_call_site_target_clobbered,
- tval);
- }
- }
- if (die != NULL)
- {
- call_site_note_count++;
- if (ca_loc->tail_call_p)
- tail_call_site_note_count++;
- }
- }
- }
- call_arg_locations = NULL;
- call_arg_loc_last = NULL;
- if (tail_call_site_count >= 0
- && tail_call_site_count == tail_call_site_note_count
- && !dwarf_strict)
- {
- if (call_site_count >= 0
- && call_site_count == call_site_note_count)
- add_AT_flag (subr_die, DW_AT_GNU_all_call_sites, 1);
- else
- add_AT_flag (subr_die, DW_AT_GNU_all_tail_call_sites, 1);
- }
- call_site_count = -1;
- tail_call_site_count = -1;
- }
- if (subr_die != old_die)
- /* Add the calling convention attribute if requested. */
- add_calling_convention_attribute (subr_die, decl);
- }
- /* Returns a hash value for X (which really is a die_struct). */
- hashval_t
- block_die_hasher::hash (die_struct *d)
- {
- return (hashval_t) d->decl_id ^ htab_hash_pointer (d->die_parent);
- }
- /* Return nonzero if decl_id and die_parent of die_struct X is the same
- as decl_id and die_parent of die_struct Y. */
- bool
- block_die_hasher::equal (die_struct *x, die_struct *y)
- {
- return x->decl_id == y->decl_id && x->die_parent == y->die_parent;
- }
- /* Generate a DIE to represent a declared data object.
- Either DECL or ORIGIN must be non-null. */
- static void
- gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
- {
- HOST_WIDE_INT off = 0;
- tree com_decl;
- tree decl_or_origin = decl ? decl : origin;
- tree ultimate_origin;
- dw_die_ref var_die;
- dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
- dw_die_ref origin_die;
- bool declaration = (DECL_EXTERNAL (decl_or_origin)
- || class_or_namespace_scope_p (context_die));
- bool specialization_p = false;
- ultimate_origin = decl_ultimate_origin (decl_or_origin);
- if (decl || ultimate_origin)
- origin = ultimate_origin;
- com_decl = fortran_common (decl_or_origin, &off);
- /* Symbol in common gets emitted as a child of the common block, in the form
- of a data member. */
- if (com_decl)
- {
- dw_die_ref com_die;
- dw_loc_list_ref loc;
- die_node com_die_arg;
- var_die = lookup_decl_die (decl_or_origin);
- if (var_die)
- {
- if (get_AT (var_die, DW_AT_location) == NULL)
- {
- loc = loc_list_from_tree (com_decl, off ? 1 : 2, NULL);
- if (loc)
- {
- if (off)
- {
- /* Optimize the common case. */
- if (single_element_loc_list_p (loc)
- && loc->expr->dw_loc_opc == DW_OP_addr
- && loc->expr->dw_loc_next == NULL
- && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr)
- == SYMBOL_REF)
- {
- rtx x = loc->expr->dw_loc_oprnd1.v.val_addr;
- loc->expr->dw_loc_oprnd1.v.val_addr
- = plus_constant (GET_MODE (x), x , off);
- }
- else
- loc_list_plus_const (loc, off);
- }
- add_AT_location_description (var_die, DW_AT_location, loc);
- remove_AT (var_die, DW_AT_declaration);
- }
- }
- return;
- }
- if (common_block_die_table == NULL)
- common_block_die_table = hash_table<block_die_hasher>::create_ggc (10);
- com_die_arg.decl_id = DECL_UID (com_decl);
- com_die_arg.die_parent = context_die;
- com_die = common_block_die_table->find (&com_die_arg);
- loc = loc_list_from_tree (com_decl, 2, NULL);
- if (com_die == NULL)
- {
- const char *cnam
- = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (com_decl));
- die_node **slot;
- com_die = new_die (DW_TAG_common_block, context_die, decl);
- add_name_and_src_coords_attributes (com_die, com_decl);
- if (loc)
- {
- add_AT_location_description (com_die, DW_AT_location, loc);
- /* Avoid sharing the same loc descriptor between
- DW_TAG_common_block and DW_TAG_variable. */
- loc = loc_list_from_tree (com_decl, 2, NULL);
- }
- else if (DECL_EXTERNAL (decl))
- add_AT_flag (com_die, DW_AT_declaration, 1);
- if (want_pubnames ())
- add_pubname_string (cnam, com_die); /* ??? needed? */
- com_die->decl_id = DECL_UID (com_decl);
- slot = common_block_die_table->find_slot (com_die, INSERT);
- *slot = com_die;
- }
- else if (get_AT (com_die, DW_AT_location) == NULL && loc)
- {
- add_AT_location_description (com_die, DW_AT_location, loc);
- loc = loc_list_from_tree (com_decl, 2, NULL);
- remove_AT (com_die, DW_AT_declaration);
- }
- var_die = new_die (DW_TAG_variable, com_die, decl);
- add_name_and_src_coords_attributes (var_die, decl);
- add_type_attribute (var_die, TREE_TYPE (decl), decl_quals (decl),
- context_die);
- add_AT_flag (var_die, DW_AT_external, 1);
- if (loc)
- {
- if (off)
- {
- /* Optimize the common case. */
- if (single_element_loc_list_p (loc)
- && loc->expr->dw_loc_opc == DW_OP_addr
- && loc->expr->dw_loc_next == NULL
- && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
- {
- rtx x = loc->expr->dw_loc_oprnd1.v.val_addr;
- loc->expr->dw_loc_oprnd1.v.val_addr
- = plus_constant (GET_MODE (x), x, off);
- }
- else
- loc_list_plus_const (loc, off);
- }
- add_AT_location_description (var_die, DW_AT_location, loc);
- }
- else if (DECL_EXTERNAL (decl))
- add_AT_flag (var_die, DW_AT_declaration, 1);
- equate_decl_number_to_die (decl, var_die);
- return;
- }
- /* If the compiler emitted a definition for the DECL declaration
- and if we already emitted a DIE for it, don't emit a second
- DIE for it again. Allow re-declarations of DECLs that are
- inside functions, though. */
- if (old_die && declaration && !local_scope_p (context_die))
- return;
- /* For static data members, the declaration in the class is supposed
- to have DW_TAG_member tag; the specification should still be
- DW_TAG_variable referencing the DW_TAG_member DIE. */
- if (declaration && class_scope_p (context_die))
- var_die = new_die (DW_TAG_member, context_die, decl);
- else
- var_die = new_die (DW_TAG_variable, context_die, decl);
- origin_die = NULL;
- if (origin != NULL)
- origin_die = add_abstract_origin_attribute (var_die, origin);
- /* Loop unrolling can create multiple blocks that refer to the same
- static variable, so we must test for the DW_AT_declaration flag.
- ??? Loop unrolling/reorder_blocks should perhaps be rewritten to
- copy decls and set the DECL_ABSTRACT_P flag on them instead of
- sharing them.
- ??? Duplicated blocks have been rewritten to use .debug_ranges.
- ??? The declare_in_namespace support causes us to get two DIEs for one
- variable, both of which are declarations. We want to avoid considering
- one to be a specification, so we must test that this DIE is not a
- declaration. */
- else if (old_die && TREE_STATIC (decl) && ! declaration
- && get_AT_flag (old_die, DW_AT_declaration) == 1)
- {
- /* This is a definition of a C++ class level static. */
- add_AT_specification (var_die, old_die);
- specialization_p = true;
- if (DECL_NAME (decl))
- {
- expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
- struct dwarf_file_data * file_index = lookup_filename (s.file);
- if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
- add_AT_file (var_die, DW_AT_decl_file, file_index);
- if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
- add_AT_unsigned (var_die, DW_AT_decl_line, s.line);
- if (old_die->die_tag == DW_TAG_member)
- add_linkage_name (var_die, decl);
- }
- }
- else
- add_name_and_src_coords_attributes (var_die, decl);
- if ((origin == NULL && !specialization_p)
- || (origin != NULL
- && !DECL_ABSTRACT_P (decl_or_origin)
- && variably_modified_type_p (TREE_TYPE (decl_or_origin),
- decl_function_context
- (decl_or_origin))))
- {
- tree type = TREE_TYPE (decl_or_origin);
- if (decl_by_reference_p (decl_or_origin))
- add_type_attribute (var_die, TREE_TYPE (type), TYPE_UNQUALIFIED,
- context_die);
- else
- add_type_attribute (var_die, type, decl_quals (decl_or_origin),
- context_die);
- }
- if (origin == NULL && !specialization_p)
- {
- if (TREE_PUBLIC (decl))
- add_AT_flag (var_die, DW_AT_external, 1);
- if (DECL_ARTIFICIAL (decl))
- add_AT_flag (var_die, DW_AT_artificial, 1);
- add_accessibility_attribute (var_die, decl);
- }
- if (declaration)
- add_AT_flag (var_die, DW_AT_declaration, 1);
- if (decl && (DECL_ABSTRACT_P (decl) || declaration || old_die == NULL))
- equate_decl_number_to_die (decl, var_die);
- if (! declaration
- && (! DECL_ABSTRACT_P (decl_or_origin)
- /* Local static vars are shared between all clones/inlines,
- so emit DW_AT_location on the abstract DIE if DECL_RTL is
- already set. */
- || (TREE_CODE (decl_or_origin) == VAR_DECL
- && TREE_STATIC (decl_or_origin)
- && DECL_RTL_SET_P (decl_or_origin)))
- /* When abstract origin already has DW_AT_location attribute, no need
- to add it again. */
- && (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
- {
- if (TREE_CODE (decl_or_origin) == VAR_DECL && TREE_STATIC (decl_or_origin)
- && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl_or_origin)))
- defer_location (decl_or_origin, var_die);
- else
- add_location_or_const_value_attribute (var_die, decl_or_origin,
- decl == NULL, DW_AT_location);
- add_pubname (decl_or_origin, var_die);
- }
- else
- tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
- }
- /* Generate a DIE to represent a named constant. */
- static void
- gen_const_die (tree decl, dw_die_ref context_die)
- {
- dw_die_ref const_die;
- tree type = TREE_TYPE (decl);
- const_die = new_die (DW_TAG_constant, context_die, decl);
- add_name_and_src_coords_attributes (const_die, decl);
- add_type_attribute (const_die, type, TYPE_QUAL_CONST, context_die);
- if (TREE_PUBLIC (decl))
- add_AT_flag (const_die, DW_AT_external, 1);
- if (DECL_ARTIFICIAL (decl))
- add_AT_flag (const_die, DW_AT_artificial, 1);
- tree_add_const_value_attribute_for_decl (const_die, decl);
- }
- /* Generate a DIE to represent a label identifier. */
- static void
- gen_label_die (tree decl, dw_die_ref context_die)
- {
- tree origin = decl_ultimate_origin (decl);
- dw_die_ref lbl_die = new_die (DW_TAG_label, context_die, decl);
- rtx insn;
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- if (origin != NULL)
- add_abstract_origin_attribute (lbl_die, origin);
- else
- add_name_and_src_coords_attributes (lbl_die, decl);
- if (DECL_ABSTRACT_P (decl))
- equate_decl_number_to_die (decl, lbl_die);
- else
- {
- insn = DECL_RTL_IF_SET (decl);
- /* Deleted labels are programmer specified labels which have been
- eliminated because of various optimizations. We still emit them
- here so that it is possible to put breakpoints on them. */
- if (insn
- && (LABEL_P (insn)
- || ((NOTE_P (insn)
- && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL))))
- {
- /* When optimization is enabled (via -O) some parts of the compiler
- (e.g. jump.c and cse.c) may try to delete CODE_LABEL insns which
- represent source-level labels which were explicitly declared by
- the user. This really shouldn't be happening though, so catch
- it if it ever does happen. */
- gcc_assert (!as_a<rtx_insn *> (insn)->deleted ());
- ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
- add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
- }
- else if (insn
- && NOTE_P (insn)
- && NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL
- && CODE_LABEL_NUMBER (insn) != -1)
- {
- ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn));
- add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
- }
- }
- }
- /* A helper function for gen_inlined_subroutine_die. Add source coordinate
- attributes to the DIE for a block STMT, to describe where the inlined
- function was called from. This is similar to add_src_coords_attributes. */
- static inline void
- add_call_src_coords_attributes (tree stmt, dw_die_ref die)
- {
- expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt));
- if (dwarf_version >= 3 || !dwarf_strict)
- {
- add_AT_file (die, DW_AT_call_file, lookup_filename (s.file));
- add_AT_unsigned (die, DW_AT_call_line, s.line);
- }
- }
- /* A helper function for gen_lexical_block_die and gen_inlined_subroutine_die.
- Add low_pc and high_pc attributes to the DIE for a block STMT. */
- static inline void
- add_high_low_attributes (tree stmt, dw_die_ref die)
- {
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- if (BLOCK_FRAGMENT_CHAIN (stmt)
- && (dwarf_version >= 3 || !dwarf_strict))
- {
- tree chain, superblock = NULL_TREE;
- dw_die_ref pdie;
- dw_attr_ref attr = NULL;
- if (inlined_function_outer_scope_p (stmt))
- {
- ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
- BLOCK_NUMBER (stmt));
- add_AT_lbl_id (die, DW_AT_entry_pc, label);
- }
- /* Optimize duplicate .debug_ranges lists or even tails of
- lists. If this BLOCK has same ranges as its supercontext,
- lookup DW_AT_ranges attribute in the supercontext (and
- recursively so), verify that the ranges_table contains the
- right values and use it instead of adding a new .debug_range. */
- for (chain = stmt, pdie = die;
- BLOCK_SAME_RANGE (chain);
- chain = BLOCK_SUPERCONTEXT (chain))
- {
- dw_attr_ref new_attr;
- pdie = pdie->die_parent;
- if (pdie == NULL)
- break;
- if (BLOCK_SUPERCONTEXT (chain) == NULL_TREE)
- break;
- new_attr = get_AT (pdie, DW_AT_ranges);
- if (new_attr == NULL
- || new_attr->dw_attr_val.val_class != dw_val_class_range_list)
- break;
- attr = new_attr;
- superblock = BLOCK_SUPERCONTEXT (chain);
- }
- if (attr != NULL
- && (ranges_table[attr->dw_attr_val.v.val_offset
- / 2 / DWARF2_ADDR_SIZE].num
- == BLOCK_NUMBER (superblock))
- && BLOCK_FRAGMENT_CHAIN (superblock))
- {
- unsigned long off = attr->dw_attr_val.v.val_offset
- / 2 / DWARF2_ADDR_SIZE;
- unsigned long supercnt = 0, thiscnt = 0;
- for (chain = BLOCK_FRAGMENT_CHAIN (superblock);
- chain; chain = BLOCK_FRAGMENT_CHAIN (chain))
- {
- ++supercnt;
- gcc_checking_assert (ranges_table[off + supercnt].num
- == BLOCK_NUMBER (chain));
- }
- gcc_checking_assert (ranges_table[off + supercnt + 1].num == 0);
- for (chain = BLOCK_FRAGMENT_CHAIN (stmt);
- chain; chain = BLOCK_FRAGMENT_CHAIN (chain))
- ++thiscnt;
- gcc_assert (supercnt >= thiscnt);
- add_AT_range_list (die, DW_AT_ranges,
- ((off + supercnt - thiscnt)
- * 2 * DWARF2_ADDR_SIZE),
- false);
- return;
- }
- add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt), false);
- chain = BLOCK_FRAGMENT_CHAIN (stmt);
- do
- {
- add_ranges (chain);
- chain = BLOCK_FRAGMENT_CHAIN (chain);
- }
- while (chain);
- add_ranges (NULL);
- }
- else
- {
- char label_high[MAX_ARTIFICIAL_LABEL_BYTES];
- ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
- BLOCK_NUMBER (stmt));
- ASM_GENERATE_INTERNAL_LABEL (label_high, BLOCK_END_LABEL,
- BLOCK_NUMBER (stmt));
- add_AT_low_high_pc (die, label, label_high, false);
- }
- }
- /* Generate a DIE for a lexical block. */
- static void
- gen_lexical_block_die (tree stmt, dw_die_ref context_die)
- {
- dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
- if (call_arg_locations)
- {
- if (block_map.length () <= BLOCK_NUMBER (stmt))
- block_map.safe_grow_cleared (BLOCK_NUMBER (stmt) + 1);
- block_map[BLOCK_NUMBER (stmt)] = stmt_die;
- }
- if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
- add_high_low_attributes (stmt, stmt_die);
- decls_for_scope (stmt, stmt_die);
- }
- /* Generate a DIE for an inlined subprogram. */
- static void
- gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die)
- {
- tree decl;
- /* The instance of function that is effectively being inlined shall not
- be abstract. */
- gcc_assert (! BLOCK_ABSTRACT (stmt));
- decl = block_ultimate_origin (stmt);
- /* Emit info for the abstract instance first, if we haven't yet. We
- must emit this even if the block is abstract, otherwise when we
- emit the block below (or elsewhere), we may end up trying to emit
- a die whose origin die hasn't been emitted, and crashing. */
- dwarf2out_abstract_function (decl);
- if (! BLOCK_ABSTRACT (stmt))
- {
- dw_die_ref subr_die
- = new_die (DW_TAG_inlined_subroutine, context_die, stmt);
- if (call_arg_locations)
- {
- if (block_map.length () <= BLOCK_NUMBER (stmt))
- block_map.safe_grow_cleared (BLOCK_NUMBER (stmt) + 1);
- block_map[BLOCK_NUMBER (stmt)] = subr_die;
- }
- add_abstract_origin_attribute (subr_die, decl);
- if (TREE_ASM_WRITTEN (stmt))
- add_high_low_attributes (stmt, subr_die);
- add_call_src_coords_attributes (stmt, subr_die);
- decls_for_scope (stmt, subr_die);
- }
- }
- /* Generate a DIE for a field in a record, or structure. */
- static void
- gen_field_die (tree decl, dw_die_ref context_die)
- {
- dw_die_ref decl_die;
- if (TREE_TYPE (decl) == error_mark_node)
- return;
- decl_die = new_die (DW_TAG_member, context_die, decl);
- add_name_and_src_coords_attributes (decl_die, decl);
- add_type_attribute (decl_die, member_declared_type (decl),
- decl_quals (decl), context_die);
- if (DECL_BIT_FIELD_TYPE (decl))
- {
- add_byte_size_attribute (decl_die, decl);
- add_bit_size_attribute (decl_die, decl);
- add_bit_offset_attribute (decl_die, decl);
- }
- if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE)
- add_data_member_location_attribute (decl_die, decl);
- if (DECL_ARTIFICIAL (decl))
- add_AT_flag (decl_die, DW_AT_artificial, 1);
- add_accessibility_attribute (decl_die, decl);
- /* Equate decl number to die, so that we can look up this decl later on. */
- equate_decl_number_to_die (decl, decl_die);
- }
- #if 0
- /* Don't generate either pointer_type DIEs or reference_type DIEs here.
- Use modified_type_die instead.
- We keep this code here just in case these types of DIEs may be needed to
- represent certain things in other languages (e.g. Pascal) someday. */
- static void
- gen_pointer_type_die (tree type, dw_die_ref context_die)
- {
- dw_die_ref ptr_die
- = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die), type);
- equate_type_number_to_die (type, ptr_die);
- add_type_attribute (ptr_die, TREE_TYPE (type), TYPE_UNQUALIFIED,
- context_die);
- add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
- }
- /* Don't generate either pointer_type DIEs or reference_type DIEs here.
- Use modified_type_die instead.
- We keep this code here just in case these types of DIEs may be needed to
- represent certain things in other languages (e.g. Pascal) someday. */
- static void
- gen_reference_type_die (tree type, dw_die_ref context_die)
- {
- dw_die_ref ref_die, scope_die = scope_die_for (type, context_die);
- if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4)
- ref_die = new_die (DW_TAG_rvalue_reference_type, scope_die, type);
- else
- ref_die = new_die (DW_TAG_reference_type, scope_die, type);
- equate_type_number_to_die (type, ref_die);
- add_type_attribute (ref_die, TREE_TYPE (type), TYPE_UNQUALIFIED,
- context_die);
- add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
- }
- #endif
- /* Generate a DIE for a pointer to a member type. */
- static void
- gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die)
- {
- dw_die_ref ptr_die
- = new_die (DW_TAG_ptr_to_member_type,
- scope_die_for (type, context_die), type);
- equate_type_number_to_die (type, ptr_die);
- add_AT_die_ref (ptr_die, DW_AT_containing_type,
- lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
- add_type_attribute (ptr_die, TREE_TYPE (type), TYPE_UNQUALIFIED,
- context_die);
- }
- typedef const char *dchar_p; /* For DEF_VEC_P. */
- static char *producer_string;
- /* Return a heap allocated producer string including command line options
- if -grecord-gcc-switches. */
- static char *
- gen_producer_string (void)
- {
- size_t j;
- auto_vec<dchar_p> switches;
- const char *language_string = lang_hooks.name;
- char *producer, *tail;
- const char *p;
- size_t len = dwarf_record_gcc_switches ? 0 : 3;
- size_t plen = strlen (language_string) + 1 + strlen (version_string);
- for (j = 1; dwarf_record_gcc_switches && j < save_decoded_options_count; j++)
- switch (save_decoded_options[j].opt_index)
- {
- case OPT_o:
- case OPT_d:
- case OPT_dumpbase:
- case OPT_dumpdir:
- case OPT_auxbase:
- case OPT_auxbase_strip:
- case OPT_quiet:
- case OPT_version:
- case OPT_v:
- case OPT_w:
- case OPT_L:
- case OPT_D:
- case OPT_I:
- case OPT_U:
- case OPT_SPECIAL_unknown:
- case OPT_SPECIAL_ignore:
- case OPT_SPECIAL_program_name:
- case OPT_SPECIAL_input_file:
- case OPT_grecord_gcc_switches:
- case OPT_gno_record_gcc_switches:
- case OPT__output_pch_:
- case OPT_fdiagnostics_show_location_:
- case OPT_fdiagnostics_show_option:
- case OPT_fdiagnostics_show_caret:
- case OPT_fdiagnostics_color_:
- case OPT_fverbose_asm:
- case OPT____:
- case OPT__sysroot_:
- case OPT_nostdinc:
- case OPT_nostdinc__:
- case OPT_fpreprocessed:
- case OPT_fltrans_output_list_:
- case OPT_fresolution_:
- /* Ignore these. */
- continue;
- default:
- if (cl_options[save_decoded_options[j].opt_index].flags
- & CL_NO_DWARF_RECORD)
- continue;
- gcc_checking_assert (save_decoded_options[j].canonical_option[0][0]
- == '-');
- switch (save_decoded_options[j].canonical_option[0][1])
- {
- case 'M':
- case 'i':
- case 'W':
- continue;
- case 'f':
- if (strncmp (save_decoded_options[j].canonical_option[0] + 2,
- "dump", 4) == 0)
- continue;
- break;
- default:
- break;
- }
- switches.safe_push (save_decoded_options[j].orig_option_with_args_text);
- len += strlen (save_decoded_options[j].orig_option_with_args_text) + 1;
- break;
- }
- producer = XNEWVEC (char, plen + 1 + len + 1);
- tail = producer;
- sprintf (tail, "%s %s", language_string, version_string);
- tail += plen;
- FOR_EACH_VEC_ELT (switches, j, p)
- {
- len = strlen (p);
- *tail = ' ';
- memcpy (tail + 1, p, len);
- tail += len + 1;
- }
- *tail = '\0';
- return producer;
- }
- /* Given a C and/or C++ language/version string return the "highest".
- C++ is assumed to be "higher" than C in this case. Used for merging
- LTO translation unit languages. */
- static const char *
- highest_c_language (const char *lang1, const char *lang2)
- {
- if (strcmp ("GNU C++14", lang1) == 0 || strcmp ("GNU C++14", lang2) == 0)
- return "GNU C++14";
- if (strcmp ("GNU C++11", lang1) == 0 || strcmp ("GNU C++11", lang2) == 0)
- return "GNU C++11";
- if (strcmp ("GNU C++98", lang1) == 0 || strcmp ("GNU C++98", lang2) == 0)
- return "GNU C++98";
- if (strcmp ("GNU C11", lang1) == 0 || strcmp ("GNU C11", lang2) == 0)
- return "GNU C11";
- if (strcmp ("GNU C99", lang1) == 0 || strcmp ("GNU C99", lang2) == 0)
- return "GNU C99";
- if (strcmp ("GNU C89", lang1) == 0 || strcmp ("GNU C89", lang2) == 0)
- return "GNU C89";
- gcc_unreachable ();
- }
- /* Generate the DIE for the compilation unit. */
- static dw_die_ref
- gen_compile_unit_die (const char *filename)
- {
- dw_die_ref die;
- const char *language_string = lang_hooks.name;
- int language;
- die = new_die (DW_TAG_compile_unit, NULL, NULL);
- if (filename)
- {
- add_name_attribute (die, filename);
- /* Don't add cwd for <built-in>. */
- if (!IS_ABSOLUTE_PATH (filename) && filename[0] != '<')
- add_comp_dir_attribute (die);
- }
- add_AT_string (die, DW_AT_producer, producer_string ? producer_string : "");
- /* If our producer is LTO try to figure out a common language to use
- from the global list of translation units. */
- if (strcmp (language_string, "GNU GIMPLE") == 0)
- {
- unsigned i;
- tree t;
- const char *common_lang = NULL;
- FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, t)
- {
- if (!TRANSLATION_UNIT_LANGUAGE (t))
- continue;
- if (!common_lang)
- common_lang = TRANSLATION_UNIT_LANGUAGE (t);
- else if (strcmp (common_lang, TRANSLATION_UNIT_LANGUAGE (t)) == 0)
- ;
- else if (strncmp (common_lang, "GNU C", 5) == 0
- && strncmp (TRANSLATION_UNIT_LANGUAGE (t), "GNU C", 5) == 0)
- /* Mixing C and C++ is ok, use C++ in that case. */
- common_lang = highest_c_language (common_lang,
- TRANSLATION_UNIT_LANGUAGE (t));
- else
- {
- /* Fall back to C. */
- common_lang = NULL;
- break;
- }
- }
- if (common_lang)
- language_string = common_lang;
- }
- language = DW_LANG_C;
- if (strncmp (language_string, "GNU C", 5) == 0
- && ISDIGIT (language_string[5]))
- {
- language = DW_LANG_C89;
- if (dwarf_version >= 3 || !dwarf_strict)
- {
- if (strcmp (language_string, "GNU C89") != 0)
- language = DW_LANG_C99;
- if (dwarf_version >= 5 /* || !dwarf_strict */)
- if (strcmp (language_string, "GNU C11") == 0)
- language = DW_LANG_C11;
- }
- }
- else if (strncmp (language_string, "GNU C++", 7) == 0)
- {
- language = DW_LANG_C_plus_plus;
- if (dwarf_version >= 5 /* || !dwarf_strict */)
- {
- if (strcmp (language_string, "GNU C++11") == 0)
- language = DW_LANG_C_plus_plus_11;
- else if (strcmp (language_string, "GNU C++14") == 0)
- language = DW_LANG_C_plus_plus_14;
- }
- }
- else if (strcmp (language_string, "GNU F77") == 0)
- language = DW_LANG_Fortran77;
- else if (strcmp (language_string, "GNU Pascal") == 0)
- language = DW_LANG_Pascal83;
- else if (dwarf_version >= 3 || !dwarf_strict)
- {
- if (strcmp (language_string, "GNU Ada") == 0)
- language = DW_LANG_Ada95;
- else if (strncmp (language_string, "GNU Fortran", 11) == 0)
- {
- language = DW_LANG_Fortran95;
- if (dwarf_version >= 5 /* || !dwarf_strict */)
- {
- if (strcmp (language_string, "GNU Fortran2003") == 0)
- language = DW_LANG_Fortran03;
- else if (strcmp (language_string, "GNU Fortran2008") == 0)
- language = DW_LANG_Fortran08;
- }
- }
- else if (strcmp (language_string, "GNU Java") == 0)
- language = DW_LANG_Java;
- else if (strcmp (language_string, "GNU Objective-C") == 0)
- language = DW_LANG_ObjC;
- else if (strcmp (language_string, "GNU Objective-C++") == 0)
- language = DW_LANG_ObjC_plus_plus;
- else if (dwarf_version >= 5 || !dwarf_strict)
- {
- if (strcmp (language_string, "GNU Go") == 0)
- language = DW_LANG_Go;
- }
- }
- /* Use a degraded Fortran setting in strict DWARF2 so is_fortran works. */
- else if (strncmp (language_string, "GNU Fortran", 11) == 0)
- language = DW_LANG_Fortran90;
- add_AT_unsigned (die, DW_AT_language, language);
- switch (language)
- {
- case DW_LANG_Fortran77:
- case DW_LANG_Fortran90:
- case DW_LANG_Fortran95:
- case DW_LANG_Fortran03:
- case DW_LANG_Fortran08:
- /* Fortran has case insensitive identifiers and the front-end
- lowercases everything. */
- add_AT_unsigned (die, DW_AT_identifier_case, DW_ID_down_case);
- break;
- default:
- /* The default DW_ID_case_sensitive doesn't need to be specified. */
- break;
- }
- return die;
- }
- /* Generate the DIE for a base class. */
- static void
- gen_inheritance_die (tree binfo, tree access, dw_die_ref context_die)
- {
- dw_die_ref die = new_die (DW_TAG_inheritance, context_die, binfo);
- add_type_attribute (die, BINFO_TYPE (binfo), TYPE_UNQUALIFIED, context_die);
- add_data_member_location_attribute (die, binfo);
- if (BINFO_VIRTUAL_P (binfo))
- add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
- /* In DWARF3+ the default is DW_ACCESS_private only in DW_TAG_class_type
- children, otherwise the default is DW_ACCESS_public. In DWARF2
- the default has always been DW_ACCESS_private. */
- if (access == access_public_node)
- {
- if (dwarf_version == 2
- || context_die->die_tag == DW_TAG_class_type)
- add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
- }
- else if (access == access_protected_node)
- add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
- else if (dwarf_version > 2
- && context_die->die_tag != DW_TAG_class_type)
- add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_private);
- }
- /* Generate a DIE for a class member. */
- static void
- gen_member_die (tree type, dw_die_ref context_die)
- {
- tree member;
- tree binfo = TYPE_BINFO (type);
- dw_die_ref child;
- /* If this is not an incomplete type, output descriptions of each of its
- members. Note that as we output the DIEs necessary to represent the
- members of this record or union type, we will also be trying to output
- DIEs to represent the *types* of those members. However the `type'
- function (above) will specifically avoid generating type DIEs for member
- types *within* the list of member DIEs for this (containing) type except
- for those types (of members) which are explicitly marked as also being
- members of this (containing) type themselves. The g++ front- end can
- force any given type to be treated as a member of some other (containing)
- type by setting the TYPE_CONTEXT of the given (member) type to point to
- the TREE node representing the appropriate (containing) type. */
- /* First output info about the base classes. */
- if (binfo)
- {
- vec<tree, va_gc> *accesses = BINFO_BASE_ACCESSES (binfo);
- int i;
- tree base;
- for (i = 0; BINFO_BASE_ITERATE (binfo, i, base); i++)
- gen_inheritance_die (base,
- (accesses ? (*accesses)[i] : access_public_node),
- context_die);
- }
- /* Now output info about the data members and type members. */
- for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN (member))
- {
- /* If we thought we were generating minimal debug info for TYPE
- and then changed our minds, some of the member declarations
- may have already been defined. Don't define them again, but
- do put them in the right order. */
- child = lookup_decl_die (member);
- if (child)
- splice_child_die (context_die, child);
- else
- gen_decl_die (member, NULL, context_die);
- }
- /* Now output info about the function members (if any). */
- for (member = TYPE_METHODS (type); member; member = DECL_CHAIN (member))
- {
- /* Don't include clones in the member list. */
- if (DECL_ABSTRACT_ORIGIN (member))
- continue;
- child = lookup_decl_die (member);
- if (child)
- splice_child_die (context_die, child);
- else
- gen_decl_die (member, NULL, context_die);
- }
- }
- /* Generate a DIE for a structure or union type. If TYPE_DECL_SUPPRESS_DEBUG
- is set, we pretend that the type was never defined, so we only get the
- member DIEs needed by later specification DIEs. */
- static void
- gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
- enum debug_info_usage usage)
- {
- dw_die_ref type_die = lookup_type_die (type);
- dw_die_ref scope_die = 0;
- int nested = 0;
- int complete = (TYPE_SIZE (type)
- && (! TYPE_STUB_DECL (type)
- || ! TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))));
- int ns_decl = (context_die && context_die->die_tag == DW_TAG_namespace);
- complete = complete && should_emit_struct_debug (type, usage);
- if (type_die && ! complete)
- return;
- if (TYPE_CONTEXT (type) != NULL_TREE
- && (AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
- || TREE_CODE (TYPE_CONTEXT (type)) == NAMESPACE_DECL))
- nested = 1;
- scope_die = scope_die_for (type, context_die);
- /* Generate child dies for template paramaters. */
- if (!type_die && debug_info_level > DINFO_LEVEL_TERSE)
- schedule_generic_params_dies_gen (type);
- if (! type_die || (nested && is_cu_die (scope_die)))
- /* First occurrence of type or toplevel definition of nested class. */
- {
- dw_die_ref old_die = type_die;
- type_die = new_die (TREE_CODE (type) == RECORD_TYPE
- ? record_type_tag (type) : DW_TAG_union_type,
- scope_die, type);
- equate_type_number_to_die (type, type_die);
- if (old_die)
- add_AT_specification (type_die, old_die);
- else
- add_name_attribute (type_die, type_tag (type));
- }
- else
- remove_AT (type_die, DW_AT_declaration);
- /* If this type has been completed, then give it a byte_size attribute and
- then give a list of members. */
- if (complete && !ns_decl)
- {
- /* Prevent infinite recursion in cases where the type of some member of
- this type is expressed in terms of this type itself. */
- TREE_ASM_WRITTEN (type) = 1;
- add_byte_size_attribute (type_die, type);
- if (TYPE_STUB_DECL (type) != NULL_TREE)
- {
- add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
- add_accessibility_attribute (type_die, TYPE_STUB_DECL (type));
- }
- /* If the first reference to this type was as the return type of an
- inline function, then it may not have a parent. Fix this now. */
- if (type_die->die_parent == NULL)
- add_child_die (scope_die, type_die);
- push_decl_scope (type);
- gen_member_die (type, type_die);
- pop_decl_scope ();
- add_gnat_descriptive_type_attribute (type_die, type, context_die);
- if (TYPE_ARTIFICIAL (type))
- add_AT_flag (type_die, DW_AT_artificial, 1);
- /* GNU extension: Record what type our vtable lives in. */
- if (TYPE_VFIELD (type))
- {
- tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type));
- gen_type_die (vtype, context_die);
- add_AT_die_ref (type_die, DW_AT_containing_type,
- lookup_type_die (vtype));
- }
- }
- else
- {
- add_AT_flag (type_die, DW_AT_declaration, 1);
- /* We don't need to do this for function-local types. */
- if (TYPE_STUB_DECL (type)
- && ! decl_function_context (TYPE_STUB_DECL (type)))
- vec_safe_push (incomplete_types, type);
- }
- if (get_AT (type_die, DW_AT_name))
- add_pubtype (type, type_die);
- }
- /* Generate a DIE for a subroutine _type_. */
- static void
- gen_subroutine_type_die (tree type, dw_die_ref context_die)
- {
- tree return_type = TREE_TYPE (type);
- dw_die_ref subr_die
- = new_die (DW_TAG_subroutine_type,
- scope_die_for (type, context_die), type);
- equate_type_number_to_die (type, subr_die);
- add_prototyped_attribute (subr_die, type);
- add_type_attribute (subr_die, return_type, TYPE_UNQUALIFIED, context_die);
- gen_formal_types_die (type, subr_die);
- if (get_AT (subr_die, DW_AT_name))
- add_pubtype (type, subr_die);
- }
- /* Generate a DIE for a type definition. */
- static void
- gen_typedef_die (tree decl, dw_die_ref context_die)
- {
- dw_die_ref type_die;
- tree origin;
- if (TREE_ASM_WRITTEN (decl))
- return;
- TREE_ASM_WRITTEN (decl) = 1;
- type_die = new_die (DW_TAG_typedef, context_die, decl);
- origin = decl_ultimate_origin (decl);
- if (origin != NULL)
- add_abstract_origin_attribute (type_die, origin);
- else
- {
- tree type;
- add_name_and_src_coords_attributes (type_die, decl);
- if (DECL_ORIGINAL_TYPE (decl))
- {
- type = DECL_ORIGINAL_TYPE (decl);
- gcc_assert (type != TREE_TYPE (decl));
- equate_type_number_to_die (TREE_TYPE (decl), type_die);
- }
- else
- {
- type = TREE_TYPE (decl);
- if (is_naming_typedef_decl (TYPE_NAME (type)))
- {
- /* Here, we are in the case of decl being a typedef naming
- an anonymous type, e.g:
- typedef struct {...} foo;
- In that case TREE_TYPE (decl) is not a typedef variant
- type and TYPE_NAME of the anonymous type is set to the
- TYPE_DECL of the typedef. This construct is emitted by
- the C++ FE.
- TYPE is the anonymous struct named by the typedef
- DECL. As we need the DW_AT_type attribute of the
- DW_TAG_typedef to point to the DIE of TYPE, let's
- generate that DIE right away. add_type_attribute
- called below will then pick (via lookup_type_die) that
- anonymous struct DIE. */
- if (!TREE_ASM_WRITTEN (type))
- gen_tagged_type_die (type, context_die, DINFO_USAGE_DIR_USE);
- /* This is a GNU Extension. We are adding a
- DW_AT_linkage_name attribute to the DIE of the
- anonymous struct TYPE. The value of that attribute
- is the name of the typedef decl naming the anonymous
- struct. This greatly eases the work of consumers of
- this debug info. */
- add_linkage_attr (lookup_type_die (type), decl);
- }
- }
- add_type_attribute (type_die, type, decl_quals (decl), context_die);
- if (is_naming_typedef_decl (decl))
- /* We want that all subsequent calls to lookup_type_die with
- TYPE in argument yield the DW_TAG_typedef we have just
- created. */
- equate_type_number_to_die (type, type_die);
- add_accessibility_attribute (type_die, decl);
- }
- if (DECL_ABSTRACT_P (decl))
- equate_decl_number_to_die (decl, type_die);
- if (get_AT (type_die, DW_AT_name))
- add_pubtype (decl, type_die);
- }
- /* Generate a DIE for a struct, class, enum or union type. */
- static void
- gen_tagged_type_die (tree type,
- dw_die_ref context_die,
- enum debug_info_usage usage)
- {
- int need_pop;
- if (type == NULL_TREE
- || !is_tagged_type (type))
- return;
- /* If this is a nested type whose containing class hasn't been written
- out yet, writing it out will cover this one, too. This does not apply
- to instantiations of member class templates; they need to be added to
- the containing class as they are generated. FIXME: This hurts the
- idea of combining type decls from multiple TUs, since we can't predict
- what set of template instantiations we'll get. */
- if (TYPE_CONTEXT (type)
- && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
- && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
- {
- gen_type_die_with_usage (TYPE_CONTEXT (type), context_die, usage);
- if (TREE_ASM_WRITTEN (type))
- return;
- /* If that failed, attach ourselves to the stub. */
- push_decl_scope (TYPE_CONTEXT (type));
- context_die = lookup_type_die (TYPE_CONTEXT (type));
- need_pop = 1;
- }
- else if (TYPE_CONTEXT (type) != NULL_TREE
- && (TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL))
- {
- /* If this type is local to a function that hasn't been written
- out yet, use a NULL context for now; it will be fixed up in
- decls_for_scope. */
- context_die = lookup_decl_die (TYPE_CONTEXT (type));
- /* A declaration DIE doesn't count; nested types need to go in the
- specification. */
- if (context_die && is_declaration_die (context_die))
- context_die = NULL;
- need_pop = 0;
- }
- else
- {
- context_die = declare_in_namespace (type, context_die);
- need_pop = 0;
- }
- if (TREE_CODE (type) == ENUMERAL_TYPE)
- {
- /* This might have been written out by the call to
- declare_in_namespace. */
- if (!TREE_ASM_WRITTEN (type))
- gen_enumeration_type_die (type, context_die);
- }
- else
- gen_struct_or_union_type_die (type, context_die, usage);
- if (need_pop)
- pop_decl_scope ();
- /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix
- it up if it is ever completed. gen_*_type_die will set it for us
- when appropriate. */
- }
- /* Generate a type description DIE. */
- static void
- gen_type_die_with_usage (tree type, dw_die_ref context_die,
- enum debug_info_usage usage)
- {
- struct array_descr_info info;
- if (type == NULL_TREE || type == error_mark_node)
- return;
- if (TYPE_NAME (type) != NULL_TREE
- && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
- && is_redundant_typedef (TYPE_NAME (type))
- && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
- /* The DECL of this type is a typedef we don't want to emit debug
- info for but we want debug info for its underlying typedef.
- This can happen for e.g, the injected-class-name of a C++
- type. */
- type = DECL_ORIGINAL_TYPE (TYPE_NAME (type));
- /* If TYPE is a typedef type variant, let's generate debug info
- for the parent typedef which TYPE is a type of. */
- if (typedef_variant_p (type))
- {
- if (TREE_ASM_WRITTEN (type))
- return;
- /* Prevent broken recursion; we can't hand off to the same type. */
- gcc_assert (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) != type);
- /* Give typedefs the right scope. */
- context_die = scope_die_for (type, context_die);
- TREE_ASM_WRITTEN (type) = 1;
- gen_decl_die (TYPE_NAME (type), NULL, context_die);
- return;
- }
- /* If type is an anonymous tagged type named by a typedef, let's
- generate debug info for the typedef. */
- if (is_naming_typedef_decl (TYPE_NAME (type)))
- {
- /* Use the DIE of the containing namespace as the parent DIE of
- the type description DIE we want to generate. */
- if (DECL_CONTEXT (TYPE_NAME (type))
- && TREE_CODE (DECL_CONTEXT (TYPE_NAME (type))) == NAMESPACE_DECL)
- context_die = get_context_die (DECL_CONTEXT (TYPE_NAME (type)));
-
- gen_decl_die (TYPE_NAME (type), NULL, context_die);
- return;
- }
- /* We are going to output a DIE to represent the unqualified version
- of this type (i.e. without any const or volatile qualifiers) so
- get the main variant (i.e. the unqualified version) of this type
- now. (Vectors are special because the debugging info is in the
- cloned type itself). */
- if (TREE_CODE (type) != VECTOR_TYPE)
- type = type_main_variant (type);
- /* If this is an array type with hidden descriptor, handle it first. */
- if (!TREE_ASM_WRITTEN (type)
- && lang_hooks.types.get_array_descr_info)
- {
- memset (&info, 0, sizeof (info));
- if (lang_hooks.types.get_array_descr_info (type, &info))
- {
- gen_descr_array_type_die (type, &info, context_die);
- TREE_ASM_WRITTEN (type) = 1;
- return;
- }
- }
- if (TREE_ASM_WRITTEN (type))
- return;
- switch (TREE_CODE (type))
- {
- case ERROR_MARK:
- break;
- case POINTER_TYPE:
- case REFERENCE_TYPE:
- /* We must set TREE_ASM_WRITTEN in case this is a recursive type. This
- ensures that the gen_type_die recursion will terminate even if the
- type is recursive. Recursive types are possible in Ada. */
- /* ??? We could perhaps do this for all types before the switch
- statement. */
- TREE_ASM_WRITTEN (type) = 1;
- /* For these types, all that is required is that we output a DIE (or a
- set of DIEs) to represent the "basis" type. */
- gen_type_die_with_usage (TREE_TYPE (type), context_die,
- DINFO_USAGE_IND_USE);
- break;
- case OFFSET_TYPE:
- /* This code is used for C++ pointer-to-data-member types.
- Output a description of the relevant class type. */
- gen_type_die_with_usage (TYPE_OFFSET_BASETYPE (type), context_die,
- DINFO_USAGE_IND_USE);
- /* Output a description of the type of the object pointed to. */
- gen_type_die_with_usage (TREE_TYPE (type), context_die,
- DINFO_USAGE_IND_USE);
- /* Now output a DIE to represent this pointer-to-data-member type
- itself. */
- gen_ptr_to_mbr_type_die (type, context_die);
- break;
- case FUNCTION_TYPE:
- /* Force out return type (in case it wasn't forced out already). */
- gen_type_die_with_usage (TREE_TYPE (type), context_die,
- DINFO_USAGE_DIR_USE);
- gen_subroutine_type_die (type, context_die);
- break;
- case METHOD_TYPE:
- /* Force out return type (in case it wasn't forced out already). */
- gen_type_die_with_usage (TREE_TYPE (type), context_die,
- DINFO_USAGE_DIR_USE);
- gen_subroutine_type_die (type, context_die);
- break;
- case ARRAY_TYPE:
- gen_array_type_die (type, context_die);
- break;
- case VECTOR_TYPE:
- gen_array_type_die (type, context_die);
- break;
- case ENUMERAL_TYPE:
- case RECORD_TYPE:
- case UNION_TYPE:
- case QUAL_UNION_TYPE:
- gen_tagged_type_die (type, context_die, usage);
- return;
- case VOID_TYPE:
- case INTEGER_TYPE:
- case REAL_TYPE:
- case FIXED_POINT_TYPE:
- case COMPLEX_TYPE:
- case BOOLEAN_TYPE:
- case POINTER_BOUNDS_TYPE:
- /* No DIEs needed for fundamental types. */
- break;
- case NULLPTR_TYPE:
- case LANG_TYPE:
- /* Just use DW_TAG_unspecified_type. */
- {
- dw_die_ref type_die = lookup_type_die (type);
- if (type_die == NULL)
- {
- tree name = TYPE_IDENTIFIER (type);
- type_die = new_die (DW_TAG_unspecified_type, comp_unit_die (),
- type);
- add_name_attribute (type_die, IDENTIFIER_POINTER (name));
- equate_type_number_to_die (type, type_die);
- }
- }
- break;
- default:
- if (is_cxx_auto (type))
- {
- tree name = TYPE_IDENTIFIER (type);
- dw_die_ref *die = (name == get_identifier ("auto")
- ? &auto_die : &decltype_auto_die);
- if (!*die)
- {
- *die = new_die (DW_TAG_unspecified_type,
- comp_unit_die (), NULL_TREE);
- add_name_attribute (*die, IDENTIFIER_POINTER (name));
- }
- equate_type_number_to_die (type, *die);
- break;
- }
- gcc_unreachable ();
- }
- TREE_ASM_WRITTEN (type) = 1;
- }
- static void
- gen_type_die (tree type, dw_die_ref context_die)
- {
- gen_type_die_with_usage (type, context_die, DINFO_USAGE_DIR_USE);
- }
- /* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the
- things which are local to the given block. */
- static void
- gen_block_die (tree stmt, dw_die_ref context_die)
- {
- int must_output_die = 0;
- bool inlined_func;
- /* Ignore blocks that are NULL. */
- if (stmt == NULL_TREE)
- return;
- inlined_func = inlined_function_outer_scope_p (stmt);
- /* If the block is one fragment of a non-contiguous block, do not
- process the variables, since they will have been done by the
- origin block. Do process subblocks. */
- if (BLOCK_FRAGMENT_ORIGIN (stmt))
- {
- tree sub;
- for (sub = BLOCK_SUBBLOCKS (stmt); sub; sub = BLOCK_CHAIN (sub))
- gen_block_die (sub, context_die);
- return;
- }
- /* Determine if we need to output any Dwarf DIEs at all to represent this
- block. */
- if (inlined_func)
- /* The outer scopes for inlinings *must* always be represented. We
- generate DW_TAG_inlined_subroutine DIEs for them. (See below.) */
- must_output_die = 1;
- else
- {
- /* Determine if this block directly contains any "significant"
- local declarations which we will need to output DIEs for. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
- /* We are not in terse mode so *any* local declaration counts
- as being a "significant" one. */
- must_output_die = ((BLOCK_VARS (stmt) != NULL
- || BLOCK_NUM_NONLOCALIZED_VARS (stmt))
- && (TREE_USED (stmt)
- || TREE_ASM_WRITTEN (stmt)
- || BLOCK_ABSTRACT (stmt)));
- else if ((TREE_USED (stmt)
- || TREE_ASM_WRITTEN (stmt)
- || BLOCK_ABSTRACT (stmt))
- && !dwarf2out_ignore_block (stmt))
- must_output_die = 1;
- }
- /* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block
- DIE for any block which contains no significant local declarations at
- all. Rather, in such cases we just call `decls_for_scope' so that any
- needed Dwarf info for any sub-blocks will get properly generated. Note
- that in terse mode, our definition of what constitutes a "significant"
- local declaration gets restricted to include only inlined function
- instances and local (nested) function definitions. */
- if (must_output_die)
- {
- if (inlined_func)
- {
- /* If STMT block is abstract, that means we have been called
- indirectly from dwarf2out_abstract_function.
- That function rightfully marks the descendent blocks (of
- the abstract function it is dealing with) as being abstract,
- precisely to prevent us from emitting any
- DW_TAG_inlined_subroutine DIE as a descendent
- of an abstract function instance. So in that case, we should
- not call gen_inlined_subroutine_die.
- Later though, when cgraph asks dwarf2out to emit info
- for the concrete instance of the function decl into which
- the concrete instance of STMT got inlined, the later will lead
- to the generation of a DW_TAG_inlined_subroutine DIE. */
- if (! BLOCK_ABSTRACT (stmt))
- gen_inlined_subroutine_die (stmt, context_die);
- }
- else
- gen_lexical_block_die (stmt, context_die);
- }
- else
- decls_for_scope (stmt, context_die);
- }
- /* Process variable DECL (or variable with origin ORIGIN) within
- block STMT and add it to CONTEXT_DIE. */
- static void
- process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
- {
- dw_die_ref die;
- tree decl_or_origin = decl ? decl : origin;
- if (TREE_CODE (decl_or_origin) == FUNCTION_DECL)
- die = lookup_decl_die (decl_or_origin);
- else if (TREE_CODE (decl_or_origin) == TYPE_DECL
- && TYPE_DECL_IS_STUB (decl_or_origin))
- die = lookup_type_die (TREE_TYPE (decl_or_origin));
- else
- die = NULL;
- if (die != NULL && die->die_parent == NULL)
- add_child_die (context_die, die);
- else if (TREE_CODE (decl_or_origin) == IMPORTED_DECL)
- dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
- stmt, context_die);
- else
- gen_decl_die (decl, origin, context_die);
- }
- /* Generate all of the decls declared within a given scope and (recursively)
- all of its sub-blocks. */
- static void
- decls_for_scope (tree stmt, dw_die_ref context_die)
- {
- tree decl;
- unsigned int i;
- tree subblocks;
- /* Ignore NULL blocks. */
- if (stmt == NULL_TREE)
- return;
- /* Output the DIEs to represent all of the data objects and typedefs
- declared directly within this block but not within any nested
- sub-blocks. Also, nested function and tag DIEs have been
- generated with a parent of NULL; fix that up now. We don't
- have to do this if we're at -g1. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
- {
- for (decl = BLOCK_VARS (stmt); decl != NULL; decl = DECL_CHAIN (decl))
- process_scope_var (stmt, decl, NULL_TREE, context_die);
- for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
- process_scope_var (stmt, NULL, BLOCK_NONLOCALIZED_VAR (stmt, i),
- context_die);
- }
- /* Even if we're at -g1, we need to process the subblocks in order to get
- inlined call information. */
- /* Output the DIEs to represent all sub-blocks (and the items declared
- therein) of this block. */
- for (subblocks = BLOCK_SUBBLOCKS (stmt);
- subblocks != NULL;
- subblocks = BLOCK_CHAIN (subblocks))
- gen_block_die (subblocks, context_die);
- }
- /* Is this a typedef we can avoid emitting? */
- static inline int
- is_redundant_typedef (const_tree decl)
- {
- if (TYPE_DECL_IS_STUB (decl))
- return 1;
- if (DECL_ARTIFICIAL (decl)
- && DECL_CONTEXT (decl)
- && is_tagged_type (DECL_CONTEXT (decl))
- && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
- && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
- /* Also ignore the artificial member typedef for the class name. */
- return 1;
- return 0;
- }
- /* Return TRUE if TYPE is a typedef that names a type for linkage
- purposes. This kind of typedefs is produced by the C++ FE for
- constructs like:
- typedef struct {...} foo;
- In that case, there is no typedef variant type produced for foo.
- Rather, the TREE_TYPE of the TYPE_DECL of foo is the anonymous
- struct type. */
- static bool
- is_naming_typedef_decl (const_tree decl)
- {
- if (decl == NULL_TREE
- || TREE_CODE (decl) != TYPE_DECL
- || !is_tagged_type (TREE_TYPE (decl))
- || DECL_IS_BUILTIN (decl)
- || is_redundant_typedef (decl)
- /* It looks like Ada produces TYPE_DECLs that are very similar
- to C++ naming typedefs but that have different
- semantics. Let's be specific to c++ for now. */
- || !is_cxx ())
- return FALSE;
- return (DECL_ORIGINAL_TYPE (decl) == NULL_TREE
- && TYPE_NAME (TREE_TYPE (decl)) == decl
- && (TYPE_STUB_DECL (TREE_TYPE (decl))
- != TYPE_NAME (TREE_TYPE (decl))));
- }
- /* Looks up the DIE for a context. */
- static inline dw_die_ref
- lookup_context_die (tree context)
- {
- if (context)
- {
- /* Find die that represents this context. */
- if (TYPE_P (context))
- {
- context = TYPE_MAIN_VARIANT (context);
- dw_die_ref ctx = lookup_type_die (context);
- if (!ctx)
- return NULL;
- return strip_naming_typedef (context, ctx);
- }
- else
- return lookup_decl_die (context);
- }
- return comp_unit_die ();
- }
- /* Returns the DIE for a context. */
- static inline dw_die_ref
- get_context_die (tree context)
- {
- if (context)
- {
- /* Find die that represents this context. */
- if (TYPE_P (context))
- {
- context = TYPE_MAIN_VARIANT (context);
- return strip_naming_typedef (context, force_type_die (context));
- }
- else
- return force_decl_die (context);
- }
- return comp_unit_die ();
- }
- /* Returns the DIE for decl. A DIE will always be returned. */
- static dw_die_ref
- force_decl_die (tree decl)
- {
- dw_die_ref decl_die;
- unsigned saved_external_flag;
- tree save_fn = NULL_TREE;
- decl_die = lookup_decl_die (decl);
- if (!decl_die)
- {
- dw_die_ref context_die = get_context_die (DECL_CONTEXT (decl));
- decl_die = lookup_decl_die (decl);
- if (decl_die)
- return decl_die;
- switch (TREE_CODE (decl))
- {
- case FUNCTION_DECL:
- /* Clear current_function_decl, so that gen_subprogram_die thinks
- that this is a declaration. At this point, we just want to force
- declaration die. */
- save_fn = current_function_decl;
- current_function_decl = NULL_TREE;
- gen_subprogram_die (decl, context_die);
- current_function_decl = save_fn;
- break;
- case VAR_DECL:
- /* Set external flag to force declaration die. Restore it after
- gen_decl_die() call. */
- saved_external_flag = DECL_EXTERNAL (decl);
- DECL_EXTERNAL (decl) = 1;
- gen_decl_die (decl, NULL, context_die);
- DECL_EXTERNAL (decl) = saved_external_flag;
- break;
- case NAMESPACE_DECL:
- if (dwarf_version >= 3 || !dwarf_strict)
- dwarf2out_decl (decl);
- else
- /* DWARF2 has neither DW_TAG_module, nor DW_TAG_namespace. */
- decl_die = comp_unit_die ();
- break;
- case TRANSLATION_UNIT_DECL:
- decl_die = comp_unit_die ();
- break;
- default:
- gcc_unreachable ();
- }
- /* We should be able to find the DIE now. */
- if (!decl_die)
- decl_die = lookup_decl_die (decl);
- gcc_assert (decl_die);
- }
- return decl_die;
- }
- /* Returns the DIE for TYPE, that must not be a base type. A DIE is
- always returned. */
- static dw_die_ref
- force_type_die (tree type)
- {
- dw_die_ref type_die;
- type_die = lookup_type_die (type);
- if (!type_die)
- {
- dw_die_ref context_die = get_context_die (TYPE_CONTEXT (type));
- type_die = modified_type_die (type, TYPE_QUALS_NO_ADDR_SPACE (type),
- context_die);
- gcc_assert (type_die);
- }
- return type_die;
- }
- /* Force out any required namespaces to be able to output DECL,
- and return the new context_die for it, if it's changed. */
- static dw_die_ref
- setup_namespace_context (tree thing, dw_die_ref context_die)
- {
- tree context = (DECL_P (thing)
- ? DECL_CONTEXT (thing) : TYPE_CONTEXT (thing));
- if (context && TREE_CODE (context) == NAMESPACE_DECL)
- /* Force out the namespace. */
- context_die = force_decl_die (context);
- return context_die;
- }
- /* Emit a declaration DIE for THING (which is either a DECL or a tagged
- type) within its namespace, if appropriate.
- For compatibility with older debuggers, namespace DIEs only contain
- declarations; all definitions are emitted at CU scope. */
- static dw_die_ref
- declare_in_namespace (tree thing, dw_die_ref context_die)
- {
- dw_die_ref ns_context;
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- return context_die;
- /* External declarations in the local scope only need to be emitted
- once, not once in the namespace and once in the scope.
- This avoids declaring the `extern' below in the
- namespace DIE as well as in the innermost scope:
- namespace S
- {
- int i=5;
- int foo()
- {
- int i=8;
- extern int i;
- return i;
- }
- }
- */
- if (DECL_P (thing) && DECL_EXTERNAL (thing) && local_scope_p (context_die))
- return context_die;
- /* If this decl is from an inlined function, then don't try to emit it in its
- namespace, as we will get confused. It would have already been emitted
- when the abstract instance of the inline function was emitted anyways. */
- if (DECL_P (thing) && DECL_ABSTRACT_ORIGIN (thing))
- return context_die;
- ns_context = setup_namespace_context (thing, context_die);
- if (ns_context != context_die)
- {
- if (is_fortran ())
- return ns_context;
- if (DECL_P (thing))
- gen_decl_die (thing, NULL, ns_context);
- else
- gen_type_die (thing, ns_context);
- }
- return context_die;
- }
- /* Generate a DIE for a namespace or namespace alias. */
- static void
- gen_namespace_die (tree decl, dw_die_ref context_die)
- {
- dw_die_ref namespace_die;
- /* Namespace aliases have a DECL_ABSTRACT_ORIGIN of the namespace
- they are an alias of. */
- if (DECL_ABSTRACT_ORIGIN (decl) == NULL)
- {
- /* Output a real namespace or module. */
- context_die = setup_namespace_context (decl, comp_unit_die ());
- namespace_die = new_die (is_fortran ()
- ? DW_TAG_module : DW_TAG_namespace,
- context_die, decl);
- /* For Fortran modules defined in different CU don't add src coords. */
- if (namespace_die->die_tag == DW_TAG_module && DECL_EXTERNAL (decl))
- {
- const char *name = dwarf2_name (decl, 0);
- if (name)
- add_name_attribute (namespace_die, name);
- }
- else
- add_name_and_src_coords_attributes (namespace_die, decl);
- if (DECL_EXTERNAL (decl))
- add_AT_flag (namespace_die, DW_AT_declaration, 1);
- equate_decl_number_to_die (decl, namespace_die);
- }
- else
- {
- /* Output a namespace alias. */
- /* Force out the namespace we are an alias of, if necessary. */
- dw_die_ref origin_die
- = force_decl_die (DECL_ABSTRACT_ORIGIN (decl));
- if (DECL_FILE_SCOPE_P (decl)
- || TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL)
- context_die = setup_namespace_context (decl, comp_unit_die ());
- /* Now create the namespace alias DIE. */
- namespace_die = new_die (DW_TAG_imported_declaration, context_die, decl);
- add_name_and_src_coords_attributes (namespace_die, decl);
- add_AT_die_ref (namespace_die, DW_AT_import, origin_die);
- equate_decl_number_to_die (decl, namespace_die);
- }
- /* Bypass dwarf2_name's check for DECL_NAMELESS. */
- if (want_pubnames ())
- add_pubname_string (lang_hooks.dwarf_name (decl, 1), namespace_die);
- }
- /* Generate Dwarf debug information for a decl described by DECL.
- The return value is currently only meaningful for PARM_DECLs,
- for all other decls it returns NULL. */
- static dw_die_ref
- gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
- {
- tree decl_or_origin = decl ? decl : origin;
- tree class_origin = NULL, ultimate_origin;
- if (DECL_P (decl_or_origin) && DECL_IGNORED_P (decl_or_origin))
- return NULL;
- /* Ignore pointer bounds decls. */
- if (DECL_P (decl_or_origin)
- && TREE_TYPE (decl_or_origin)
- && POINTER_BOUNDS_P (decl_or_origin))
- return NULL;
- switch (TREE_CODE (decl_or_origin))
- {
- case ERROR_MARK:
- break;
- case CONST_DECL:
- if (!is_fortran () && !is_ada ())
- {
- /* The individual enumerators of an enum type get output when we output
- the Dwarf representation of the relevant enum type itself. */
- break;
- }
- /* Emit its type. */
- gen_type_die (TREE_TYPE (decl), context_die);
- /* And its containing namespace. */
- context_die = declare_in_namespace (decl, context_die);
- gen_const_die (decl, context_die);
- break;
- case FUNCTION_DECL:
- /* Don't output any DIEs to represent mere function declarations,
- unless they are class members or explicit block externs. */
- if (DECL_INITIAL (decl_or_origin) == NULL_TREE
- && DECL_FILE_SCOPE_P (decl_or_origin)
- && (current_function_decl == NULL_TREE
- || DECL_ARTIFICIAL (decl_or_origin)))
- break;
- #if 0
- /* FIXME */
- /* This doesn't work because the C frontend sets DECL_ABSTRACT_ORIGIN
- on local redeclarations of global functions. That seems broken. */
- if (current_function_decl != decl)
- /* This is only a declaration. */;
- #endif
- /* If we're emitting a clone, emit info for the abstract instance. */
- if (origin || DECL_ORIGIN (decl) != decl)
- dwarf2out_abstract_function (origin
- ? DECL_ORIGIN (origin)
- : DECL_ABSTRACT_ORIGIN (decl));
- /* If we're emitting an out-of-line copy of an inline function,
- emit info for the abstract instance and set up to refer to it. */
- else if (cgraph_function_possibly_inlined_p (decl)
- && ! DECL_ABSTRACT_P (decl)
- && ! class_or_namespace_scope_p (context_die)
- /* dwarf2out_abstract_function won't emit a die if this is just
- a declaration. We must avoid setting DECL_ABSTRACT_ORIGIN in
- that case, because that works only if we have a die. */
- && DECL_INITIAL (decl) != NULL_TREE)
- {
- dwarf2out_abstract_function (decl);
- set_decl_origin_self (decl);
- }
- /* Otherwise we're emitting the primary DIE for this decl. */
- else if (debug_info_level > DINFO_LEVEL_TERSE)
- {
- /* Before we describe the FUNCTION_DECL itself, make sure that we
- have its containing type. */
- if (!origin)
- origin = decl_class_context (decl);
- if (origin != NULL_TREE)
- gen_type_die (origin, context_die);
- /* And its return type. */
- gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die);
- /* And its virtual context. */
- if (DECL_VINDEX (decl) != NULL_TREE)
- gen_type_die (DECL_CONTEXT (decl), context_die);
- /* Make sure we have a member DIE for decl. */
- if (origin != NULL_TREE)
- gen_type_die_for_member (origin, decl, context_die);
- /* And its containing namespace. */
- context_die = declare_in_namespace (decl, context_die);
- }
- /* Now output a DIE to represent the function itself. */
- if (decl)
- gen_subprogram_die (decl, context_die);
- break;
- case TYPE_DECL:
- /* If we are in terse mode, don't generate any DIEs to represent any
- actual typedefs. */
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- break;
- /* In the special case of a TYPE_DECL node representing the declaration
- of some type tag, if the given TYPE_DECL is marked as having been
- instantiated from some other (original) TYPE_DECL node (e.g. one which
- was generated within the original definition of an inline function) we
- used to generate a special (abbreviated) DW_TAG_structure_type,
- DW_TAG_union_type, or DW_TAG_enumeration_type DIE here. But nothing
- should be actually referencing those DIEs, as variable DIEs with that
- type would be emitted already in the abstract origin, so it was always
- removed during unused type prunning. Don't add anything in this
- case. */
- if (TYPE_DECL_IS_STUB (decl) && decl_ultimate_origin (decl) != NULL_TREE)
- break;
- if (is_redundant_typedef (decl))
- gen_type_die (TREE_TYPE (decl), context_die);
- else
- /* Output a DIE to represent the typedef itself. */
- gen_typedef_die (decl, context_die);
- break;
- case LABEL_DECL:
- if (debug_info_level >= DINFO_LEVEL_NORMAL)
- gen_label_die (decl, context_die);
- break;
- case VAR_DECL:
- case RESULT_DECL:
- /* If we are in terse mode, don't generate any DIEs to represent any
- variable declarations or definitions. */
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- break;
- /* Output any DIEs that are needed to specify the type of this data
- object. */
- if (decl_by_reference_p (decl_or_origin))
- gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
- else
- gen_type_die (TREE_TYPE (decl_or_origin), context_die);
- /* And its containing type. */
- class_origin = decl_class_context (decl_or_origin);
- if (class_origin != NULL_TREE)
- gen_type_die_for_member (class_origin, decl_or_origin, context_die);
- /* And its containing namespace. */
- context_die = declare_in_namespace (decl_or_origin, context_die);
- /* Now output the DIE to represent the data object itself. This gets
- complicated because of the possibility that the VAR_DECL really
- represents an inlined instance of a formal parameter for an inline
- function. */
- ultimate_origin = decl_ultimate_origin (decl_or_origin);
- if (ultimate_origin != NULL_TREE
- && TREE_CODE (ultimate_origin) == PARM_DECL)
- gen_formal_parameter_die (decl, origin,
- true /* Emit name attribute. */,
- context_die);
- else
- gen_variable_die (decl, origin, context_die);
- break;
- case FIELD_DECL:
- /* Ignore the nameless fields that are used to skip bits but handle C++
- anonymous unions and structs. */
- if (DECL_NAME (decl) != NULL_TREE
- || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
- || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
- {
- gen_type_die (member_declared_type (decl), context_die);
- gen_field_die (decl, context_die);
- }
- break;
- case PARM_DECL:
- if (DECL_BY_REFERENCE (decl_or_origin))
- gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
- else
- gen_type_die (TREE_TYPE (decl_or_origin), context_die);
- return gen_formal_parameter_die (decl, origin,
- true /* Emit name attribute. */,
- context_die);
- case NAMESPACE_DECL:
- case IMPORTED_DECL:
- if (dwarf_version >= 3 || !dwarf_strict)
- gen_namespace_die (decl, context_die);
- break;
- case NAMELIST_DECL:
- gen_namelist_decl (DECL_NAME (decl), context_die,
- NAMELIST_DECL_ASSOCIATED_DECL (decl));
- break;
- default:
- /* Probably some frontend-internal decl. Assume we don't care. */
- gcc_assert ((int)TREE_CODE (decl) > NUM_TREE_CODES);
- break;
- }
- return NULL;
- }
- /* Output debug information for global decl DECL. Called from toplev.c after
- compilation proper has finished. */
- static void
- dwarf2out_global_decl (tree decl)
- {
- /* Output DWARF2 information for file-scope tentative data object
- declarations, file-scope (extern) function declarations (which
- had no corresponding body) and file-scope tagged type declarations
- and definitions which have not yet been forced out. */
- if ((TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
- && !POINTER_BOUNDS_P (decl))
- dwarf2out_decl (decl);
- }
- /* Output debug information for type decl DECL. Called from toplev.c
- and from language front ends (to record built-in types). */
- static void
- dwarf2out_type_decl (tree decl, int local)
- {
- if (!local)
- dwarf2out_decl (decl);
- }
- /* Output debug information for imported module or decl DECL.
- NAME is non-NULL name in the lexical block if the decl has been renamed.
- LEXICAL_BLOCK is the lexical block (which TREE_CODE is a BLOCK)
- that DECL belongs to.
- LEXICAL_BLOCK_DIE is the DIE of LEXICAL_BLOCK. */
- static void
- dwarf2out_imported_module_or_decl_1 (tree decl,
- tree name,
- tree lexical_block,
- dw_die_ref lexical_block_die)
- {
- expanded_location xloc;
- dw_die_ref imported_die = NULL;
- dw_die_ref at_import_die;
- if (TREE_CODE (decl) == IMPORTED_DECL)
- {
- xloc = expand_location (DECL_SOURCE_LOCATION (decl));
- decl = IMPORTED_DECL_ASSOCIATED_DECL (decl);
- gcc_assert (decl);
- }
- else
- xloc = expand_location (input_location);
- if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
- {
- at_import_die = force_type_die (TREE_TYPE (decl));
- /* For namespace N { typedef void T; } using N::T; base_type_die
- returns NULL, but DW_TAG_imported_declaration requires
- the DW_AT_import tag. Force creation of DW_TAG_typedef. */
- if (!at_import_die)
- {
- gcc_assert (TREE_CODE (decl) == TYPE_DECL);
- gen_typedef_die (decl, get_context_die (DECL_CONTEXT (decl)));
- at_import_die = lookup_type_die (TREE_TYPE (decl));
- gcc_assert (at_import_die);
- }
- }
- else
- {
- at_import_die = lookup_decl_die (decl);
- if (!at_import_die)
- {
- /* If we're trying to avoid duplicate debug info, we may not have
- emitted the member decl for this field. Emit it now. */
- if (TREE_CODE (decl) == FIELD_DECL)
- {
- tree type = DECL_CONTEXT (decl);
- if (TYPE_CONTEXT (type)
- && TYPE_P (TYPE_CONTEXT (type))
- && !should_emit_struct_debug (TYPE_CONTEXT (type),
- DINFO_USAGE_DIR_USE))
- return;
- gen_type_die_for_member (type, decl,
- get_context_die (TYPE_CONTEXT (type)));
- }
- if (TREE_CODE (decl) == NAMELIST_DECL)
- at_import_die = gen_namelist_decl (DECL_NAME (decl),
- get_context_die (DECL_CONTEXT (decl)),
- NULL_TREE);
- else
- at_import_die = force_decl_die (decl);
- }
- }
- if (TREE_CODE (decl) == NAMESPACE_DECL)
- {
- if (dwarf_version >= 3 || !dwarf_strict)
- imported_die = new_die (DW_TAG_imported_module,
- lexical_block_die,
- lexical_block);
- else
- return;
- }
- else
- imported_die = new_die (DW_TAG_imported_declaration,
- lexical_block_die,
- lexical_block);
- add_AT_file (imported_die, DW_AT_decl_file, lookup_filename (xloc.file));
- add_AT_unsigned (imported_die, DW_AT_decl_line, xloc.line);
- if (name)
- add_AT_string (imported_die, DW_AT_name,
- IDENTIFIER_POINTER (name));
- add_AT_die_ref (imported_die, DW_AT_import, at_import_die);
- }
- /* Output debug information for imported module or decl DECL.
- NAME is non-NULL name in context if the decl has been renamed.
- CHILD is true if decl is one of the renamed decls as part of
- importing whole module. */
- static void
- dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
- bool child)
- {
- /* dw_die_ref at_import_die; */
- dw_die_ref scope_die;
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- return;
- gcc_assert (decl);
- /* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs.
- We need decl DIE for reference and scope die. First, get DIE for the decl
- itself. */
- /* Get the scope die for decl context. Use comp_unit_die for global module
- or decl. If die is not found for non globals, force new die. */
- if (context
- && TYPE_P (context)
- && !should_emit_struct_debug (context, DINFO_USAGE_DIR_USE))
- return;
- if (!(dwarf_version >= 3 || !dwarf_strict))
- return;
- scope_die = get_context_die (context);
- if (child)
- {
- gcc_assert (scope_die->die_child);
- gcc_assert (scope_die->die_child->die_tag == DW_TAG_imported_module);
- gcc_assert (TREE_CODE (decl) != NAMESPACE_DECL);
- scope_die = scope_die->die_child;
- }
- /* OK, now we have DIEs for decl as well as scope. Emit imported die. */
- dwarf2out_imported_module_or_decl_1 (decl, name, context, scope_die);
- }
- /* Output debug information for namelists. */
- static dw_die_ref
- gen_namelist_decl (tree name, dw_die_ref scope_die, tree item_decls)
- {
- dw_die_ref nml_die, nml_item_die, nml_item_ref_die;
- tree value;
- unsigned i;
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- return NULL;
- gcc_assert (scope_die != NULL);
- nml_die = new_die (DW_TAG_namelist, scope_die, NULL);
- add_AT_string (nml_die, DW_AT_name, IDENTIFIER_POINTER (name));
- /* If there are no item_decls, we have a nondefining namelist, e.g.
- with USE association; hence, set DW_AT_declaration. */
- if (item_decls == NULL_TREE)
- {
- add_AT_flag (nml_die, DW_AT_declaration, 1);
- return nml_die;
- }
- FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (item_decls), i, value)
- {
- nml_item_ref_die = lookup_decl_die (value);
- if (!nml_item_ref_die)
- nml_item_ref_die = force_decl_die (value);
- nml_item_die = new_die (DW_TAG_namelist_item, nml_die, NULL);
- add_AT_die_ref (nml_item_die, DW_AT_namelist_items, nml_item_ref_die);
- }
- return nml_die;
- }
- /* Write the debugging output for DECL. */
- static void
- dwarf2out_decl (tree decl)
- {
- dw_die_ref context_die = comp_unit_die ();
- switch (TREE_CODE (decl))
- {
- case ERROR_MARK:
- return;
- case FUNCTION_DECL:
- /* What we would really like to do here is to filter out all mere
- file-scope declarations of file-scope functions which are never
- referenced later within this translation unit (and keep all of ones
- that *are* referenced later on) but we aren't clairvoyant, so we have
- no idea which functions will be referenced in the future (i.e. later
- on within the current translation unit). So here we just ignore all
- file-scope function declarations which are not also definitions. If
- and when the debugger needs to know something about these functions,
- it will have to hunt around and find the DWARF information associated
- with the definition of the function.
- We can't just check DECL_EXTERNAL to find out which FUNCTION_DECL
- nodes represent definitions and which ones represent mere
- declarations. We have to check DECL_INITIAL instead. That's because
- the C front-end supports some weird semantics for "extern inline"
- function definitions. These can get inlined within the current
- translation unit (and thus, we need to generate Dwarf info for their
- abstract instances so that the Dwarf info for the concrete inlined
- instances can have something to refer to) but the compiler never
- generates any out-of-lines instances of such things (despite the fact
- that they *are* definitions).
- The important point is that the C front-end marks these "extern
- inline" functions as DECL_EXTERNAL, but we need to generate DWARF for
- them anyway. Note that the C++ front-end also plays some similar games
- for inline function definitions appearing within include files which
- also contain `#pragma interface' pragmas.
- If we are called from dwarf2out_abstract_function output a DIE
- anyway. We can end up here this way with early inlining and LTO
- where the inlined function is output in a different LTRANS unit
- or not at all. */
- if (DECL_INITIAL (decl) == NULL_TREE
- && ! DECL_ABSTRACT_P (decl))
- return;
- /* If we're a nested function, initially use a parent of NULL; if we're
- a plain function, this will be fixed up in decls_for_scope. If
- we're a method, it will be ignored, since we already have a DIE. */
- if (decl_function_context (decl)
- /* But if we're in terse mode, we don't care about scope. */
- && debug_info_level > DINFO_LEVEL_TERSE)
- context_die = NULL;
- break;
- case VAR_DECL:
- /* Ignore this VAR_DECL if it refers to a file-scope extern data object
- declaration and if the declaration was never even referenced from
- within this entire compilation unit. We suppress these DIEs in
- order to save space in the .debug section (by eliminating entries
- which are probably useless). Note that we must not suppress
- block-local extern declarations (whether used or not) because that
- would screw-up the debugger's name lookup mechanism and cause it to
- miss things which really ought to be in scope at a given point. */
- if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
- return;
- /* For local statics lookup proper context die. */
- if (TREE_STATIC (decl)
- && DECL_CONTEXT (decl)
- && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
- context_die = lookup_decl_die (DECL_CONTEXT (decl));
- /* If we are in terse mode, don't generate any DIEs to represent any
- variable declarations or definitions. */
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- return;
- break;
- case CONST_DECL:
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- return;
- if (!is_fortran () && !is_ada ())
- return;
- if (TREE_STATIC (decl) && decl_function_context (decl))
- context_die = lookup_decl_die (DECL_CONTEXT (decl));
- break;
- case NAMESPACE_DECL:
- case IMPORTED_DECL:
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- return;
- if (lookup_decl_die (decl) != NULL)
- return;
- break;
- case TYPE_DECL:
- /* Don't emit stubs for types unless they are needed by other DIEs. */
- if (TYPE_DECL_SUPPRESS_DEBUG (decl))
- return;
- /* Don't bother trying to generate any DIEs to represent any of the
- normal built-in types for the language we are compiling. */
- if (DECL_IS_BUILTIN (decl))
- return;
- /* If we are in terse mode, don't generate any DIEs for types. */
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- return;
- /* If we're a function-scope tag, initially use a parent of NULL;
- this will be fixed up in decls_for_scope. */
- if (decl_function_context (decl))
- context_die = NULL;
- break;
- case NAMELIST_DECL:
- break;
- default:
- return;
- }
- gen_decl_die (decl, NULL, context_die);
- }
- /* Write the debugging output for DECL. */
- static void
- dwarf2out_function_decl (tree decl)
- {
- dwarf2out_decl (decl);
- call_arg_locations = NULL;
- call_arg_loc_last = NULL;
- call_site_count = -1;
- tail_call_site_count = -1;
- block_map.release ();
- decl_loc_table->empty ();
- cached_dw_loc_list_table->empty ();
- }
- /* Output a marker (i.e. a label) for the beginning of the generated code for
- a lexical block. */
- static void
- dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
- unsigned int blocknum)
- {
- switch_to_section (current_function_section ());
- ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
- }
- /* Output a marker (i.e. a label) for the end of the generated code for a
- lexical block. */
- static void
- dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
- {
- switch_to_section (current_function_section ());
- ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
- }
- /* Returns nonzero if it is appropriate not to emit any debugging
- information for BLOCK, because it doesn't contain any instructions.
- Don't allow this for blocks with nested functions or local classes
- as we would end up with orphans, and in the presence of scheduling
- we may end up calling them anyway. */
- static bool
- dwarf2out_ignore_block (const_tree block)
- {
- tree decl;
- unsigned int i;
- for (decl = BLOCK_VARS (block); decl; decl = DECL_CHAIN (decl))
- if (TREE_CODE (decl) == FUNCTION_DECL
- || (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)))
- return 0;
- for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (block); i++)
- {
- decl = BLOCK_NONLOCALIZED_VAR (block, i);
- if (TREE_CODE (decl) == FUNCTION_DECL
- || (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)))
- return 0;
- }
- return 1;
- }
- /* Hash table routines for file_hash. */
- bool
- dwarf_file_hasher::equal (dwarf_file_data *p1, const char *p2)
- {
- return filename_cmp (p1->filename, p2) == 0;
- }
- hashval_t
- dwarf_file_hasher::hash (dwarf_file_data *p)
- {
- return htab_hash_string (p->filename);
- }
- /* Lookup FILE_NAME (in the list of filenames that we know about here in
- dwarf2out.c) and return its "index". The index of each (known) filename is
- just a unique number which is associated with only that one filename. We
- need such numbers for the sake of generating labels (in the .debug_sfnames
- section) and references to those files numbers (in the .debug_srcinfo
- and.debug_macinfo sections). If the filename given as an argument is not
- found in our current list, add it to the list and assign it the next
- available unique index number. In order to speed up searches, we remember
- the index of the filename was looked up last. This handles the majority of
- all searches. */
- static struct dwarf_file_data *
- lookup_filename (const char *file_name)
- {
- struct dwarf_file_data * created;
- /* Check to see if the file name that was searched on the previous
- call matches this file name. If so, return the index. */
- if (file_table_last_lookup
- && (file_name == file_table_last_lookup->filename
- || filename_cmp (file_table_last_lookup->filename, file_name) == 0))
- return file_table_last_lookup;
- /* Didn't match the previous lookup, search the table. */
- dwarf_file_data **slot
- = file_table->find_slot_with_hash (file_name, htab_hash_string (file_name),
- INSERT);
- if (*slot)
- return *slot;
- created = ggc_alloc<dwarf_file_data> ();
- created->filename = file_name;
- created->emitted_number = 0;
- *slot = created;
- return created;
- }
- /* If the assembler will construct the file table, then translate the compiler
- internal file table number into the assembler file table number, and emit
- a .file directive if we haven't already emitted one yet. The file table
- numbers are different because we prune debug info for unused variables and
- types, which may include filenames. */
- static int
- maybe_emit_file (struct dwarf_file_data * fd)
- {
- if (! fd->emitted_number)
- {
- if (last_emitted_file)
- fd->emitted_number = last_emitted_file->emitted_number + 1;
- else
- fd->emitted_number = 1;
- last_emitted_file = fd;
- if (DWARF2_ASM_LINE_DEBUG_INFO)
- {
- fprintf (asm_out_file, "\t.file %u ", fd->emitted_number);
- output_quoted_string (asm_out_file,
- remap_debug_filename (fd->filename));
- fputc ('\n', asm_out_file);
- }
- }
- return fd->emitted_number;
- }
- /* Schedule generation of a DW_AT_const_value attribute to DIE.
- That generation should happen after function debug info has been
- generated. The value of the attribute is the constant value of ARG. */
- static void
- append_entry_to_tmpl_value_parm_die_table (dw_die_ref die, tree arg)
- {
- die_arg_entry entry;
- if (!die || !arg)
- return;
- if (!tmpl_value_parm_die_table)
- vec_alloc (tmpl_value_parm_die_table, 32);
- entry.die = die;
- entry.arg = arg;
- vec_safe_push (tmpl_value_parm_die_table, entry);
- }
- /* Return TRUE if T is an instance of generic type, FALSE
- otherwise. */
- static bool
- generic_type_p (tree t)
- {
- if (t == NULL_TREE || !TYPE_P (t))
- return false;
- return lang_hooks.get_innermost_generic_parms (t) != NULL_TREE;
- }
- /* Schedule the generation of the generic parameter dies for the
- instance of generic type T. The proper generation itself is later
- done by gen_scheduled_generic_parms_dies. */
- static void
- schedule_generic_params_dies_gen (tree t)
- {
- if (!generic_type_p (t))
- return;
- if (!generic_type_instances)
- vec_alloc (generic_type_instances, 256);
- vec_safe_push (generic_type_instances, t);
- }
- /* Add a DW_AT_const_value attribute to DIEs that were scheduled
- by append_entry_to_tmpl_value_parm_die_table. This function must
- be called after function DIEs have been generated. */
- static void
- gen_remaining_tmpl_value_param_die_attribute (void)
- {
- if (tmpl_value_parm_die_table)
- {
- unsigned i;
- die_arg_entry *e;
- FOR_EACH_VEC_ELT (*tmpl_value_parm_die_table, i, e)
- tree_add_const_value_attribute (e->die, e->arg);
- }
- }
- /* Generate generic parameters DIEs for instances of generic types
- that have been previously scheduled by
- schedule_generic_params_dies_gen. This function must be called
- after all the types of the CU have been laid out. */
- static void
- gen_scheduled_generic_parms_dies (void)
- {
- unsigned i;
- tree t;
- if (!generic_type_instances)
- return;
-
- FOR_EACH_VEC_ELT (*generic_type_instances, i, t)
- if (COMPLETE_TYPE_P (t))
- gen_generic_params_dies (t);
- }
- /* Replace DW_AT_name for the decl with name. */
- static void
- dwarf2out_set_name (tree decl, tree name)
- {
- dw_die_ref die;
- dw_attr_ref attr;
- const char *dname;
- die = TYPE_SYMTAB_DIE (decl);
- if (!die)
- return;
- dname = dwarf2_name (name, 0);
- if (!dname)
- return;
- attr = get_AT (die, DW_AT_name);
- if (attr)
- {
- struct indirect_string_node *node;
- node = find_AT_string (dname);
- /* replace the string. */
- attr->dw_attr_val.v.val_str = node;
- }
- else
- add_name_attribute (die, dname);
- }
- /* True if before or during processing of the first function being emitted. */
- static bool in_first_function_p = true;
- /* True if loc_note during dwarf2out_var_location call might still be
- before first real instruction at address equal to .Ltext0. */
- static bool maybe_at_text_label_p = true;
- /* One above highest N where .LVLN label might be equal to .Ltext0 label. */
- static unsigned int first_loclabel_num_not_at_text_label;
- /* Called by the final INSN scan whenever we see a var location. We
- use it to drop labels in the right places, and throw the location in
- our lookup table. */
- static void
- dwarf2out_var_location (rtx_insn *loc_note)
- {
- char loclabel[MAX_ARTIFICIAL_LABEL_BYTES + 2];
- struct var_loc_node *newloc;
- rtx_insn *next_real, *next_note;
- static const char *last_label;
- static const char *last_postcall_label;
- static bool last_in_cold_section_p;
- static rtx_insn *expected_next_loc_note;
- tree decl;
- bool var_loc_p;
- if (!NOTE_P (loc_note))
- {
- if (CALL_P (loc_note))
- {
- call_site_count++;
- if (SIBLING_CALL_P (loc_note))
- tail_call_site_count++;
- }
- return;
- }
- var_loc_p = NOTE_KIND (loc_note) == NOTE_INSN_VAR_LOCATION;
- if (var_loc_p && !DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
- return;
- /* Optimize processing a large consecutive sequence of location
- notes so we don't spend too much time in next_real_insn. If the
- next insn is another location note, remember the next_real_insn
- calculation for next time. */
- next_real = cached_next_real_insn;
- if (next_real)
- {
- if (expected_next_loc_note != loc_note)
- next_real = NULL;
- }
- next_note = NEXT_INSN (loc_note);
- if (! next_note
- || next_note->deleted ()
- || ! NOTE_P (next_note)
- || (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION
- && NOTE_KIND (next_note) != NOTE_INSN_CALL_ARG_LOCATION))
- next_note = NULL;
- if (! next_real)
- next_real = next_real_insn (loc_note);
- if (next_note)
- {
- expected_next_loc_note = next_note;
- cached_next_real_insn = next_real;
- }
- else
- cached_next_real_insn = NULL;
- /* If there are no instructions which would be affected by this note,
- don't do anything. */
- if (var_loc_p
- && next_real == NULL_RTX
- && !NOTE_DURING_CALL_P (loc_note))
- return;
- if (next_real == NULL_RTX)
- next_real = get_last_insn ();
- /* If there were any real insns between note we processed last time
- and this note (or if it is the first note), clear
- last_{,postcall_}label so that they are not reused this time. */
- if (last_var_location_insn == NULL_RTX
- || last_var_location_insn != next_real
- || last_in_cold_section_p != in_cold_section_p)
- {
- last_label = NULL;
- last_postcall_label = NULL;
- }
- if (var_loc_p)
- {
- decl = NOTE_VAR_LOCATION_DECL (loc_note);
- newloc = add_var_loc_to_decl (decl, loc_note,
- NOTE_DURING_CALL_P (loc_note)
- ? last_postcall_label : last_label);
- if (newloc == NULL)
- return;
- }
- else
- {
- decl = NULL_TREE;
- newloc = NULL;
- }
- /* If there were no real insns between note we processed last time
- and this note, use the label we emitted last time. Otherwise
- create a new label and emit it. */
- if (last_label == NULL)
- {
- ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num);
- ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num);
- loclabel_num++;
- last_label = ggc_strdup (loclabel);
- /* See if loclabel might be equal to .Ltext0. If yes,
- bump first_loclabel_num_not_at_text_label. */
- if (!have_multiple_function_sections
- && in_first_function_p
- && maybe_at_text_label_p)
- {
- static rtx_insn *last_start;
- rtx_insn *insn;
- for (insn = loc_note; insn; insn = previous_insn (insn))
- if (insn == last_start)
- break;
- else if (!NONDEBUG_INSN_P (insn))
- continue;
- else
- {
- rtx body = PATTERN (insn);
- if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
- continue;
- /* Inline asm could occupy zero bytes. */
- else if (GET_CODE (body) == ASM_INPUT
- || asm_noperands (body) >= 0)
- continue;
- #ifdef HAVE_attr_length
- else if (get_attr_min_length (insn) == 0)
- continue;
- #endif
- else
- {
- /* Assume insn has non-zero length. */
- maybe_at_text_label_p = false;
- break;
- }
- }
- if (maybe_at_text_label_p)
- {
- last_start = loc_note;
- first_loclabel_num_not_at_text_label = loclabel_num;
- }
- }
- }
- if (!var_loc_p)
- {
- struct call_arg_loc_node *ca_loc
- = ggc_cleared_alloc<call_arg_loc_node> ();
- rtx_insn *prev = prev_real_insn (loc_note);
- rtx x;
- ca_loc->call_arg_loc_note = loc_note;
- ca_loc->next = NULL;
- ca_loc->label = last_label;
- gcc_assert (prev
- && (CALL_P (prev)
- || (NONJUMP_INSN_P (prev)
- && GET_CODE (PATTERN (prev)) == SEQUENCE
- && CALL_P (XVECEXP (PATTERN (prev), 0, 0)))));
- if (!CALL_P (prev))
- prev = as_a <rtx_sequence *> (PATTERN (prev))->insn (0);
- ca_loc->tail_call_p = SIBLING_CALL_P (prev);
- x = get_call_rtx_from (PATTERN (prev));
- if (x)
- {
- x = XEXP (XEXP (x, 0), 0);
- if (GET_CODE (x) == SYMBOL_REF
- && SYMBOL_REF_DECL (x)
- && TREE_CODE (SYMBOL_REF_DECL (x)) == FUNCTION_DECL)
- ca_loc->symbol_ref = x;
- }
- ca_loc->block = insn_scope (prev);
- if (call_arg_locations)
- call_arg_loc_last->next = ca_loc;
- else
- call_arg_locations = ca_loc;
- call_arg_loc_last = ca_loc;
- }
- else if (!NOTE_DURING_CALL_P (loc_note))
- newloc->label = last_label;
- else
- {
- if (!last_postcall_label)
- {
- sprintf (loclabel, "%s-1", last_label);
- last_postcall_label = ggc_strdup (loclabel);
- }
- newloc->label = last_postcall_label;
- }
- last_var_location_insn = next_real;
- last_in_cold_section_p = in_cold_section_p;
- }
- /* Note in one location list that text section has changed. */
- int
- var_location_switch_text_section_1 (var_loc_list **slot, void *)
- {
- var_loc_list *list = *slot;
- if (list->first)
- list->last_before_switch
- = list->last->next ? list->last->next : list->last;
- return 1;
- }
- /* Note in all location lists that text section has changed. */
- static void
- var_location_switch_text_section (void)
- {
- if (decl_loc_table == NULL)
- return;
- decl_loc_table->traverse<void *, var_location_switch_text_section_1> (NULL);
- }
- /* Create a new line number table. */
- static dw_line_info_table *
- new_line_info_table (void)
- {
- dw_line_info_table *table;
- table = ggc_cleared_alloc<dw_line_info_table_struct> ();
- table->file_num = 1;
- table->line_num = 1;
- table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
- return table;
- }
- /* Lookup the "current" table into which we emit line info, so
- that we don't have to do it for every source line. */
- static void
- set_cur_line_info_table (section *sec)
- {
- dw_line_info_table *table;
- if (sec == text_section)
- table = text_section_line_info;
- else if (sec == cold_text_section)
- {
- table = cold_text_section_line_info;
- if (!table)
- {
- cold_text_section_line_info = table = new_line_info_table ();
- table->end_label = cold_end_label;
- }
- }
- else
- {
- const char *end_label;
- if (flag_reorder_blocks_and_partition)
- {
- if (in_cold_section_p)
- end_label = crtl->subsections.cold_section_end_label;
- else
- end_label = crtl->subsections.hot_section_end_label;
- }
- else
- {
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL,
- current_function_funcdef_no);
- end_label = ggc_strdup (label);
- }
- table = new_line_info_table ();
- table->end_label = end_label;
- vec_safe_push (separate_line_info, table);
- }
- if (DWARF2_ASM_LINE_DEBUG_INFO)
- table->is_stmt = (cur_line_info_table
- ? cur_line_info_table->is_stmt
- : DWARF_LINE_DEFAULT_IS_STMT_START);
- cur_line_info_table = table;
- }
- /* We need to reset the locations at the beginning of each
- function. We can't do this in the end_function hook, because the
- declarations that use the locations won't have been output when
- that hook is called. Also compute have_multiple_function_sections here. */
- static void
- dwarf2out_begin_function (tree fun)
- {
- section *sec = function_section (fun);
- if (sec != text_section)
- have_multiple_function_sections = true;
- if (flag_reorder_blocks_and_partition && !cold_text_section)
- {
- gcc_assert (current_function_decl == fun);
- cold_text_section = unlikely_text_section ();
- switch_to_section (cold_text_section);
- ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label);
- switch_to_section (sec);
- }
- dwarf2out_note_section_used ();
- call_site_count = 0;
- tail_call_site_count = 0;
- set_cur_line_info_table (sec);
- }
- /* Helper function of dwarf2out_end_function, called only after emitting
- the very first function into assembly. Check if some .debug_loc range
- might end with a .LVL* label that could be equal to .Ltext0.
- In that case we must force using absolute addresses in .debug_loc ranges,
- because this range could be .LVLN-.Ltext0 .. .LVLM-.Ltext0 for
- .LVLN == .LVLM == .Ltext0, thus 0 .. 0, which is a .debug_loc
- list terminator.
- Set have_multiple_function_sections to true in that case and
- terminate htab traversal. */
- int
- find_empty_loc_ranges_at_text_label (var_loc_list **slot, int)
- {
- var_loc_list *entry = *slot;
- struct var_loc_node *node;
- node = entry->first;
- if (node && node->next && node->next->label)
- {
- unsigned int i;
- const char *label = node->next->label;
- char loclabel[MAX_ARTIFICIAL_LABEL_BYTES];
- for (i = 0; i < first_loclabel_num_not_at_text_label; i++)
- {
- ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", i);
- if (strcmp (label, loclabel) == 0)
- {
- have_multiple_function_sections = true;
- return 0;
- }
- }
- }
- return 1;
- }
- /* Hook called after emitting a function into assembly.
- This does something only for the very first function emitted. */
- static void
- dwarf2out_end_function (unsigned int)
- {
- if (in_first_function_p
- && !have_multiple_function_sections
- && first_loclabel_num_not_at_text_label
- && decl_loc_table)
- decl_loc_table->traverse<int, find_empty_loc_ranges_at_text_label> (0);
- in_first_function_p = false;
- maybe_at_text_label_p = false;
- }
- /* Temporary holder for dwarf2out_register_main_translation_unit. Used to let
- front-ends register a translation unit even before dwarf2out_init is
- called. */
- static tree main_translation_unit = NULL_TREE;
- /* Hook called by front-ends after they built their main translation unit.
- Associate comp_unit_die to UNIT. */
- static void
- dwarf2out_register_main_translation_unit (tree unit)
- {
- gcc_assert (TREE_CODE (unit) == TRANSLATION_UNIT_DECL
- && main_translation_unit == NULL_TREE);
- main_translation_unit = unit;
- /* If dwarf2out_init has not been called yet, it will perform the association
- itself looking at main_translation_unit. */
- if (decl_die_table != NULL)
- equate_decl_number_to_die (unit, comp_unit_die ());
- }
- /* Add OPCODE+VAL as an entry at the end of the opcode array in TABLE. */
- static void
- push_dw_line_info_entry (dw_line_info_table *table,
- enum dw_line_info_opcode opcode, unsigned int val)
- {
- dw_line_info_entry e;
- e.opcode = opcode;
- e.val = val;
- vec_safe_push (table->entries, e);
- }
- /* Output a label to mark the beginning of a source code line entry
- and record information relating to this source line, in
- 'line_info_table' for later output of the .debug_line section. */
- /* ??? The discriminator parameter ought to be unsigned. */
- static void
- dwarf2out_source_line (unsigned int line, const char *filename,
- int discriminator, bool is_stmt)
- {
- unsigned int file_num;
- dw_line_info_table *table;
- if (debug_info_level < DINFO_LEVEL_TERSE || line == 0)
- return;
- /* The discriminator column was added in dwarf4. Simplify the below
- by simply removing it if we're not supposed to output it. */
- if (dwarf_version < 4 && dwarf_strict)
- discriminator = 0;
- table = cur_line_info_table;
- file_num = maybe_emit_file (lookup_filename (filename));
- /* ??? TODO: Elide duplicate line number entries. Traditionally,
- the debugger has used the second (possibly duplicate) line number
- at the beginning of the function to mark the end of the prologue.
- We could eliminate any other duplicates within the function. For
- Dwarf3, we ought to include the DW_LNS_set_prologue_end mark in
- that second line number entry. */
- /* Recall that this end-of-prologue indication is *not* the same thing
- as the end_prologue debug hook. The NOTE_INSN_PROLOGUE_END note,
- to which the hook corresponds, follows the last insn that was
- emitted by gen_prologue. What we need is to precede the first insn
- that had been emitted after NOTE_INSN_FUNCTION_BEG, i.e. the first
- insn that corresponds to something the user wrote. These may be
- very different locations once scheduling is enabled. */
- if (0 && file_num == table->file_num
- && line == table->line_num
- && discriminator == table->discrim_num
- && is_stmt == table->is_stmt)
- return;
- switch_to_section (current_function_section ());
- /* If requested, emit something human-readable. */
- if (flag_debug_asm)
- fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START, filename, line);
- if (DWARF2_ASM_LINE_DEBUG_INFO)
- {
- /* Emit the .loc directive understood by GNU as. */
- /* "\t.loc %u %u 0 is_stmt %u discriminator %u",
- file_num, line, is_stmt, discriminator */
- fputs ("\t.loc ", asm_out_file);
- fprint_ul (asm_out_file, file_num);
- putc (' ', asm_out_file);
- fprint_ul (asm_out_file, line);
- putc (' ', asm_out_file);
- putc ('0', asm_out_file);
- if (is_stmt != table->is_stmt)
- {
- fputs (" is_stmt ", asm_out_file);
- putc (is_stmt ? '1' : '0', asm_out_file);
- }
- if (SUPPORTS_DISCRIMINATOR && discriminator != 0)
- {
- gcc_assert (discriminator > 0);
- fputs (" discriminator ", asm_out_file);
- fprint_ul (asm_out_file, (unsigned long) discriminator);
- }
- putc ('\n', asm_out_file);
- }
- else
- {
- unsigned int label_num = ++line_info_label_num;
- targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);
- push_dw_line_info_entry (table, LI_set_address, label_num);
- if (file_num != table->file_num)
- push_dw_line_info_entry (table, LI_set_file, file_num);
- if (discriminator != table->discrim_num)
- push_dw_line_info_entry (table, LI_set_discriminator, discriminator);
- if (is_stmt != table->is_stmt)
- push_dw_line_info_entry (table, LI_negate_stmt, 0);
- push_dw_line_info_entry (table, LI_set_line, line);
- }
- table->file_num = file_num;
- table->line_num = line;
- table->discrim_num = discriminator;
- table->is_stmt = is_stmt;
- table->in_use = true;
- }
- /* Record the beginning of a new source file. */
- static void
- dwarf2out_start_source_file (unsigned int lineno, const char *filename)
- {
- if (flag_eliminate_dwarf2_dups)
- {
- /* Record the beginning of the file for break_out_includes. */
- dw_die_ref bincl_die;
- bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die (), NULL);
- add_AT_string (bincl_die, DW_AT_name, remap_debug_filename (filename));
- }
- if (debug_info_level >= DINFO_LEVEL_VERBOSE)
- {
- macinfo_entry e;
- e.code = DW_MACINFO_start_file;
- e.lineno = lineno;
- e.info = ggc_strdup (filename);
- vec_safe_push (macinfo_table, e);
- }
- }
- /* Record the end of a source file. */
- static void
- dwarf2out_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED)
- {
- if (flag_eliminate_dwarf2_dups)
- /* Record the end of the file for break_out_includes. */
- new_die (DW_TAG_GNU_EINCL, comp_unit_die (), NULL);
- if (debug_info_level >= DINFO_LEVEL_VERBOSE)
- {
- macinfo_entry e;
- e.code = DW_MACINFO_end_file;
- e.lineno = lineno;
- e.info = NULL;
- vec_safe_push (macinfo_table, e);
- }
- }
- /* Called from debug_define in toplev.c. The `buffer' parameter contains
- the tail part of the directive line, i.e. the part which is past the
- initial whitespace, #, whitespace, directive-name, whitespace part. */
- static void
- dwarf2out_define (unsigned int lineno ATTRIBUTE_UNUSED,
- const char *buffer ATTRIBUTE_UNUSED)
- {
- if (debug_info_level >= DINFO_LEVEL_VERBOSE)
- {
- macinfo_entry e;
- /* Insert a dummy first entry to be able to optimize the whole
- predefined macro block using DW_MACRO_GNU_transparent_include. */
- if (macinfo_table->is_empty () && lineno <= 1)
- {
- e.code = 0;
- e.lineno = 0;
- e.info = NULL;
- vec_safe_push (macinfo_table, e);
- }
- e.code = DW_MACINFO_define;
- e.lineno = lineno;
- e.info = ggc_strdup (buffer);
- vec_safe_push (macinfo_table, e);
- }
- }
- /* Called from debug_undef in toplev.c. The `buffer' parameter contains
- the tail part of the directive line, i.e. the part which is past the
- initial whitespace, #, whitespace, directive-name, whitespace part. */
- static void
- dwarf2out_undef (unsigned int lineno ATTRIBUTE_UNUSED,
- const char *buffer ATTRIBUTE_UNUSED)
- {
- if (debug_info_level >= DINFO_LEVEL_VERBOSE)
- {
- macinfo_entry e;
- /* Insert a dummy first entry to be able to optimize the whole
- predefined macro block using DW_MACRO_GNU_transparent_include. */
- if (macinfo_table->is_empty () && lineno <= 1)
- {
- e.code = 0;
- e.lineno = 0;
- e.info = NULL;
- vec_safe_push (macinfo_table, e);
- }
- e.code = DW_MACINFO_undef;
- e.lineno = lineno;
- e.info = ggc_strdup (buffer);
- vec_safe_push (macinfo_table, e);
- }
- }
- /* Helpers to manipulate hash table of CUs. */
- struct macinfo_entry_hasher : typed_noop_remove <macinfo_entry>
- {
- typedef macinfo_entry value_type;
- typedef macinfo_entry compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
- };
- inline hashval_t
- macinfo_entry_hasher::hash (const value_type *entry)
- {
- return htab_hash_string (entry->info);
- }
- inline bool
- macinfo_entry_hasher::equal (const value_type *entry1,
- const compare_type *entry2)
- {
- return !strcmp (entry1->info, entry2->info);
- }
- typedef hash_table<macinfo_entry_hasher> macinfo_hash_type;
- /* Output a single .debug_macinfo entry. */
- static void
- output_macinfo_op (macinfo_entry *ref)
- {
- int file_num;
- size_t len;
- struct indirect_string_node *node;
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- struct dwarf_file_data *fd;
- switch (ref->code)
- {
- case DW_MACINFO_start_file:
- fd = lookup_filename (ref->info);
- file_num = maybe_emit_file (fd);
- dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
- dw2_asm_output_data_uleb128 (ref->lineno,
- "Included from line number %lu",
- (unsigned long) ref->lineno);
- dw2_asm_output_data_uleb128 (file_num, "file %s", ref->info);
- break;
- case DW_MACINFO_end_file:
- dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
- break;
- case DW_MACINFO_define:
- case DW_MACINFO_undef:
- len = strlen (ref->info) + 1;
- if (!dwarf_strict
- && len > DWARF_OFFSET_SIZE
- && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
- && (debug_str_section->common.flags & SECTION_MERGE) != 0)
- {
- ref->code = ref->code == DW_MACINFO_define
- ? DW_MACRO_GNU_define_indirect
- : DW_MACRO_GNU_undef_indirect;
- output_macinfo_op (ref);
- return;
- }
- dw2_asm_output_data (1, ref->code,
- ref->code == DW_MACINFO_define
- ? "Define macro" : "Undefine macro");
- dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
- (unsigned long) ref->lineno);
- dw2_asm_output_nstring (ref->info, -1, "The macro");
- break;
- case DW_MACRO_GNU_define_indirect:
- case DW_MACRO_GNU_undef_indirect:
- node = find_AT_string (ref->info);
- gcc_assert (node
- && ((node->form == DW_FORM_strp)
- || (node->form == DW_FORM_GNU_str_index)));
- dw2_asm_output_data (1, ref->code,
- ref->code == DW_MACRO_GNU_define_indirect
- ? "Define macro indirect"
- : "Undefine macro indirect");
- dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
- (unsigned long) ref->lineno);
- if (node->form == DW_FORM_strp)
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
- debug_str_section, "The macro: \"%s\"",
- ref->info);
- else
- dw2_asm_output_data_uleb128 (node->index, "The macro: \"%s\"",
- ref->info);
- break;
- case DW_MACRO_GNU_transparent_include:
- dw2_asm_output_data (1, ref->code, "Transparent include");
- ASM_GENERATE_INTERNAL_LABEL (label,
- DEBUG_MACRO_SECTION_LABEL, ref->lineno);
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL);
- break;
- default:
- fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n",
- ASM_COMMENT_START, (unsigned long) ref->code);
- break;
- }
- }
- /* Attempt to make a sequence of define/undef macinfo ops shareable with
- other compilation unit .debug_macinfo sections. IDX is the first
- index of a define/undef, return the number of ops that should be
- emitted in a comdat .debug_macinfo section and emit
- a DW_MACRO_GNU_transparent_include entry referencing it.
- If the define/undef entry should be emitted normally, return 0. */
- static unsigned
- optimize_macinfo_range (unsigned int idx, vec<macinfo_entry, va_gc> *files,
- macinfo_hash_type **macinfo_htab)
- {
- macinfo_entry *first, *second, *cur, *inc;
- char linebuf[sizeof (HOST_WIDE_INT) * 3 + 1];
- unsigned char checksum[16];
- struct md5_ctx ctx;
- char *grp_name, *tail;
- const char *base;
- unsigned int i, count, encoded_filename_len, linebuf_len;
- macinfo_entry **slot;
- first = &(*macinfo_table)[idx];
- second = &(*macinfo_table)[idx + 1];
- /* Optimize only if there are at least two consecutive define/undef ops,
- and either all of them are before first DW_MACINFO_start_file
- with lineno {0,1} (i.e. predefined macro block), or all of them are
- in some included header file. */
- if (second->code != DW_MACINFO_define && second->code != DW_MACINFO_undef)
- return 0;
- if (vec_safe_is_empty (files))
- {
- if (first->lineno > 1 || second->lineno > 1)
- return 0;
- }
- else if (first->lineno == 0)
- return 0;
- /* Find the last define/undef entry that can be grouped together
- with first and at the same time compute md5 checksum of their
- codes, linenumbers and strings. */
- md5_init_ctx (&ctx);
- for (i = idx; macinfo_table->iterate (i, &cur); i++)
- if (cur->code != DW_MACINFO_define && cur->code != DW_MACINFO_undef)
- break;
- else if (vec_safe_is_empty (files) && cur->lineno > 1)
- break;
- else
- {
- unsigned char code = cur->code;
- md5_process_bytes (&code, 1, &ctx);
- checksum_uleb128 (cur->lineno, &ctx);
- md5_process_bytes (cur->info, strlen (cur->info) + 1, &ctx);
- }
- md5_finish_ctx (&ctx, checksum);
- count = i - idx;
- /* From the containing include filename (if any) pick up just
- usable characters from its basename. */
- if (vec_safe_is_empty (files))
- base = "";
- else
- base = lbasename (files->last ().info);
- for (encoded_filename_len = 0, i = 0; base[i]; i++)
- if (ISIDNUM (base[i]) || base[i] == '.')
- encoded_filename_len++;
- /* Count . at the end. */
- if (encoded_filename_len)
- encoded_filename_len++;
- sprintf (linebuf, HOST_WIDE_INT_PRINT_UNSIGNED, first->lineno);
- linebuf_len = strlen (linebuf);
- /* The group name format is: wmN.[<encoded filename>.]<lineno>.<md5sum> */
- grp_name = XALLOCAVEC (char, 4 + encoded_filename_len + linebuf_len + 1
- + 16 * 2 + 1);
- memcpy (grp_name, DWARF_OFFSET_SIZE == 4 ? "wm4." : "wm8.", 4);
- tail = grp_name + 4;
- if (encoded_filename_len)
- {
- for (i = 0; base[i]; i++)
- if (ISIDNUM (base[i]) || base[i] == '.')
- *tail++ = base[i];
- *tail++ = '.';
- }
- memcpy (tail, linebuf, linebuf_len);
- tail += linebuf_len;
- *tail++ = '.';
- for (i = 0; i < 16; i++)
- sprintf (tail + i * 2, "%02x", checksum[i] & 0xff);
- /* Construct a macinfo_entry for DW_MACRO_GNU_transparent_include
- in the empty vector entry before the first define/undef. */
- inc = &(*macinfo_table)[idx - 1];
- inc->code = DW_MACRO_GNU_transparent_include;
- inc->lineno = 0;
- inc->info = ggc_strdup (grp_name);
- if (!*macinfo_htab)
- *macinfo_htab = new macinfo_hash_type (10);
- /* Avoid emitting duplicates. */
- slot = (*macinfo_htab)->find_slot (inc, INSERT);
- if (*slot != NULL)
- {
- inc->code = 0;
- inc->info = NULL;
- /* If such an entry has been used before, just emit
- a DW_MACRO_GNU_transparent_include op. */
- inc = *slot;
- output_macinfo_op (inc);
- /* And clear all macinfo_entry in the range to avoid emitting them
- in the second pass. */
- for (i = idx; macinfo_table->iterate (i, &cur) && i < idx + count; i++)
- {
- cur->code = 0;
- cur->info = NULL;
- }
- }
- else
- {
- *slot = inc;
- inc->lineno = (*macinfo_htab)->elements ();
- output_macinfo_op (inc);
- }
- return count;
- }
- /* Save any strings needed by the macinfo table in the debug str
- table. All strings must be collected into the table by the time
- index_string is called. */
- static void
- save_macinfo_strings (void)
- {
- unsigned len;
- unsigned i;
- macinfo_entry *ref;
- for (i = 0; macinfo_table && macinfo_table->iterate (i, &ref); i++)
- {
- switch (ref->code)
- {
- /* Match the logic in output_macinfo_op to decide on
- indirect strings. */
- case DW_MACINFO_define:
- case DW_MACINFO_undef:
- len = strlen (ref->info) + 1;
- if (!dwarf_strict
- && len > DWARF_OFFSET_SIZE
- && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
- && (debug_str_section->common.flags & SECTION_MERGE) != 0)
- set_indirect_string (find_AT_string (ref->info));
- break;
- case DW_MACRO_GNU_define_indirect:
- case DW_MACRO_GNU_undef_indirect:
- set_indirect_string (find_AT_string (ref->info));
- break;
- default:
- break;
- }
- }
- }
- /* Output macinfo section(s). */
- static void
- output_macinfo (void)
- {
- unsigned i;
- unsigned long length = vec_safe_length (macinfo_table);
- macinfo_entry *ref;
- vec<macinfo_entry, va_gc> *files = NULL;
- macinfo_hash_type *macinfo_htab = NULL;
- if (! length)
- return;
- /* output_macinfo* uses these interchangeably. */
- gcc_assert ((int) DW_MACINFO_define == (int) DW_MACRO_GNU_define
- && (int) DW_MACINFO_undef == (int) DW_MACRO_GNU_undef
- && (int) DW_MACINFO_start_file == (int) DW_MACRO_GNU_start_file
- && (int) DW_MACINFO_end_file == (int) DW_MACRO_GNU_end_file);
- /* For .debug_macro emit the section header. */
- if (!dwarf_strict)
- {
- dw2_asm_output_data (2, 4, "DWARF macro version number");
- if (DWARF_OFFSET_SIZE == 8)
- dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present");
- else
- dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present");
- dw2_asm_output_offset (DWARF_OFFSET_SIZE,
- (!dwarf_split_debug_info ? debug_line_section_label
- : debug_skeleton_line_section_label),
- debug_line_section, NULL);
- }
- /* In the first loop, it emits the primary .debug_macinfo section
- and after each emitted op the macinfo_entry is cleared.
- If a longer range of define/undef ops can be optimized using
- DW_MACRO_GNU_transparent_include, the
- DW_MACRO_GNU_transparent_include op is emitted and kept in
- the vector before the first define/undef in the range and the
- whole range of define/undef ops is not emitted and kept. */
- for (i = 0; macinfo_table->iterate (i, &ref); i++)
- {
- switch (ref->code)
- {
- case DW_MACINFO_start_file:
- vec_safe_push (files, *ref);
- break;
- case DW_MACINFO_end_file:
- if (!vec_safe_is_empty (files))
- files->pop ();
- break;
- case DW_MACINFO_define:
- case DW_MACINFO_undef:
- if (!dwarf_strict
- && HAVE_COMDAT_GROUP
- && vec_safe_length (files) != 1
- && i > 0
- && i + 1 < length
- && (*macinfo_table)[i - 1].code == 0)
- {
- unsigned count = optimize_macinfo_range (i, files, &macinfo_htab);
- if (count)
- {
- i += count - 1;
- continue;
- }
- }
- break;
- case 0:
- /* A dummy entry may be inserted at the beginning to be able
- to optimize the whole block of predefined macros. */
- if (i == 0)
- continue;
- default:
- break;
- }
- output_macinfo_op (ref);
- ref->info = NULL;
- ref->code = 0;
- }
- if (!macinfo_htab)
- return;
- delete macinfo_htab;
- macinfo_htab = NULL;
- /* If any DW_MACRO_GNU_transparent_include were used, on those
- DW_MACRO_GNU_transparent_include entries terminate the
- current chain and switch to a new comdat .debug_macinfo
- section and emit the define/undef entries within it. */
- for (i = 0; macinfo_table->iterate (i, &ref); i++)
- switch (ref->code)
- {
- case 0:
- continue;
- case DW_MACRO_GNU_transparent_include:
- {
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- tree comdat_key = get_identifier (ref->info);
- /* Terminate the previous .debug_macinfo section. */
- dw2_asm_output_data (1, 0, "End compilation unit");
- targetm.asm_out.named_section (DEBUG_MACRO_SECTION,
- SECTION_DEBUG
- | SECTION_LINKONCE,
- comdat_key);
- ASM_GENERATE_INTERNAL_LABEL (label,
- DEBUG_MACRO_SECTION_LABEL,
- ref->lineno);
- ASM_OUTPUT_LABEL (asm_out_file, label);
- ref->code = 0;
- ref->info = NULL;
- dw2_asm_output_data (2, 4, "DWARF macro version number");
- if (DWARF_OFFSET_SIZE == 8)
- dw2_asm_output_data (1, 1, "Flags: 64-bit");
- else
- dw2_asm_output_data (1, 0, "Flags: 32-bit");
- }
- break;
- case DW_MACINFO_define:
- case DW_MACINFO_undef:
- output_macinfo_op (ref);
- ref->code = 0;
- ref->info = NULL;
- break;
- default:
- gcc_unreachable ();
- }
- }
- /* Set up for Dwarf output at the start of compilation. */
- static void
- dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
- {
- /* This option is currently broken, see (PR53118 and PR46102). */
- if (flag_eliminate_dwarf2_dups
- && strstr (lang_hooks.name, "C++"))
- {
- warning (0, "-feliminate-dwarf2-dups is broken for C++, ignoring");
- flag_eliminate_dwarf2_dups = 0;
- }
- /* Allocate the file_table. */
- file_table = hash_table<dwarf_file_hasher>::create_ggc (50);
- /* Allocate the decl_die_table. */
- decl_die_table = hash_table<decl_die_hasher>::create_ggc (10);
- /* Allocate the decl_loc_table. */
- decl_loc_table = hash_table<decl_loc_hasher>::create_ggc (10);
- /* Allocate the cached_dw_loc_list_table. */
- cached_dw_loc_list_table = hash_table<dw_loc_list_hasher>::create_ggc (10);
- /* Allocate the initial hunk of the decl_scope_table. */
- vec_alloc (decl_scope_table, 256);
- /* Allocate the initial hunk of the abbrev_die_table. */
- abbrev_die_table = ggc_cleared_vec_alloc<dw_die_ref>
- (ABBREV_DIE_TABLE_INCREMENT);
- abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
- /* Zero-th entry is allocated, but unused. */
- abbrev_die_table_in_use = 1;
- /* Allocate the pubtypes and pubnames vectors. */
- vec_alloc (pubname_table, 32);
- vec_alloc (pubtype_table, 32);
- vec_alloc (incomplete_types, 64);
- vec_alloc (used_rtx_array, 32);
- if (!dwarf_split_debug_info)
- {
- debug_info_section = get_section (DEBUG_INFO_SECTION,
- SECTION_DEBUG, NULL);
- debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
- SECTION_DEBUG, NULL);
- debug_loc_section = get_section (DEBUG_LOC_SECTION,
- SECTION_DEBUG, NULL);
- }
- else
- {
- debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE,
- NULL);
- debug_addr_section = get_section (DEBUG_ADDR_SECTION,
- SECTION_DEBUG, NULL);
- debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
- SECTION_DEBUG, NULL);
- debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
- SECTION_DEBUG, NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
- DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0);
- /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
- the main .o, but the skeleton_line goes into the split off dwo. */
- debug_skeleton_line_section
- = get_section (DEBUG_DWO_LINE_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
- DEBUG_SKELETON_LINE_SECTION_LABEL, 0);
- debug_str_offsets_section = get_section (DEBUG_STR_OFFSETS_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE,
- NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
- DEBUG_SKELETON_INFO_SECTION_LABEL, 0);
- debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
- DEBUG_STR_DWO_SECTION_FLAGS, NULL);
- }
- debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
- SECTION_DEBUG, NULL);
- debug_macinfo_section = get_section (dwarf_strict
- ? DEBUG_MACINFO_SECTION
- : DEBUG_MACRO_SECTION,
- DEBUG_MACRO_SECTION_FLAGS, NULL);
- debug_line_section = get_section (DEBUG_LINE_SECTION,
- SECTION_DEBUG, NULL);
- debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
- SECTION_DEBUG, NULL);
- debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
- SECTION_DEBUG, NULL);
- debug_str_section = get_section (DEBUG_STR_SECTION,
- DEBUG_STR_SECTION_FLAGS, NULL);
- debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
- SECTION_DEBUG, NULL);
- debug_frame_section = get_section (DEBUG_FRAME_SECTION,
- SECTION_DEBUG, NULL);
- ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
- DEBUG_ABBREV_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
- COLD_TEXT_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
- DEBUG_INFO_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
- DEBUG_LINE_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
- DEBUG_RANGES_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
- DEBUG_ADDR_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
- dwarf_strict
- ? DEBUG_MACINFO_SECTION_LABEL
- : DEBUG_MACRO_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0);
- if (debug_info_level >= DINFO_LEVEL_VERBOSE)
- vec_alloc (macinfo_table, 64);
- switch_to_section (text_section);
- ASM_OUTPUT_LABEL (asm_out_file, text_section_label);
- /* Make sure the line number table for .text always exists. */
- text_section_line_info = new_line_info_table ();
- text_section_line_info->end_label = text_end_label;
- /* If front-ends already registered a main translation unit but we were not
- ready to perform the association, do this now. */
- if (main_translation_unit != NULL_TREE)
- equate_decl_number_to_die (main_translation_unit, comp_unit_die ());
- }
- /* Called before compile () starts outputtting functions, variables
- and toplevel asms into assembly. */
- static void
- dwarf2out_assembly_start (void)
- {
- if (HAVE_GAS_CFI_SECTIONS_DIRECTIVE
- && dwarf2out_do_cfi_asm ()
- && (!(flag_unwind_tables || flag_exceptions)
- || targetm_common.except_unwind_info (&global_options) != UI_DWARF2))
- fprintf (asm_out_file, "\t.cfi_sections\t.debug_frame\n");
- }
- /* A helper function for dwarf2out_finish called through
- htab_traverse. Assign a string its index. All strings must be
- collected into the table by the time index_string is called,
- because the indexing code relies on htab_traverse to traverse nodes
- in the same order for each run. */
- int
- index_string (indirect_string_node **h, unsigned int *index)
- {
- indirect_string_node *node = *h;
- find_string_form (node);
- if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
- {
- gcc_assert (node->index == NO_INDEX_ASSIGNED);
- node->index = *index;
- *index += 1;
- }
- return 1;
- }
- /* A helper function for output_indirect_strings called through
- htab_traverse. Output the offset to a string and update the
- current offset. */
- int
- output_index_string_offset (indirect_string_node **h, unsigned int *offset)
- {
- indirect_string_node *node = *h;
- if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
- {
- /* Assert that this node has been assigned an index. */
- gcc_assert (node->index != NO_INDEX_ASSIGNED
- && node->index != NOT_INDEXED);
- dw2_asm_output_data (DWARF_OFFSET_SIZE, *offset,
- "indexed string 0x%x: %s", node->index, node->str);
- *offset += strlen (node->str) + 1;
- }
- return 1;
- }
- /* A helper function for dwarf2out_finish called through
- htab_traverse. Output the indexed string. */
- int
- output_index_string (indirect_string_node **h, unsigned int *cur_idx)
- {
- struct indirect_string_node *node = *h;
- if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
- {
- /* Assert that the strings are output in the same order as their
- indexes were assigned. */
- gcc_assert (*cur_idx == node->index);
- assemble_string (node->str, strlen (node->str) + 1);
- *cur_idx += 1;
- }
- return 1;
- }
- /* A helper function for dwarf2out_finish called through
- htab_traverse. Emit one queued .debug_str string. */
- int
- output_indirect_string (indirect_string_node **h, void *)
- {
- struct indirect_string_node *node = *h;
- node->form = find_string_form (node);
- if (node->form == DW_FORM_strp && node->refcount > 0)
- {
- ASM_OUTPUT_LABEL (asm_out_file, node->label);
- assemble_string (node->str, strlen (node->str) + 1);
- }
- return 1;
- }
- /* Output the indexed string table. */
- static void
- output_indirect_strings (void)
- {
- switch_to_section (debug_str_section);
- if (!dwarf_split_debug_info)
- debug_str_hash->traverse<void *, output_indirect_string> (NULL);
- else
- {
- unsigned int offset = 0;
- unsigned int cur_idx = 0;
- skeleton_debug_str_hash->traverse<void *, output_indirect_string> (NULL);
- switch_to_section (debug_str_offsets_section);
- debug_str_hash->traverse_noresize
- <unsigned int *, output_index_string_offset> (&offset);
- switch_to_section (debug_str_dwo_section);
- debug_str_hash->traverse_noresize<unsigned int *, output_index_string>
- (&cur_idx);
- }
- }
- /* Callback for htab_traverse to assign an index to an entry in the
- table, and to write that entry to the .debug_addr section. */
- int
- output_addr_table_entry (addr_table_entry **slot, unsigned int *cur_index)
- {
- addr_table_entry *entry = *slot;
- if (entry->refcount == 0)
- {
- gcc_assert (entry->index == NO_INDEX_ASSIGNED
- || entry->index == NOT_INDEXED);
- return 1;
- }
- gcc_assert (entry->index == *cur_index);
- (*cur_index)++;
- switch (entry->kind)
- {
- case ate_kind_rtx:
- dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, entry->addr.rtl,
- "0x%x", entry->index);
- break;
- case ate_kind_rtx_dtprel:
- gcc_assert (targetm.asm_out.output_dwarf_dtprel);
- targetm.asm_out.output_dwarf_dtprel (asm_out_file,
- DWARF2_ADDR_SIZE,
- entry->addr.rtl);
- fputc ('\n', asm_out_file);
- break;
- case ate_kind_label:
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, entry->addr.label,
- "0x%x", entry->index);
- break;
- default:
- gcc_unreachable ();
- }
- return 1;
- }
- /* Produce the .debug_addr section. */
- static void
- output_addr_table (void)
- {
- unsigned int index = 0;
- if (addr_index_table == NULL || addr_index_table->size () == 0)
- return;
- switch_to_section (debug_addr_section);
- addr_index_table
- ->traverse_noresize<unsigned int *, output_addr_table_entry> (&index);
- }
- #if ENABLE_ASSERT_CHECKING
- /* Verify that all marks are clear. */
- static void
- verify_marks_clear (dw_die_ref die)
- {
- dw_die_ref c;
- gcc_assert (! die->die_mark);
- FOR_EACH_CHILD (die, c, verify_marks_clear (c));
- }
- #endif /* ENABLE_ASSERT_CHECKING */
- /* Clear the marks for a die and its children.
- Be cool if the mark isn't set. */
- static void
- prune_unmark_dies (dw_die_ref die)
- {
- dw_die_ref c;
- if (die->die_mark)
- die->die_mark = 0;
- FOR_EACH_CHILD (die, c, prune_unmark_dies (c));
- }
- /* Given DIE that we're marking as used, find any other dies
- it references as attributes and mark them as used. */
- static void
- prune_unused_types_walk_attribs (dw_die_ref die)
- {
- dw_attr_ref a;
- unsigned ix;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- {
- if (a->dw_attr_val.val_class == dw_val_class_die_ref)
- {
- /* A reference to another DIE.
- Make sure that it will get emitted.
- If it was broken out into a comdat group, don't follow it. */
- if (! AT_ref (a)->comdat_type_p
- || a->dw_attr == DW_AT_specification)
- prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
- }
- /* Set the string's refcount to 0 so that prune_unused_types_mark
- accounts properly for it. */
- if (AT_class (a) == dw_val_class_str)
- a->dw_attr_val.v.val_str->refcount = 0;
- }
- }
- /* Mark the generic parameters and arguments children DIEs of DIE. */
- static void
- prune_unused_types_mark_generic_parms_dies (dw_die_ref die)
- {
- dw_die_ref c;
- if (die == NULL || die->die_child == NULL)
- return;
- c = die->die_child;
- do
- {
- if (is_template_parameter (c))
- prune_unused_types_mark (c, 1);
- c = c->die_sib;
- } while (c && c != die->die_child);
- }
- /* Mark DIE as being used. If DOKIDS is true, then walk down
- to DIE's children. */
- static void
- prune_unused_types_mark (dw_die_ref die, int dokids)
- {
- dw_die_ref c;
- if (die->die_mark == 0)
- {
- /* We haven't done this node yet. Mark it as used. */
- die->die_mark = 1;
- /* If this is the DIE of a generic type instantiation,
- mark the children DIEs that describe its generic parms and
- args. */
- prune_unused_types_mark_generic_parms_dies (die);
- /* We also have to mark its parents as used.
- (But we don't want to mark our parent's kids due to this,
- unless it is a class.) */
- if (die->die_parent)
- prune_unused_types_mark (die->die_parent,
- class_scope_p (die->die_parent));
- /* Mark any referenced nodes. */
- prune_unused_types_walk_attribs (die);
- /* If this node is a specification,
- also mark the definition, if it exists. */
- if (get_AT_flag (die, DW_AT_declaration) && die->die_definition)
- prune_unused_types_mark (die->die_definition, 1);
- }
- if (dokids && die->die_mark != 2)
- {
- /* We need to walk the children, but haven't done so yet.
- Remember that we've walked the kids. */
- die->die_mark = 2;
- /* If this is an array type, we need to make sure our
- kids get marked, even if they're types. If we're
- breaking out types into comdat sections, do this
- for all type definitions. */
- if (die->die_tag == DW_TAG_array_type
- || (use_debug_types
- && is_type_die (die) && ! is_declaration_die (die)))
- FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1));
- else
- FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
- }
- }
- /* For local classes, look if any static member functions were emitted
- and if so, mark them. */
- static void
- prune_unused_types_walk_local_classes (dw_die_ref die)
- {
- dw_die_ref c;
- if (die->die_mark == 2)
- return;
- switch (die->die_tag)
- {
- case DW_TAG_structure_type:
- case DW_TAG_union_type:
- case DW_TAG_class_type:
- break;
- case DW_TAG_subprogram:
- if (!get_AT_flag (die, DW_AT_declaration)
- || die->die_definition != NULL)
- prune_unused_types_mark (die, 1);
- return;
- default:
- return;
- }
- /* Mark children. */
- FOR_EACH_CHILD (die, c, prune_unused_types_walk_local_classes (c));
- }
- /* Walk the tree DIE and mark types that we actually use. */
- static void
- prune_unused_types_walk (dw_die_ref die)
- {
- dw_die_ref c;
- /* Don't do anything if this node is already marked and
- children have been marked as well. */
- if (die->die_mark == 2)
- return;
- switch (die->die_tag)
- {
- case DW_TAG_structure_type:
- case DW_TAG_union_type:
- case DW_TAG_class_type:
- if (die->die_perennial_p)
- break;
- for (c = die->die_parent; c; c = c->die_parent)
- if (c->die_tag == DW_TAG_subprogram)
- break;
- /* Finding used static member functions inside of classes
- is needed just for local classes, because for other classes
- static member function DIEs with DW_AT_specification
- are emitted outside of the DW_TAG_*_type. If we ever change
- it, we'd need to call this even for non-local classes. */
- if (c)
- prune_unused_types_walk_local_classes (die);
- /* It's a type node --- don't mark it. */
- return;
- case DW_TAG_const_type:
- case DW_TAG_packed_type:
- case DW_TAG_pointer_type:
- case DW_TAG_reference_type:
- case DW_TAG_rvalue_reference_type:
- case DW_TAG_volatile_type:
- case DW_TAG_typedef:
- case DW_TAG_array_type:
- case DW_TAG_interface_type:
- case DW_TAG_friend:
- case DW_TAG_variant_part:
- case DW_TAG_enumeration_type:
- case DW_TAG_subroutine_type:
- case DW_TAG_string_type:
- case DW_TAG_set_type:
- case DW_TAG_subrange_type:
- case DW_TAG_ptr_to_member_type:
- case DW_TAG_file_type:
- if (die->die_perennial_p)
- break;
- /* It's a type node --- don't mark it. */
- return;
- default:
- /* Mark everything else. */
- break;
- }
- if (die->die_mark == 0)
- {
- die->die_mark = 1;
- /* Now, mark any dies referenced from here. */
- prune_unused_types_walk_attribs (die);
- }
- die->die_mark = 2;
- /* Mark children. */
- FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
- }
- /* Increment the string counts on strings referred to from DIE's
- attributes. */
- static void
- prune_unused_types_update_strings (dw_die_ref die)
- {
- dw_attr_ref a;
- unsigned ix;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- if (AT_class (a) == dw_val_class_str)
- {
- struct indirect_string_node *s = a->dw_attr_val.v.val_str;
- s->refcount++;
- /* Avoid unnecessarily putting strings that are used less than
- twice in the hash table. */
- if (s->refcount
- == ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) ? 1 : 2))
- {
- indirect_string_node **slot
- = debug_str_hash->find_slot_with_hash (s->str,
- htab_hash_string (s->str),
- INSERT);
- gcc_assert (*slot == NULL);
- *slot = s;
- }
- }
- }
- /* Remove from the tree DIE any dies that aren't marked. */
- static void
- prune_unused_types_prune (dw_die_ref die)
- {
- dw_die_ref c;
- gcc_assert (die->die_mark);
- prune_unused_types_update_strings (die);
- if (! die->die_child)
- return;
- c = die->die_child;
- do {
- dw_die_ref prev = c;
- for (c = c->die_sib; ! c->die_mark; c = c->die_sib)
- if (c == die->die_child)
- {
- /* No marked children between 'prev' and the end of the list. */
- if (prev == c)
- /* No marked children at all. */
- die->die_child = NULL;
- else
- {
- prev->die_sib = c->die_sib;
- die->die_child = prev;
- }
- return;
- }
- if (c != prev->die_sib)
- prev->die_sib = c;
- prune_unused_types_prune (c);
- } while (c != die->die_child);
- }
- /* Remove dies representing declarations that we never use. */
- static void
- prune_unused_types (void)
- {
- unsigned int i;
- limbo_die_node *node;
- comdat_type_node *ctnode;
- pubname_ref pub;
- dw_die_ref base_type;
- #if ENABLE_ASSERT_CHECKING
- /* All the marks should already be clear. */
- verify_marks_clear (comp_unit_die ());
- for (node = limbo_die_list; node; node = node->next)
- verify_marks_clear (node->die);
- for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
- verify_marks_clear (ctnode->root_die);
- #endif /* ENABLE_ASSERT_CHECKING */
- /* Mark types that are used in global variables. */
- premark_types_used_by_global_vars ();
- /* Set the mark on nodes that are actually used. */
- prune_unused_types_walk (comp_unit_die ());
- for (node = limbo_die_list; node; node = node->next)
- prune_unused_types_walk (node->die);
- for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
- {
- prune_unused_types_walk (ctnode->root_die);
- prune_unused_types_mark (ctnode->type_die, 1);
- }
- /* Also set the mark on nodes referenced from the pubname_table. Enumerators
- are unusual in that they are pubnames that are the children of pubtypes.
- They should only be marked via their parent DW_TAG_enumeration_type die,
- not as roots in themselves. */
- FOR_EACH_VEC_ELT (*pubname_table, i, pub)
- if (pub->die->die_tag != DW_TAG_enumerator)
- prune_unused_types_mark (pub->die, 1);
- for (i = 0; base_types.iterate (i, &base_type); i++)
- prune_unused_types_mark (base_type, 1);
- if (debug_str_hash)
- debug_str_hash->empty ();
- if (skeleton_debug_str_hash)
- skeleton_debug_str_hash->empty ();
- prune_unused_types_prune (comp_unit_die ());
- for (node = limbo_die_list; node; node = node->next)
- prune_unused_types_prune (node->die);
- for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
- prune_unused_types_prune (ctnode->root_die);
- /* Leave the marks clear. */
- prune_unmark_dies (comp_unit_die ());
- for (node = limbo_die_list; node; node = node->next)
- prune_unmark_dies (node->die);
- for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
- prune_unmark_dies (ctnode->root_die);
- }
- /* Set the parameter to true if there are any relative pathnames in
- the file table. */
- int
- file_table_relative_p (dwarf_file_data **slot, bool *p)
- {
- struct dwarf_file_data *d = *slot;
- if (!IS_ABSOLUTE_PATH (d->filename))
- {
- *p = true;
- return 0;
- }
- return 1;
- }
- /* Helpers to manipulate hash table of comdat type units. */
- struct comdat_type_hasher : typed_noop_remove <comdat_type_node>
- {
- typedef comdat_type_node value_type;
- typedef comdat_type_node compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
- };
- inline hashval_t
- comdat_type_hasher::hash (const value_type *type_node)
- {
- hashval_t h;
- memcpy (&h, type_node->signature, sizeof (h));
- return h;
- }
- inline bool
- comdat_type_hasher::equal (const value_type *type_node_1,
- const compare_type *type_node_2)
- {
- return (! memcmp (type_node_1->signature, type_node_2->signature,
- DWARF_TYPE_SIGNATURE_SIZE));
- }
- /* Move a DW_AT_{,MIPS_}linkage_name attribute just added to dw_die_ref
- to the location it would have been added, should we know its
- DECL_ASSEMBLER_NAME when we added other attributes. This will
- probably improve compactness of debug info, removing equivalent
- abbrevs, and hide any differences caused by deferring the
- computation of the assembler name, triggered by e.g. PCH. */
- static inline void
- move_linkage_attr (dw_die_ref die)
- {
- unsigned ix = vec_safe_length (die->die_attr);
- dw_attr_node linkage = (*die->die_attr)[ix - 1];
- gcc_assert (linkage.dw_attr == DW_AT_linkage_name
- || linkage.dw_attr == DW_AT_MIPS_linkage_name);
- while (--ix > 0)
- {
- dw_attr_node *prev = &(*die->die_attr)[ix - 1];
- if (prev->dw_attr == DW_AT_decl_line || prev->dw_attr == DW_AT_name)
- break;
- }
- if (ix != vec_safe_length (die->die_attr) - 1)
- {
- die->die_attr->pop ();
- die->die_attr->quick_insert (ix, linkage);
- }
- }
- /* Helper function for resolve_addr, mark DW_TAG_base_type nodes
- referenced from typed stack ops and count how often they are used. */
- static void
- mark_base_types (dw_loc_descr_ref loc)
- {
- dw_die_ref base_type = NULL;
- for (; loc; loc = loc->dw_loc_next)
- {
- switch (loc->dw_loc_opc)
- {
- case DW_OP_GNU_regval_type:
- case DW_OP_GNU_deref_type:
- base_type = loc->dw_loc_oprnd2.v.val_die_ref.die;
- break;
- case DW_OP_GNU_convert:
- case DW_OP_GNU_reinterpret:
- if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const)
- continue;
- /* FALLTHRU */
- case DW_OP_GNU_const_type:
- base_type = loc->dw_loc_oprnd1.v.val_die_ref.die;
- break;
- case DW_OP_GNU_entry_value:
- mark_base_types (loc->dw_loc_oprnd1.v.val_loc);
- continue;
- default:
- continue;
- }
- gcc_assert (base_type->die_parent == comp_unit_die ());
- if (base_type->die_mark)
- base_type->die_mark++;
- else
- {
- base_types.safe_push (base_type);
- base_type->die_mark = 1;
- }
- }
- }
- /* Comparison function for sorting marked base types. */
- static int
- base_type_cmp (const void *x, const void *y)
- {
- dw_die_ref dx = *(const dw_die_ref *) x;
- dw_die_ref dy = *(const dw_die_ref *) y;
- unsigned int byte_size1, byte_size2;
- unsigned int encoding1, encoding2;
- if (dx->die_mark > dy->die_mark)
- return -1;
- if (dx->die_mark < dy->die_mark)
- return 1;
- byte_size1 = get_AT_unsigned (dx, DW_AT_byte_size);
- byte_size2 = get_AT_unsigned (dy, DW_AT_byte_size);
- if (byte_size1 < byte_size2)
- return 1;
- if (byte_size1 > byte_size2)
- return -1;
- encoding1 = get_AT_unsigned (dx, DW_AT_encoding);
- encoding2 = get_AT_unsigned (dy, DW_AT_encoding);
- if (encoding1 < encoding2)
- return 1;
- if (encoding1 > encoding2)
- return -1;
- return 0;
- }
- /* Move base types marked by mark_base_types as early as possible
- in the CU, sorted by decreasing usage count both to make the
- uleb128 references as small as possible and to make sure they
- will have die_offset already computed by calc_die_sizes when
- sizes of typed stack loc ops is computed. */
- static void
- move_marked_base_types (void)
- {
- unsigned int i;
- dw_die_ref base_type, die, c;
- if (base_types.is_empty ())
- return;
- /* Sort by decreasing usage count, they will be added again in that
- order later on. */
- base_types.qsort (base_type_cmp);
- die = comp_unit_die ();
- c = die->die_child;
- do
- {
- dw_die_ref prev = c;
- c = c->die_sib;
- while (c->die_mark)
- {
- remove_child_with_prev (c, prev);
- /* As base types got marked, there must be at least
- one node other than DW_TAG_base_type. */
- gcc_assert (c != c->die_sib);
- c = c->die_sib;
- }
- }
- while (c != die->die_child);
- gcc_assert (die->die_child);
- c = die->die_child;
- for (i = 0; base_types.iterate (i, &base_type); i++)
- {
- base_type->die_mark = 0;
- base_type->die_sib = c->die_sib;
- c->die_sib = base_type;
- c = base_type;
- }
- }
- /* Helper function for resolve_addr, attempt to resolve
- one CONST_STRING, return true if successful. Similarly verify that
- SYMBOL_REFs refer to variables emitted in the current CU. */
- static bool
- resolve_one_addr (rtx *addr)
- {
- rtx rtl = *addr;
- if (GET_CODE (rtl) == CONST_STRING)
- {
- size_t len = strlen (XSTR (rtl, 0)) + 1;
- tree t = build_string (len, XSTR (rtl, 0));
- tree tlen = size_int (len - 1);
- TREE_TYPE (t)
- = build_array_type (char_type_node, build_index_type (tlen));
- rtl = lookup_constant_def (t);
- if (!rtl || !MEM_P (rtl))
- return false;
- rtl = XEXP (rtl, 0);
- if (GET_CODE (rtl) == SYMBOL_REF
- && SYMBOL_REF_DECL (rtl)
- && !TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
- return false;
- vec_safe_push (used_rtx_array, rtl);
- *addr = rtl;
- return true;
- }
- if (GET_CODE (rtl) == SYMBOL_REF
- && SYMBOL_REF_DECL (rtl))
- {
- if (TREE_CONSTANT_POOL_ADDRESS_P (rtl))
- {
- if (!TREE_ASM_WRITTEN (DECL_INITIAL (SYMBOL_REF_DECL (rtl))))
- return false;
- }
- else if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
- return false;
- }
- if (GET_CODE (rtl) == CONST)
- {
- subrtx_ptr_iterator::array_type array;
- FOR_EACH_SUBRTX_PTR (iter, array, &XEXP (rtl, 0), ALL)
- if (!resolve_one_addr (*iter))
- return false;
- }
- return true;
- }
- /* For STRING_CST, return SYMBOL_REF of its constant pool entry,
- if possible, and create DW_TAG_dwarf_procedure that can be referenced
- from DW_OP_GNU_implicit_pointer if the string hasn't been seen yet. */
- static rtx
- string_cst_pool_decl (tree t)
- {
- rtx rtl = output_constant_def (t, 1);
- unsigned char *array;
- dw_loc_descr_ref l;
- tree decl;
- size_t len;
- dw_die_ref ref;
- if (!rtl || !MEM_P (rtl))
- return NULL_RTX;
- rtl = XEXP (rtl, 0);
- if (GET_CODE (rtl) != SYMBOL_REF
- || SYMBOL_REF_DECL (rtl) == NULL_TREE)
- return NULL_RTX;
- decl = SYMBOL_REF_DECL (rtl);
- if (!lookup_decl_die (decl))
- {
- len = TREE_STRING_LENGTH (t);
- vec_safe_push (used_rtx_array, rtl);
- ref = new_die (DW_TAG_dwarf_procedure, comp_unit_die (), decl);
- array = ggc_vec_alloc<unsigned char> (len);
- memcpy (array, TREE_STRING_POINTER (t), len);
- l = new_loc_descr (DW_OP_implicit_value, len, 0);
- l->dw_loc_oprnd2.val_class = dw_val_class_vec;
- l->dw_loc_oprnd2.v.val_vec.length = len;
- l->dw_loc_oprnd2.v.val_vec.elt_size = 1;
- l->dw_loc_oprnd2.v.val_vec.array = array;
- add_AT_loc (ref, DW_AT_location, l);
- equate_decl_number_to_die (decl, ref);
- }
- return rtl;
- }
- /* Helper function of resolve_addr_in_expr. LOC is
- a DW_OP_addr followed by DW_OP_stack_value, either at the start
- of exprloc or after DW_OP_{,bit_}piece, and val_addr can't be
- resolved. Replace it (both DW_OP_addr and DW_OP_stack_value)
- with DW_OP_GNU_implicit_pointer if possible
- and return true, if unsuccessful, return false. */
- static bool
- optimize_one_addr_into_implicit_ptr (dw_loc_descr_ref loc)
- {
- rtx rtl = loc->dw_loc_oprnd1.v.val_addr;
- HOST_WIDE_INT offset = 0;
- dw_die_ref ref = NULL;
- tree decl;
- if (GET_CODE (rtl) == CONST
- && GET_CODE (XEXP (rtl, 0)) == PLUS
- && CONST_INT_P (XEXP (XEXP (rtl, 0), 1)))
- {
- offset = INTVAL (XEXP (XEXP (rtl, 0), 1));
- rtl = XEXP (XEXP (rtl, 0), 0);
- }
- if (GET_CODE (rtl) == CONST_STRING)
- {
- size_t len = strlen (XSTR (rtl, 0)) + 1;
- tree t = build_string (len, XSTR (rtl, 0));
- tree tlen = size_int (len - 1);
- TREE_TYPE (t)
- = build_array_type (char_type_node, build_index_type (tlen));
- rtl = string_cst_pool_decl (t);
- if (!rtl)
- return false;
- }
- if (GET_CODE (rtl) == SYMBOL_REF && SYMBOL_REF_DECL (rtl))
- {
- decl = SYMBOL_REF_DECL (rtl);
- if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
- {
- ref = lookup_decl_die (decl);
- if (ref && (get_AT (ref, DW_AT_location)
- || get_AT (ref, DW_AT_const_value)))
- {
- loc->dw_loc_opc = DW_OP_GNU_implicit_pointer;
- loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- loc->dw_loc_oprnd1.val_entry = NULL;
- loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
- loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
- loc->dw_loc_next = loc->dw_loc_next->dw_loc_next;
- loc->dw_loc_oprnd2.v.val_int = offset;
- return true;
- }
- }
- }
- return false;
- }
- /* Helper function for resolve_addr, handle one location
- expression, return false if at least one CONST_STRING or SYMBOL_REF in
- the location list couldn't be resolved. */
- static bool
- resolve_addr_in_expr (dw_loc_descr_ref loc)
- {
- dw_loc_descr_ref keep = NULL;
- for (dw_loc_descr_ref prev = NULL; loc; prev = loc, loc = loc->dw_loc_next)
- switch (loc->dw_loc_opc)
- {
- case DW_OP_addr:
- if (!resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr))
- {
- if ((prev == NULL
- || prev->dw_loc_opc == DW_OP_piece
- || prev->dw_loc_opc == DW_OP_bit_piece)
- && loc->dw_loc_next
- && loc->dw_loc_next->dw_loc_opc == DW_OP_stack_value
- && !dwarf_strict
- && optimize_one_addr_into_implicit_ptr (loc))
- break;
- return false;
- }
- break;
- case DW_OP_GNU_addr_index:
- case DW_OP_GNU_const_index:
- if (loc->dw_loc_opc == DW_OP_GNU_addr_index
- || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
- {
- rtx rtl = loc->dw_loc_oprnd1.val_entry->addr.rtl;
- if (!resolve_one_addr (&rtl))
- return false;
- remove_addr_table_entry (loc->dw_loc_oprnd1.val_entry);
- loc->dw_loc_oprnd1.val_entry =
- add_addr_table_entry (rtl, ate_kind_rtx);
- }
- break;
- case DW_OP_const4u:
- case DW_OP_const8u:
- if (loc->dtprel
- && !resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr))
- return false;
- break;
- case DW_OP_plus_uconst:
- if (size_of_loc_descr (loc)
- > size_of_int_loc_descriptor (loc->dw_loc_oprnd1.v.val_unsigned)
- + 1
- && loc->dw_loc_oprnd1.v.val_unsigned > 0)
- {
- dw_loc_descr_ref repl
- = int_loc_descriptor (loc->dw_loc_oprnd1.v.val_unsigned);
- add_loc_descr (&repl, new_loc_descr (DW_OP_plus, 0, 0));
- add_loc_descr (&repl, loc->dw_loc_next);
- *loc = *repl;
- }
- break;
- case DW_OP_implicit_value:
- if (loc->dw_loc_oprnd2.val_class == dw_val_class_addr
- && !resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr))
- return false;
- break;
- case DW_OP_GNU_implicit_pointer:
- case DW_OP_GNU_parameter_ref:
- if (loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
- {
- dw_die_ref ref
- = lookup_decl_die (loc->dw_loc_oprnd1.v.val_decl_ref);
- if (ref == NULL)
- return false;
- loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
- loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
- }
- break;
- case DW_OP_GNU_const_type:
- case DW_OP_GNU_regval_type:
- case DW_OP_GNU_deref_type:
- case DW_OP_GNU_convert:
- case DW_OP_GNU_reinterpret:
- while (loc->dw_loc_next
- && loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_convert)
- {
- dw_die_ref base1, base2;
- unsigned enc1, enc2, size1, size2;
- if (loc->dw_loc_opc == DW_OP_GNU_regval_type
- || loc->dw_loc_opc == DW_OP_GNU_deref_type)
- base1 = loc->dw_loc_oprnd2.v.val_die_ref.die;
- else if (loc->dw_loc_oprnd1.val_class
- == dw_val_class_unsigned_const)
- break;
- else
- base1 = loc->dw_loc_oprnd1.v.val_die_ref.die;
- if (loc->dw_loc_next->dw_loc_oprnd1.val_class
- == dw_val_class_unsigned_const)
- break;
- base2 = loc->dw_loc_next->dw_loc_oprnd1.v.val_die_ref.die;
- gcc_assert (base1->die_tag == DW_TAG_base_type
- && base2->die_tag == DW_TAG_base_type);
- enc1 = get_AT_unsigned (base1, DW_AT_encoding);
- enc2 = get_AT_unsigned (base2, DW_AT_encoding);
- size1 = get_AT_unsigned (base1, DW_AT_byte_size);
- size2 = get_AT_unsigned (base2, DW_AT_byte_size);
- if (size1 == size2
- && (((enc1 == DW_ATE_unsigned || enc1 == DW_ATE_signed)
- && (enc2 == DW_ATE_unsigned || enc2 == DW_ATE_signed)
- && loc != keep)
- || enc1 == enc2))
- {
- /* Optimize away next DW_OP_GNU_convert after
- adjusting LOC's base type die reference. */
- if (loc->dw_loc_opc == DW_OP_GNU_regval_type
- || loc->dw_loc_opc == DW_OP_GNU_deref_type)
- loc->dw_loc_oprnd2.v.val_die_ref.die = base2;
- else
- loc->dw_loc_oprnd1.v.val_die_ref.die = base2;
- loc->dw_loc_next = loc->dw_loc_next->dw_loc_next;
- continue;
- }
- /* Don't change integer DW_OP_GNU_convert after e.g. floating
- point typed stack entry. */
- else if (enc1 != DW_ATE_unsigned && enc1 != DW_ATE_signed)
- keep = loc->dw_loc_next;
- break;
- }
- break;
- default:
- break;
- }
- return true;
- }
- /* Helper function of resolve_addr. DIE had DW_AT_location of
- DW_OP_addr alone, which referred to DECL in DW_OP_addr's operand
- and DW_OP_addr couldn't be resolved. resolve_addr has already
- removed the DW_AT_location attribute. This function attempts to
- add a new DW_AT_location attribute with DW_OP_GNU_implicit_pointer
- to it or DW_AT_const_value attribute, if possible. */
- static void
- optimize_location_into_implicit_ptr (dw_die_ref die, tree decl)
- {
- if (TREE_CODE (decl) != VAR_DECL
- || lookup_decl_die (decl) != die
- || DECL_EXTERNAL (decl)
- || !TREE_STATIC (decl)
- || DECL_INITIAL (decl) == NULL_TREE
- || DECL_P (DECL_INITIAL (decl))
- || get_AT (die, DW_AT_const_value))
- return;
- tree init = DECL_INITIAL (decl);
- HOST_WIDE_INT offset = 0;
- /* For variables that have been optimized away and thus
- don't have a memory location, see if we can emit
- DW_AT_const_value instead. */
- if (tree_add_const_value_attribute (die, init))
- return;
- if (dwarf_strict)
- return;
- /* If init is ADDR_EXPR or POINTER_PLUS_EXPR of ADDR_EXPR,
- and ADDR_EXPR refers to a decl that has DW_AT_location or
- DW_AT_const_value (but isn't addressable, otherwise
- resolving the original DW_OP_addr wouldn't fail), see if
- we can add DW_OP_GNU_implicit_pointer. */
- STRIP_NOPS (init);
- if (TREE_CODE (init) == POINTER_PLUS_EXPR
- && tree_fits_shwi_p (TREE_OPERAND (init, 1)))
- {
- offset = tree_to_shwi (TREE_OPERAND (init, 1));
- init = TREE_OPERAND (init, 0);
- STRIP_NOPS (init);
- }
- if (TREE_CODE (init) != ADDR_EXPR)
- return;
- if ((TREE_CODE (TREE_OPERAND (init, 0)) == STRING_CST
- && !TREE_ASM_WRITTEN (TREE_OPERAND (init, 0)))
- || (TREE_CODE (TREE_OPERAND (init, 0)) == VAR_DECL
- && !DECL_EXTERNAL (TREE_OPERAND (init, 0))
- && TREE_OPERAND (init, 0) != decl))
- {
- dw_die_ref ref;
- dw_loc_descr_ref l;
- if (TREE_CODE (TREE_OPERAND (init, 0)) == STRING_CST)
- {
- rtx rtl = string_cst_pool_decl (TREE_OPERAND (init, 0));
- if (!rtl)
- return;
- decl = SYMBOL_REF_DECL (rtl);
- }
- else
- decl = TREE_OPERAND (init, 0);
- ref = lookup_decl_die (decl);
- if (ref == NULL
- || (!get_AT (ref, DW_AT_location)
- && !get_AT (ref, DW_AT_const_value)))
- return;
- l = new_loc_descr (DW_OP_GNU_implicit_pointer, 0, offset);
- l->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- l->dw_loc_oprnd1.v.val_die_ref.die = ref;
- l->dw_loc_oprnd1.v.val_die_ref.external = 0;
- add_AT_loc (die, DW_AT_location, l);
- }
- }
- /* Resolve DW_OP_addr and DW_AT_const_value CONST_STRING arguments to
- an address in .rodata section if the string literal is emitted there,
- or remove the containing location list or replace DW_AT_const_value
- with DW_AT_location and empty location expression, if it isn't found
- in .rodata. Similarly for SYMBOL_REFs, keep only those that refer
- to something that has been emitted in the current CU. */
- static void
- resolve_addr (dw_die_ref die)
- {
- dw_die_ref c;
- dw_attr_ref a;
- dw_loc_list_ref *curr, *start, loc;
- unsigned ix;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- switch (AT_class (a))
- {
- case dw_val_class_loc_list:
- start = curr = AT_loc_list_ptr (a);
- loc = *curr;
- gcc_assert (loc);
- /* The same list can be referenced more than once. See if we have
- already recorded the result from a previous pass. */
- if (loc->replaced)
- *curr = loc->dw_loc_next;
- else if (!loc->resolved_addr)
- {
- /* As things stand, we do not expect or allow one die to
- reference a suffix of another die's location list chain.
- References must be identical or completely separate.
- There is therefore no need to cache the result of this
- pass on any list other than the first; doing so
- would lead to unnecessary writes. */
- while (*curr)
- {
- gcc_assert (!(*curr)->replaced && !(*curr)->resolved_addr);
- if (!resolve_addr_in_expr ((*curr)->expr))
- {
- dw_loc_list_ref next = (*curr)->dw_loc_next;
- dw_loc_descr_ref l = (*curr)->expr;
- if (next && (*curr)->ll_symbol)
- {
- gcc_assert (!next->ll_symbol);
- next->ll_symbol = (*curr)->ll_symbol;
- }
- if (dwarf_split_debug_info)
- remove_loc_list_addr_table_entries (l);
- *curr = next;
- }
- else
- {
- mark_base_types ((*curr)->expr);
- curr = &(*curr)->dw_loc_next;
- }
- }
- if (loc == *start)
- loc->resolved_addr = 1;
- else
- {
- loc->replaced = 1;
- loc->dw_loc_next = *start;
- }
- }
- if (!*start)
- {
- remove_AT (die, a->dw_attr);
- ix--;
- }
- break;
- case dw_val_class_loc:
- {
- dw_loc_descr_ref l = AT_loc (a);
- /* For -gdwarf-2 don't attempt to optimize
- DW_AT_data_member_location containing
- DW_OP_plus_uconst - older consumers might
- rely on it being that op instead of a more complex,
- but shorter, location description. */
- if ((dwarf_version > 2
- || a->dw_attr != DW_AT_data_member_location
- || l == NULL
- || l->dw_loc_opc != DW_OP_plus_uconst
- || l->dw_loc_next != NULL)
- && !resolve_addr_in_expr (l))
- {
- if (dwarf_split_debug_info)
- remove_loc_list_addr_table_entries (l);
- if (l != NULL
- && l->dw_loc_next == NULL
- && l->dw_loc_opc == DW_OP_addr
- && GET_CODE (l->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF
- && SYMBOL_REF_DECL (l->dw_loc_oprnd1.v.val_addr)
- && a->dw_attr == DW_AT_location)
- {
- tree decl = SYMBOL_REF_DECL (l->dw_loc_oprnd1.v.val_addr);
- remove_AT (die, a->dw_attr);
- ix--;
- optimize_location_into_implicit_ptr (die, decl);
- break;
- }
- remove_AT (die, a->dw_attr);
- ix--;
- }
- else
- mark_base_types (l);
- }
- break;
- case dw_val_class_addr:
- if (a->dw_attr == DW_AT_const_value
- && !resolve_one_addr (&a->dw_attr_val.v.val_addr))
- {
- if (AT_index (a) != NOT_INDEXED)
- remove_addr_table_entry (a->dw_attr_val.val_entry);
- remove_AT (die, a->dw_attr);
- ix--;
- }
- if (die->die_tag == DW_TAG_GNU_call_site
- && a->dw_attr == DW_AT_abstract_origin)
- {
- tree tdecl = SYMBOL_REF_DECL (a->dw_attr_val.v.val_addr);
- dw_die_ref tdie = lookup_decl_die (tdecl);
- dw_die_ref cdie;
- if (tdie == NULL
- && DECL_EXTERNAL (tdecl)
- && DECL_ABSTRACT_ORIGIN (tdecl) == NULL_TREE
- && (cdie = lookup_context_die (DECL_CONTEXT (tdecl))))
- {
- /* Creating a full DIE for tdecl is overly expensive and
- at this point even wrong when in the LTO phase
- as it can end up generating new type DIEs we didn't
- output and thus optimize_external_refs will crash. */
- tdie = new_die (DW_TAG_subprogram, cdie, NULL_TREE);
- add_AT_flag (tdie, DW_AT_external, 1);
- add_AT_flag (tdie, DW_AT_declaration, 1);
- add_linkage_attr (tdie, tdecl);
- add_name_and_src_coords_attributes (tdie, tdecl);
- equate_decl_number_to_die (tdecl, tdie);
- }
- if (tdie)
- {
- a->dw_attr_val.val_class = dw_val_class_die_ref;
- a->dw_attr_val.v.val_die_ref.die = tdie;
- a->dw_attr_val.v.val_die_ref.external = 0;
- }
- else
- {
- if (AT_index (a) != NOT_INDEXED)
- remove_addr_table_entry (a->dw_attr_val.val_entry);
- remove_AT (die, a->dw_attr);
- ix--;
- }
- }
- break;
- default:
- break;
- }
- FOR_EACH_CHILD (die, c, resolve_addr (c));
- }
- /* Helper routines for optimize_location_lists.
- This pass tries to share identical local lists in .debug_loc
- section. */
- /* Iteratively hash operands of LOC opcode into HSTATE. */
- static void
- hash_loc_operands (dw_loc_descr_ref loc, inchash::hash &hstate)
- {
- dw_val_ref val1 = &loc->dw_loc_oprnd1;
- dw_val_ref val2 = &loc->dw_loc_oprnd2;
- switch (loc->dw_loc_opc)
- {
- case DW_OP_const4u:
- case DW_OP_const8u:
- if (loc->dtprel)
- goto hash_addr;
- /* FALLTHRU */
- case DW_OP_const1u:
- case DW_OP_const1s:
- case DW_OP_const2u:
- case DW_OP_const2s:
- case DW_OP_const4s:
- case DW_OP_const8s:
- case DW_OP_constu:
- case DW_OP_consts:
- case DW_OP_pick:
- case DW_OP_plus_uconst:
- case DW_OP_breg0:
- case DW_OP_breg1:
- case DW_OP_breg2:
- case DW_OP_breg3:
- case DW_OP_breg4:
- case DW_OP_breg5:
- case DW_OP_breg6:
- case DW_OP_breg7:
- case DW_OP_breg8:
- case DW_OP_breg9:
- case DW_OP_breg10:
- case DW_OP_breg11:
- case DW_OP_breg12:
- case DW_OP_breg13:
- case DW_OP_breg14:
- case DW_OP_breg15:
- case DW_OP_breg16:
- case DW_OP_breg17:
- case DW_OP_breg18:
- case DW_OP_breg19:
- case DW_OP_breg20:
- case DW_OP_breg21:
- case DW_OP_breg22:
- case DW_OP_breg23:
- case DW_OP_breg24:
- case DW_OP_breg25:
- case DW_OP_breg26:
- case DW_OP_breg27:
- case DW_OP_breg28:
- case DW_OP_breg29:
- case DW_OP_breg30:
- case DW_OP_breg31:
- case DW_OP_regx:
- case DW_OP_fbreg:
- case DW_OP_piece:
- case DW_OP_deref_size:
- case DW_OP_xderef_size:
- hstate.add_object (val1->v.val_int);
- break;
- case DW_OP_skip:
- case DW_OP_bra:
- {
- int offset;
- gcc_assert (val1->val_class == dw_val_class_loc);
- offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3);
- hstate.add_object (offset);
- }
- break;
- case DW_OP_implicit_value:
- hstate.add_object (val1->v.val_unsigned);
- switch (val2->val_class)
- {
- case dw_val_class_const:
- hstate.add_object (val2->v.val_int);
- break;
- case dw_val_class_vec:
- {
- unsigned int elt_size = val2->v.val_vec.elt_size;
- unsigned int len = val2->v.val_vec.length;
- hstate.add_int (elt_size);
- hstate.add_int (len);
- hstate.add (val2->v.val_vec.array, len * elt_size);
- }
- break;
- case dw_val_class_const_double:
- hstate.add_object (val2->v.val_double.low);
- hstate.add_object (val2->v.val_double.high);
- break;
- case dw_val_class_wide_int:
- hstate.add (val2->v.val_wide->get_val (),
- get_full_len (*val2->v.val_wide)
- * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
- break;
- case dw_val_class_addr:
- inchash::add_rtx (val2->v.val_addr, hstate);
- break;
- default:
- gcc_unreachable ();
- }
- break;
- case DW_OP_bregx:
- case DW_OP_bit_piece:
- hstate.add_object (val1->v.val_int);
- hstate.add_object (val2->v.val_int);
- break;
- case DW_OP_addr:
- hash_addr:
- if (loc->dtprel)
- {
- unsigned char dtprel = 0xd1;
- hstate.add_object (dtprel);
- }
- inchash::add_rtx (val1->v.val_addr, hstate);
- break;
- case DW_OP_GNU_addr_index:
- case DW_OP_GNU_const_index:
- {
- if (loc->dtprel)
- {
- unsigned char dtprel = 0xd1;
- hstate.add_object (dtprel);
- }
- inchash::add_rtx (val1->val_entry->addr.rtl, hstate);
- }
- break;
- case DW_OP_GNU_implicit_pointer:
- hstate.add_int (val2->v.val_int);
- break;
- case DW_OP_GNU_entry_value:
- hstate.add_object (val1->v.val_loc);
- break;
- case DW_OP_GNU_regval_type:
- case DW_OP_GNU_deref_type:
- {
- unsigned int byte_size
- = get_AT_unsigned (val2->v.val_die_ref.die, DW_AT_byte_size);
- unsigned int encoding
- = get_AT_unsigned (val2->v.val_die_ref.die, DW_AT_encoding);
- hstate.add_object (val1->v.val_int);
- hstate.add_object (byte_size);
- hstate.add_object (encoding);
- }
- break;
- case DW_OP_GNU_convert:
- case DW_OP_GNU_reinterpret:
- if (val1->val_class == dw_val_class_unsigned_const)
- {
- hstate.add_object (val1->v.val_unsigned);
- break;
- }
- /* FALLTHRU */
- case DW_OP_GNU_const_type:
- {
- unsigned int byte_size
- = get_AT_unsigned (val1->v.val_die_ref.die, DW_AT_byte_size);
- unsigned int encoding
- = get_AT_unsigned (val1->v.val_die_ref.die, DW_AT_encoding);
- hstate.add_object (byte_size);
- hstate.add_object (encoding);
- if (loc->dw_loc_opc != DW_OP_GNU_const_type)
- break;
- hstate.add_object (val2->val_class);
- switch (val2->val_class)
- {
- case dw_val_class_const:
- hstate.add_object (val2->v.val_int);
- break;
- case dw_val_class_vec:
- {
- unsigned int elt_size = val2->v.val_vec.elt_size;
- unsigned int len = val2->v.val_vec.length;
- hstate.add_object (elt_size);
- hstate.add_object (len);
- hstate.add (val2->v.val_vec.array, len * elt_size);
- }
- break;
- case dw_val_class_const_double:
- hstate.add_object (val2->v.val_double.low);
- hstate.add_object (val2->v.val_double.high);
- break;
- case dw_val_class_wide_int:
- hstate.add (val2->v.val_wide->get_val (),
- get_full_len (*val2->v.val_wide)
- * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
- break;
- default:
- gcc_unreachable ();
- }
- }
- break;
- default:
- /* Other codes have no operands. */
- break;
- }
- }
- /* Iteratively hash the whole DWARF location expression LOC into HSTATE. */
- static inline void
- hash_locs (dw_loc_descr_ref loc, inchash::hash &hstate)
- {
- dw_loc_descr_ref l;
- bool sizes_computed = false;
- /* Compute sizes, so that DW_OP_skip/DW_OP_bra can be checksummed. */
- size_of_locs (loc);
- for (l = loc; l != NULL; l = l->dw_loc_next)
- {
- enum dwarf_location_atom opc = l->dw_loc_opc;
- hstate.add_object (opc);
- if ((opc == DW_OP_skip || opc == DW_OP_bra) && !sizes_computed)
- {
- size_of_locs (loc);
- sizes_computed = true;
- }
- hash_loc_operands (l, hstate);
- }
- }
- /* Compute hash of the whole location list LIST_HEAD. */
- static inline void
- hash_loc_list (dw_loc_list_ref list_head)
- {
- dw_loc_list_ref curr = list_head;
- inchash::hash hstate;
- for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
- {
- hstate.add (curr->begin, strlen (curr->begin) + 1);
- hstate.add (curr->end, strlen (curr->end) + 1);
- if (curr->section)
- hstate.add (curr->section, strlen (curr->section) + 1);
- hash_locs (curr->expr, hstate);
- }
- list_head->hash = hstate.end ();
- }
- /* Return true if X and Y opcodes have the same operands. */
- static inline bool
- compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y)
- {
- dw_val_ref valx1 = &x->dw_loc_oprnd1;
- dw_val_ref valx2 = &x->dw_loc_oprnd2;
- dw_val_ref valy1 = &y->dw_loc_oprnd1;
- dw_val_ref valy2 = &y->dw_loc_oprnd2;
- switch (x->dw_loc_opc)
- {
- case DW_OP_const4u:
- case DW_OP_const8u:
- if (x->dtprel)
- goto hash_addr;
- /* FALLTHRU */
- case DW_OP_const1u:
- case DW_OP_const1s:
- case DW_OP_const2u:
- case DW_OP_const2s:
- case DW_OP_const4s:
- case DW_OP_const8s:
- case DW_OP_constu:
- case DW_OP_consts:
- case DW_OP_pick:
- case DW_OP_plus_uconst:
- case DW_OP_breg0:
- case DW_OP_breg1:
- case DW_OP_breg2:
- case DW_OP_breg3:
- case DW_OP_breg4:
- case DW_OP_breg5:
- case DW_OP_breg6:
- case DW_OP_breg7:
- case DW_OP_breg8:
- case DW_OP_breg9:
- case DW_OP_breg10:
- case DW_OP_breg11:
- case DW_OP_breg12:
- case DW_OP_breg13:
- case DW_OP_breg14:
- case DW_OP_breg15:
- case DW_OP_breg16:
- case DW_OP_breg17:
- case DW_OP_breg18:
- case DW_OP_breg19:
- case DW_OP_breg20:
- case DW_OP_breg21:
- case DW_OP_breg22:
- case DW_OP_breg23:
- case DW_OP_breg24:
- case DW_OP_breg25:
- case DW_OP_breg26:
- case DW_OP_breg27:
- case DW_OP_breg28:
- case DW_OP_breg29:
- case DW_OP_breg30:
- case DW_OP_breg31:
- case DW_OP_regx:
- case DW_OP_fbreg:
- case DW_OP_piece:
- case DW_OP_deref_size:
- case DW_OP_xderef_size:
- return valx1->v.val_int == valy1->v.val_int;
- case DW_OP_skip:
- case DW_OP_bra:
- /* If splitting debug info, the use of DW_OP_GNU_addr_index
- can cause irrelevant differences in dw_loc_addr. */
- gcc_assert (valx1->val_class == dw_val_class_loc
- && valy1->val_class == dw_val_class_loc
- && (dwarf_split_debug_info
- || x->dw_loc_addr == y->dw_loc_addr));
- return valx1->v.val_loc->dw_loc_addr == valy1->v.val_loc->dw_loc_addr;
- case DW_OP_implicit_value:
- if (valx1->v.val_unsigned != valy1->v.val_unsigned
- || valx2->val_class != valy2->val_class)
- return false;
- switch (valx2->val_class)
- {
- case dw_val_class_const:
- return valx2->v.val_int == valy2->v.val_int;
- case dw_val_class_vec:
- return valx2->v.val_vec.elt_size == valy2->v.val_vec.elt_size
- && valx2->v.val_vec.length == valy2->v.val_vec.length
- && memcmp (valx2->v.val_vec.array, valy2->v.val_vec.array,
- valx2->v.val_vec.elt_size
- * valx2->v.val_vec.length) == 0;
- case dw_val_class_const_double:
- return valx2->v.val_double.low == valy2->v.val_double.low
- && valx2->v.val_double.high == valy2->v.val_double.high;
- case dw_val_class_wide_int:
- return *valx2->v.val_wide == *valy2->v.val_wide;
- case dw_val_class_addr:
- return rtx_equal_p (valx2->v.val_addr, valy2->v.val_addr);
- default:
- gcc_unreachable ();
- }
- case DW_OP_bregx:
- case DW_OP_bit_piece:
- return valx1->v.val_int == valy1->v.val_int
- && valx2->v.val_int == valy2->v.val_int;
- case DW_OP_addr:
- hash_addr:
- return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr);
- case DW_OP_GNU_addr_index:
- case DW_OP_GNU_const_index:
- {
- rtx ax1 = valx1->val_entry->addr.rtl;
- rtx ay1 = valy1->val_entry->addr.rtl;
- return rtx_equal_p (ax1, ay1);
- }
- case DW_OP_GNU_implicit_pointer:
- return valx1->val_class == dw_val_class_die_ref
- && valx1->val_class == valy1->val_class
- && valx1->v.val_die_ref.die == valy1->v.val_die_ref.die
- && valx2->v.val_int == valy2->v.val_int;
- case DW_OP_GNU_entry_value:
- return compare_loc_operands (valx1->v.val_loc, valy1->v.val_loc);
- case DW_OP_GNU_const_type:
- if (valx1->v.val_die_ref.die != valy1->v.val_die_ref.die
- || valx2->val_class != valy2->val_class)
- return false;
- switch (valx2->val_class)
- {
- case dw_val_class_const:
- return valx2->v.val_int == valy2->v.val_int;
- case dw_val_class_vec:
- return valx2->v.val_vec.elt_size == valy2->v.val_vec.elt_size
- && valx2->v.val_vec.length == valy2->v.val_vec.length
- && memcmp (valx2->v.val_vec.array, valy2->v.val_vec.array,
- valx2->v.val_vec.elt_size
- * valx2->v.val_vec.length) == 0;
- case dw_val_class_const_double:
- return valx2->v.val_double.low == valy2->v.val_double.low
- && valx2->v.val_double.high == valy2->v.val_double.high;
- case dw_val_class_wide_int:
- return *valx2->v.val_wide == *valy2->v.val_wide;
- default:
- gcc_unreachable ();
- }
- case DW_OP_GNU_regval_type:
- case DW_OP_GNU_deref_type:
- return valx1->v.val_int == valy1->v.val_int
- && valx2->v.val_die_ref.die == valy2->v.val_die_ref.die;
- case DW_OP_GNU_convert:
- case DW_OP_GNU_reinterpret:
- if (valx1->val_class != valy1->val_class)
- return false;
- if (valx1->val_class == dw_val_class_unsigned_const)
- return valx1->v.val_unsigned == valy1->v.val_unsigned;
- return valx1->v.val_die_ref.die == valy1->v.val_die_ref.die;
- case DW_OP_GNU_parameter_ref:
- return valx1->val_class == dw_val_class_die_ref
- && valx1->val_class == valy1->val_class
- && valx1->v.val_die_ref.die == valy1->v.val_die_ref.die;
- default:
- /* Other codes have no operands. */
- return true;
- }
- }
- /* Return true if DWARF location expressions X and Y are the same. */
- static inline bool
- compare_locs (dw_loc_descr_ref x, dw_loc_descr_ref y)
- {
- for (; x != NULL && y != NULL; x = x->dw_loc_next, y = y->dw_loc_next)
- if (x->dw_loc_opc != y->dw_loc_opc
- || x->dtprel != y->dtprel
- || !compare_loc_operands (x, y))
- break;
- return x == NULL && y == NULL;
- }
- /* Hashtable helpers. */
- struct loc_list_hasher : typed_noop_remove <dw_loc_list_struct>
- {
- typedef dw_loc_list_struct value_type;
- typedef dw_loc_list_struct compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
- };
- /* Return precomputed hash of location list X. */
- inline hashval_t
- loc_list_hasher::hash (const value_type *x)
- {
- return x->hash;
- }
- /* Return true if location lists A and B are the same. */
- inline bool
- loc_list_hasher::equal (const value_type *a, const compare_type *b)
- {
- if (a == b)
- return 1;
- if (a->hash != b->hash)
- return 0;
- for (; a != NULL && b != NULL; a = a->dw_loc_next, b = b->dw_loc_next)
- if (strcmp (a->begin, b->begin) != 0
- || strcmp (a->end, b->end) != 0
- || (a->section == NULL) != (b->section == NULL)
- || (a->section && strcmp (a->section, b->section) != 0)
- || !compare_locs (a->expr, b->expr))
- break;
- return a == NULL && b == NULL;
- }
- typedef hash_table<loc_list_hasher> loc_list_hash_type;
- /* Recursively optimize location lists referenced from DIE
- children and share them whenever possible. */
- static void
- optimize_location_lists_1 (dw_die_ref die, loc_list_hash_type *htab)
- {
- dw_die_ref c;
- dw_attr_ref a;
- unsigned ix;
- dw_loc_list_struct **slot;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- if (AT_class (a) == dw_val_class_loc_list)
- {
- dw_loc_list_ref list = AT_loc_list (a);
- /* TODO: perform some optimizations here, before hashing
- it and storing into the hash table. */
- hash_loc_list (list);
- slot = htab->find_slot_with_hash (list, list->hash, INSERT);
- if (*slot == NULL)
- *slot = list;
- else
- a->dw_attr_val.v.val_loc_list = *slot;
- }
- FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab));
- }
- /* Recursively assign each location list a unique index into the debug_addr
- section. */
- static void
- index_location_lists (dw_die_ref die)
- {
- dw_die_ref c;
- dw_attr_ref a;
- unsigned ix;
- FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
- if (AT_class (a) == dw_val_class_loc_list)
- {
- dw_loc_list_ref list = AT_loc_list (a);
- dw_loc_list_ref curr;
- for (curr = list; curr != NULL; curr = curr->dw_loc_next)
- {
- /* Don't index an entry that has already been indexed
- or won't be output. */
- if (curr->begin_entry != NULL
- || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
- continue;
- curr->begin_entry
- = add_addr_table_entry (xstrdup (curr->begin),
- ate_kind_label);
- }
- }
- FOR_EACH_CHILD (die, c, index_location_lists (c));
- }
- /* Optimize location lists referenced from DIE
- children and share them whenever possible. */
- static void
- optimize_location_lists (dw_die_ref die)
- {
- loc_list_hash_type htab (500);
- optimize_location_lists_1 (die, &htab);
- }
- /* Output stuff that dwarf requires at the end of every file,
- and generate the DWARF-2 debugging info. */
- static void
- dwarf2out_finish (const char *filename)
- {
- limbo_die_node *node, *next_node;
- comdat_type_node *ctnode;
- unsigned int i;
- dw_die_ref main_comp_unit_die;
- /* PCH might result in DW_AT_producer string being restored from the
- header compilation, so always fill it with empty string initially
- and overwrite only here. */
- dw_attr_ref producer = get_AT (comp_unit_die (), DW_AT_producer);
- producer_string = gen_producer_string ();
- producer->dw_attr_val.v.val_str->refcount--;
- producer->dw_attr_val.v.val_str = find_AT_string (producer_string);
- gen_scheduled_generic_parms_dies ();
- gen_remaining_tmpl_value_param_die_attribute ();
- /* Add the name for the main input file now. We delayed this from
- dwarf2out_init to avoid complications with PCH.
- For LTO produced units use a fixed artificial name to avoid
- leaking tempfile names into the dwarf. */
- if (!in_lto_p)
- add_name_attribute (comp_unit_die (), remap_debug_filename (filename));
- else
- add_name_attribute (comp_unit_die (), "<artificial>");
- if (!IS_ABSOLUTE_PATH (filename) || targetm.force_at_comp_dir)
- add_comp_dir_attribute (comp_unit_die ());
- else if (get_AT (comp_unit_die (), DW_AT_comp_dir) == NULL)
- {
- bool p = false;
- file_table->traverse<bool *, file_table_relative_p> (&p);
- if (p)
- add_comp_dir_attribute (comp_unit_die ());
- }
- if (deferred_locations_list)
- for (i = 0; i < deferred_locations_list->length (); i++)
- {
- add_location_or_const_value_attribute (
- (*deferred_locations_list)[i].die,
- (*deferred_locations_list)[i].variable,
- false,
- DW_AT_location);
- }
- /* Traverse the limbo die list, and add parent/child links. The only
- dies without parents that should be here are concrete instances of
- inline functions, and the comp_unit_die. We can ignore the comp_unit_die.
- For concrete instances, we can get the parent die from the abstract
- instance. */
- for (node = limbo_die_list; node; node = next_node)
- {
- dw_die_ref die = node->die;
- next_node = node->next;
- if (die->die_parent == NULL)
- {
- dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
- if (origin && origin->die_parent)
- add_child_die (origin->die_parent, die);
- else if (is_cu_die (die))
- ;
- else if (seen_error ())
- /* It's OK to be confused by errors in the input. */
- add_child_die (comp_unit_die (), die);
- else
- {
- /* In certain situations, the lexical block containing a
- nested function can be optimized away, which results
- in the nested function die being orphaned. Likewise
- with the return type of that nested function. Force
- this to be a child of the containing function.
- It may happen that even the containing function got fully
- inlined and optimized out. In that case we are lost and
- assign the empty child. This should not be big issue as
- the function is likely unreachable too. */
- gcc_assert (node->created_for);
- if (DECL_P (node->created_for))
- origin = get_context_die (DECL_CONTEXT (node->created_for));
- else if (TYPE_P (node->created_for))
- origin = scope_die_for (node->created_for, comp_unit_die ());
- else
- origin = comp_unit_die ();
- add_child_die (origin, die);
- }
- }
- }
- limbo_die_list = NULL;
- #if ENABLE_ASSERT_CHECKING
- {
- dw_die_ref die = comp_unit_die (), c;
- FOR_EACH_CHILD (die, c, gcc_assert (! c->die_mark));
- }
- #endif
- resolve_addr (comp_unit_die ());
- move_marked_base_types ();
- for (node = deferred_asm_name; node; node = node->next)
- {
- tree decl = node->created_for;
- /* When generating LTO bytecode we can not generate new assembler
- names at this point and all important decls got theirs via
- free-lang-data. */
- if (((!flag_generate_lto && !flag_generate_offload)
- || DECL_ASSEMBLER_NAME_SET_P (decl))
- && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
- {
- add_linkage_attr (node->die, decl);
- move_linkage_attr (node->die);
- }
- }
- deferred_asm_name = NULL;
- /* Walk through the list of incomplete types again, trying once more to
- emit full debugging info for them. */
- retry_incomplete_types ();
- if (flag_eliminate_unused_debug_types)
- prune_unused_types ();
- /* Generate separate COMDAT sections for type DIEs. */
- if (use_debug_types)
- {
- break_out_comdat_types (comp_unit_die ());
- /* Each new type_unit DIE was added to the limbo die list when created.
- Since these have all been added to comdat_type_list, clear the
- limbo die list. */
- limbo_die_list = NULL;
- /* For each new comdat type unit, copy declarations for incomplete
- types to make the new unit self-contained (i.e., no direct
- references to the main compile unit). */
- for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
- copy_decls_for_unworthy_types (ctnode->root_die);
- copy_decls_for_unworthy_types (comp_unit_die ());
- /* In the process of copying declarations from one unit to another,
- we may have left some declarations behind that are no longer
- referenced. Prune them. */
- prune_unused_types ();
- }
- /* Generate separate CUs for each of the include files we've seen.
- They will go into limbo_die_list. */
- if (flag_eliminate_dwarf2_dups)
- break_out_includes (comp_unit_die ());
- /* Traverse the DIE's and add add sibling attributes to those DIE's
- that have children. */
- add_sibling_attributes (comp_unit_die ());
- for (node = limbo_die_list; node; node = node->next)
- add_sibling_attributes (node->die);
- for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
- add_sibling_attributes (ctnode->root_die);
- /* When splitting DWARF info, we put some attributes in the
- skeleton compile_unit DIE that remains in the .o, while
- most attributes go in the DWO compile_unit_die. */
- if (dwarf_split_debug_info)
- main_comp_unit_die = gen_compile_unit_die (NULL);
- else
- main_comp_unit_die = comp_unit_die ();
- /* Output a terminator label for the .text section. */
- switch_to_section (text_section);
- targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
- if (cold_text_section)
- {
- switch_to_section (cold_text_section);
- targetm.asm_out.internal_label (asm_out_file, COLD_END_LABEL, 0);
- }
- /* We can only use the low/high_pc attributes if all of the code was
- in .text. */
- if (!have_multiple_function_sections
- || (dwarf_version < 3 && dwarf_strict))
- {
- /* Don't add if the CU has no associated code. */
- if (text_section_used)
- add_AT_low_high_pc (main_comp_unit_die, text_section_label,
- text_end_label, true);
- }
- else
- {
- unsigned fde_idx;
- dw_fde_ref fde;
- bool range_list_added = false;
- if (text_section_used)
- add_ranges_by_labels (main_comp_unit_die, text_section_label,
- text_end_label, &range_list_added, true);
- if (cold_text_section_used)
- add_ranges_by_labels (main_comp_unit_die, cold_text_section_label,
- cold_end_label, &range_list_added, true);
- FOR_EACH_VEC_ELT (*fde_vec, fde_idx, fde)
- {
- if (DECL_IGNORED_P (fde->decl))
- continue;
- if (!fde->in_std_section)
- add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_begin,
- fde->dw_fde_end, &range_list_added,
- true);
- if (fde->dw_fde_second_begin && !fde->second_in_std_section)
- add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_second_begin,
- fde->dw_fde_second_end, &range_list_added,
- true);
- }
- if (range_list_added)
- {
- /* We need to give .debug_loc and .debug_ranges an appropriate
- "base address". Use zero so that these addresses become
- absolute. Historically, we've emitted the unexpected
- DW_AT_entry_pc instead of DW_AT_low_pc for this purpose.
- Emit both to give time for other tools to adapt. */
- add_AT_addr (main_comp_unit_die, DW_AT_low_pc, const0_rtx, true);
- if (! dwarf_strict && dwarf_version < 4)
- add_AT_addr (main_comp_unit_die, DW_AT_entry_pc, const0_rtx, true);
- add_ranges (NULL);
- }
- }
- if (debug_info_level >= DINFO_LEVEL_TERSE)
- add_AT_lineptr (main_comp_unit_die, DW_AT_stmt_list,
- debug_line_section_label);
- if (have_macinfo)
- add_AT_macptr (comp_unit_die (),
- dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
- macinfo_section_label);
- if (dwarf_split_debug_info)
- {
- /* optimize_location_lists calculates the size of the lists,
- so index them first, and assign indices to the entries.
- Although optimize_location_lists will remove entries from
- the table, it only does so for duplicates, and therefore
- only reduces ref_counts to 1. */
- index_location_lists (comp_unit_die ());
- if (addr_index_table != NULL)
- {
- unsigned int index = 0;
- addr_index_table
- ->traverse_noresize<unsigned int *, index_addr_table_entry>
- (&index);
- }
- }
- if (have_location_lists)
- optimize_location_lists (comp_unit_die ());
- save_macinfo_strings ();
- if (dwarf_split_debug_info)
- {
- unsigned int index = 0;
- /* Add attributes common to skeleton compile_units and
- type_units. Because these attributes include strings, it
- must be done before freezing the string table. Top-level
- skeleton die attrs are added when the skeleton type unit is
- created, so ensure it is created by this point. */
- add_top_level_skeleton_die_attrs (main_comp_unit_die);
- debug_str_hash->traverse_noresize<unsigned int *, index_string> (&index);
- }
- /* Output all of the compilation units. We put the main one last so that
- the offsets are available to output_pubnames. */
- for (node = limbo_die_list; node; node = node->next)
- output_comp_unit (node->die, 0);
- hash_table<comdat_type_hasher> comdat_type_table (100);
- for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
- {
- comdat_type_node **slot = comdat_type_table.find_slot (ctnode, INSERT);
- /* Don't output duplicate types. */
- if (*slot != HTAB_EMPTY_ENTRY)
- continue;
- /* Add a pointer to the line table for the main compilation unit
- so that the debugger can make sense of DW_AT_decl_file
- attributes. */
- if (debug_info_level >= DINFO_LEVEL_TERSE)
- add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
- (!dwarf_split_debug_info
- ? debug_line_section_label
- : debug_skeleton_line_section_label));
- output_comdat_type_unit (ctnode);
- *slot = ctnode;
- }
- /* The AT_pubnames attribute needs to go in all skeleton dies, including
- both the main_cu and all skeleton TUs. Making this call unconditional
- would end up either adding a second copy of the AT_pubnames attribute, or
- requiring a special case in add_top_level_skeleton_die_attrs. */
- if (!dwarf_split_debug_info)
- add_AT_pubnames (comp_unit_die ());
- if (dwarf_split_debug_info)
- {
- int mark;
- unsigned char checksum[16];
- struct md5_ctx ctx;
- /* Compute a checksum of the comp_unit to use as the dwo_id. */
- md5_init_ctx (&ctx);
- mark = 0;
- die_checksum (comp_unit_die (), &ctx, &mark);
- unmark_all_dies (comp_unit_die ());
- md5_finish_ctx (&ctx, checksum);
- /* Use the first 8 bytes of the checksum as the dwo_id,
- and add it to both comp-unit DIEs. */
- add_AT_data8 (main_comp_unit_die, DW_AT_GNU_dwo_id, checksum);
- add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, checksum);
- /* Add the base offset of the ranges table to the skeleton
- comp-unit DIE. */
- if (ranges_table_in_use)
- add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base,
- ranges_section_label);
- switch_to_section (debug_addr_section);
- ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label);
- output_addr_table ();
- }
- /* Output the main compilation unit if non-empty or if .debug_macinfo
- or .debug_macro will be emitted. */
- output_comp_unit (comp_unit_die (), have_macinfo);
- if (dwarf_split_debug_info && info_section_emitted)
- output_skeleton_debug_sections (main_comp_unit_die);
- /* Output the abbreviation table. */
- if (abbrev_die_table_in_use != 1)
- {
- switch_to_section (debug_abbrev_section);
- ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
- output_abbrev_section ();
- }
- /* Output location list section if necessary. */
- if (have_location_lists)
- {
- /* Output the location lists info. */
- switch_to_section (debug_loc_section);
- ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
- output_location_lists (comp_unit_die ());
- }
- output_pubtables ();
- /* Output the address range information if a CU (.debug_info section)
- was emitted. We output an empty table even if we had no functions
- to put in it. This because the consumer has no way to tell the
- difference between an empty table that we omitted and failure to
- generate a table that would have contained data. */
- if (info_section_emitted)
- {
- unsigned long aranges_length = size_of_aranges ();
- switch_to_section (debug_aranges_section);
- output_aranges (aranges_length);
- }
- /* Output ranges section if necessary. */
- if (ranges_table_in_use)
- {
- switch_to_section (debug_ranges_section);
- ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label);
- output_ranges ();
- }
- /* Have to end the macro section. */
- if (have_macinfo)
- {
- switch_to_section (debug_macinfo_section);
- ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
- output_macinfo ();
- dw2_asm_output_data (1, 0, "End compilation unit");
- }
- /* Output the source line correspondence table. We must do this
- even if there is no line information. Otherwise, on an empty
- translation unit, we will generate a present, but empty,
- .debug_info section. IRIX 6.5 `nm' will then complain when
- examining the file. This is done late so that any filenames
- used by the debug_info section are marked as 'used'. */
- switch_to_section (debug_line_section);
- ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
- if (! DWARF2_ASM_LINE_DEBUG_INFO)
- output_line_info (false);
- if (dwarf_split_debug_info && info_section_emitted)
- {
- switch_to_section (debug_skeleton_line_section);
- ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
- output_line_info (true);
- }
- /* If we emitted any indirect strings, output the string table too. */
- if (debug_str_hash || skeleton_debug_str_hash)
- output_indirect_strings ();
- }
- /* Reset all state within dwarf2out.c so that we can rerun the compiler
- within the same process. For use by toplev::finalize. */
- void
- dwarf2out_c_finalize (void)
- {
- last_var_location_insn = NULL;
- cached_next_real_insn = NULL;
- used_rtx_array = NULL;
- incomplete_types = NULL;
- decl_scope_table = NULL;
- debug_info_section = NULL;
- debug_skeleton_info_section = NULL;
- debug_abbrev_section = NULL;
- debug_skeleton_abbrev_section = NULL;
- debug_aranges_section = NULL;
- debug_addr_section = NULL;
- debug_macinfo_section = NULL;
- debug_line_section = NULL;
- debug_skeleton_line_section = NULL;
- debug_loc_section = NULL;
- debug_pubnames_section = NULL;
- debug_pubtypes_section = NULL;
- debug_str_section = NULL;
- debug_str_dwo_section = NULL;
- debug_str_offsets_section = NULL;
- debug_ranges_section = NULL;
- debug_frame_section = NULL;
- fde_vec = NULL;
- debug_str_hash = NULL;
- skeleton_debug_str_hash = NULL;
- dw2_string_counter = 0;
- have_multiple_function_sections = false;
- text_section_used = false;
- cold_text_section_used = false;
- cold_text_section = NULL;
- current_unit_personality = NULL;
- deferred_locations_list = NULL;
- next_die_offset = 0;
- single_comp_unit_die = NULL;
- comdat_type_list = NULL;
- limbo_die_list = NULL;
- deferred_asm_name = NULL;
- file_table = NULL;
- decl_die_table = NULL;
- common_block_die_table = NULL;
- decl_loc_table = NULL;
- call_arg_locations = NULL;
- call_arg_loc_last = NULL;
- call_site_count = -1;
- tail_call_site_count = -1;
- //block_map = NULL;
- cached_dw_loc_list_table = NULL;
- abbrev_die_table = NULL;
- abbrev_die_table_allocated = 0;
- abbrev_die_table_in_use = 0;
- line_info_label_num = 0;
- cur_line_info_table = NULL;
- text_section_line_info = NULL;
- cold_text_section_line_info = NULL;
- separate_line_info = NULL;
- info_section_emitted = false;
- pubname_table = NULL;
- pubtype_table = NULL;
- macinfo_table = NULL;
- ranges_table = NULL;
- ranges_table_allocated = 0;
- ranges_table_in_use = 0;
- ranges_by_label = 0;
- ranges_by_label_allocated = 0;
- ranges_by_label_in_use = 0;
- have_location_lists = false;
- loclabel_num = 0;
- poc_label_num = 0;
- last_emitted_file = NULL;
- label_num = 0;
- file_table_last_lookup = NULL;
- tmpl_value_parm_die_table = NULL;
- generic_type_instances = NULL;
- frame_pointer_fb_offset = 0;
- frame_pointer_fb_offset_valid = false;
- base_types.release ();
- XDELETEVEC (producer_string);
- producer_string = NULL;
- }
- #include "gt-dwarf2out.h"
|