123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959 |
- /* Common target dependent code for GDB on ARM systems.
- Copyright (C) 1988-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program 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 of the License, or
- (at your option) any later version.
- This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include <ctype.h> /* XXX for isupper (). */
- #include "frame.h"
- #include "inferior.h"
- #include "infrun.h"
- #include "gdbcmd.h"
- #include "gdbcore.h"
- #include "dis-asm.h" /* For register styles. */
- #include "disasm.h"
- #include "regcache.h"
- #include "reggroups.h"
- #include "target-float.h"
- #include "value.h"
- #include "arch-utils.h"
- #include "osabi.h"
- #include "frame-unwind.h"
- #include "frame-base.h"
- #include "trad-frame.h"
- #include "objfiles.h"
- #include "dwarf2.h"
- #include "dwarf2/frame.h"
- #include "gdbtypes.h"
- #include "prologue-value.h"
- #include "remote.h"
- #include "target-descriptions.h"
- #include "user-regs.h"
- #include "observable.h"
- #include "count-one-bits.h"
- #include "arch/arm.h"
- #include "arch/arm-get-next-pcs.h"
- #include "arm-tdep.h"
- #include "gdb/sim-arm.h"
- #include "elf-bfd.h"
- #include "coff/internal.h"
- #include "elf/arm.h"
- #include "record.h"
- #include "record-full.h"
- #include <algorithm>
- #include "producer.h"
- #if GDB_SELF_TEST
- #include "gdbsupport/selftest.h"
- #endif
- static bool arm_debug;
- /* Print an "arm" debug statement. */
- #define arm_debug_printf(fmt, ...) \
- debug_prefixed_printf_cond (arm_debug, "arm", fmt, ##__VA_ARGS__)
- /* Macros for setting and testing a bit in a minimal symbol that marks
- it as Thumb function. The MSB of the minimal symbol's "info" field
- is used for this purpose.
- MSYMBOL_SET_SPECIAL Actually sets the "special" bit.
- MSYMBOL_IS_SPECIAL Tests the "special" bit in a minimal symbol. */
- #define MSYMBOL_SET_SPECIAL(msym) \
- MSYMBOL_TARGET_FLAG_1 (msym) = 1
- #define MSYMBOL_IS_SPECIAL(msym) \
- MSYMBOL_TARGET_FLAG_1 (msym)
- struct arm_mapping_symbol
- {
- CORE_ADDR value;
- char type;
- bool operator< (const arm_mapping_symbol &other) const
- { return this->value < other.value; }
- };
- typedef std::vector<arm_mapping_symbol> arm_mapping_symbol_vec;
- struct arm_per_bfd
- {
- explicit arm_per_bfd (size_t num_sections)
- : section_maps (new arm_mapping_symbol_vec[num_sections]),
- section_maps_sorted (new bool[num_sections] ())
- {}
- DISABLE_COPY_AND_ASSIGN (arm_per_bfd);
- /* Information about mapping symbols ($a, $d, $t) in the objfile.
- The format is an array of vectors of arm_mapping_symbols, there is one
- vector for each section of the objfile (the array is index by BFD section
- index).
- For each section, the vector of arm_mapping_symbol is sorted by
- symbol value (address). */
- std::unique_ptr<arm_mapping_symbol_vec[]> section_maps;
- /* For each corresponding element of section_maps above, is this vector
- sorted. */
- std::unique_ptr<bool[]> section_maps_sorted;
- };
- /* Per-bfd data used for mapping symbols. */
- static bfd_key<arm_per_bfd> arm_bfd_data_key;
- /* The list of available "set arm ..." and "show arm ..." commands. */
- static struct cmd_list_element *setarmcmdlist = NULL;
- static struct cmd_list_element *showarmcmdlist = NULL;
- /* The type of floating-point to use. Keep this in sync with enum
- arm_float_model, and the help string in _initialize_arm_tdep. */
- static const char *const fp_model_strings[] =
- {
- "auto",
- "softfpa",
- "fpa",
- "softvfp",
- "vfp",
- NULL
- };
- /* A variable that can be configured by the user. */
- static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO;
- static const char *current_fp_model = "auto";
- /* The ABI to use. Keep this in sync with arm_abi_kind. */
- static const char *const arm_abi_strings[] =
- {
- "auto",
- "APCS",
- "AAPCS",
- NULL
- };
- /* A variable that can be configured by the user. */
- static enum arm_abi_kind arm_abi_global = ARM_ABI_AUTO;
- static const char *arm_abi_string = "auto";
- /* The execution mode to assume. */
- static const char *const arm_mode_strings[] =
- {
- "auto",
- "arm",
- "thumb",
- NULL
- };
- static const char *arm_fallback_mode_string = "auto";
- static const char *arm_force_mode_string = "auto";
- /* The standard register names, and all the valid aliases for them. Note
- that `fp', `sp' and `pc' are not added in this alias list, because they
- have been added as builtin user registers in
- std-regs.c:_initialize_frame_reg. */
- static const struct
- {
- const char *name;
- int regnum;
- } arm_register_aliases[] = {
- /* Basic register numbers. */
- { "r0", 0 },
- { "r1", 1 },
- { "r2", 2 },
- { "r3", 3 },
- { "r4", 4 },
- { "r5", 5 },
- { "r6", 6 },
- { "r7", 7 },
- { "r8", 8 },
- { "r9", 9 },
- { "r10", 10 },
- { "r11", 11 },
- { "r12", 12 },
- { "r13", 13 },
- { "r14", 14 },
- { "r15", 15 },
- /* Synonyms (argument and variable registers). */
- { "a1", 0 },
- { "a2", 1 },
- { "a3", 2 },
- { "a4", 3 },
- { "v1", 4 },
- { "v2", 5 },
- { "v3", 6 },
- { "v4", 7 },
- { "v5", 8 },
- { "v6", 9 },
- { "v7", 10 },
- { "v8", 11 },
- /* Other platform-specific names for r9. */
- { "sb", 9 },
- { "tr", 9 },
- /* Special names. */
- { "ip", 12 },
- { "lr", 14 },
- /* Names used by GCC (not listed in the ARM EABI). */
- { "sl", 10 },
- /* A special name from the older ATPCS. */
- { "wr", 7 },
- };
- static const char *const arm_register_names[] =
- {"r0", "r1", "r2", "r3", /* 0 1 2 3 */
- "r4", "r5", "r6", "r7", /* 4 5 6 7 */
- "r8", "r9", "r10", "r11", /* 8 9 10 11 */
- "r12", "sp", "lr", "pc", /* 12 13 14 15 */
- "f0", "f1", "f2", "f3", /* 16 17 18 19 */
- "f4", "f5", "f6", "f7", /* 20 21 22 23 */
- "fps", "cpsr" }; /* 24 25 */
- /* Holds the current set of options to be passed to the disassembler. */
- static char *arm_disassembler_options;
- /* Valid register name styles. */
- static const char **valid_disassembly_styles;
- /* Disassembly style to use. Default to "std" register names. */
- static const char *disassembly_style;
- /* All possible arm target descriptors. */
- static struct target_desc *tdesc_arm_list[ARM_FP_TYPE_INVALID];
- static struct target_desc *tdesc_arm_mprofile_list[ARM_M_TYPE_INVALID];
- /* This is used to keep the bfd arch_info in sync with the disassembly
- style. */
- static void set_disassembly_style_sfunc (const char *, int,
- struct cmd_list_element *);
- static void show_disassembly_style_sfunc (struct ui_file *, int,
- struct cmd_list_element *,
- const char *);
- static enum register_status arm_neon_quad_read (struct gdbarch *gdbarch,
- readable_regcache *regcache,
- int regnum, gdb_byte *buf);
- static void arm_neon_quad_write (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int regnum, const gdb_byte *buf);
- static CORE_ADDR
- arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self);
- /* get_next_pcs operations. */
- static struct arm_get_next_pcs_ops arm_get_next_pcs_ops = {
- arm_get_next_pcs_read_memory_unsigned_integer,
- arm_get_next_pcs_syscall_next_pc,
- arm_get_next_pcs_addr_bits_remove,
- arm_get_next_pcs_is_thumb,
- NULL,
- };
- struct arm_prologue_cache
- {
- /* The stack pointer at the time this frame was created; i.e. the
- caller's stack pointer when this function was called. It is used
- to identify this frame. */
- CORE_ADDR prev_sp;
- /* The frame base for this frame is just prev_sp - frame size.
- FRAMESIZE is the distance from the frame pointer to the
- initial stack pointer. */
- int framesize;
- /* The register used to hold the frame pointer for this frame. */
- int framereg;
- /* True if the return address is signed, false otherwise. */
- gdb::optional<bool> ra_signed_state;
- /* Saved register offsets. */
- trad_frame_saved_reg *saved_regs;
- };
- namespace {
- /* Abstract class to read ARM instructions from memory. */
- class arm_instruction_reader
- {
- public:
- /* Read a 4 bytes instruction from memory using the BYTE_ORDER endianness. */
- virtual uint32_t read (CORE_ADDR memaddr, bfd_endian byte_order) const = 0;
- };
- /* Read instructions from target memory. */
- class target_arm_instruction_reader : public arm_instruction_reader
- {
- public:
- uint32_t read (CORE_ADDR memaddr, bfd_endian byte_order) const override
- {
- return read_code_unsigned_integer (memaddr, 4, byte_order);
- }
- };
- } /* namespace */
- static CORE_ADDR arm_analyze_prologue
- (struct gdbarch *gdbarch, CORE_ADDR prologue_start, CORE_ADDR prologue_end,
- struct arm_prologue_cache *cache, const arm_instruction_reader &insn_reader);
- /* Architecture version for displaced stepping. This effects the behaviour of
- certain instructions, and really should not be hard-wired. */
- #define DISPLACED_STEPPING_ARCH_VERSION 5
- /* See arm-tdep.h. */
- bool arm_apcs_32 = true;
- /* Return the bit mask in ARM_PS_REGNUM that indicates Thumb mode. */
- int
- arm_psr_thumb_bit (struct gdbarch *gdbarch)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->is_m)
- return XPSR_T;
- else
- return CPSR_T;
- }
- /* Determine if the processor is currently executing in Thumb mode. */
- int
- arm_is_thumb (struct regcache *regcache)
- {
- ULONGEST cpsr;
- ULONGEST t_bit = arm_psr_thumb_bit (regcache->arch ());
- cpsr = regcache_raw_get_unsigned (regcache, ARM_PS_REGNUM);
- return (cpsr & t_bit) != 0;
- }
- /* Determine if FRAME is executing in Thumb mode. */
- int
- arm_frame_is_thumb (struct frame_info *frame)
- {
- CORE_ADDR cpsr;
- ULONGEST t_bit = arm_psr_thumb_bit (get_frame_arch (frame));
- /* Every ARM frame unwinder can unwind the T bit of the CPSR, either
- directly (from a signal frame or dummy frame) or by interpreting
- the saved LR (from a prologue or DWARF frame). So consult it and
- trust the unwinders. */
- cpsr = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
- return (cpsr & t_bit) != 0;
- }
- /* Search for the mapping symbol covering MEMADDR. If one is found,
- return its type. Otherwise, return 0. If START is non-NULL,
- set *START to the location of the mapping symbol. */
- static char
- arm_find_mapping_symbol (CORE_ADDR memaddr, CORE_ADDR *start)
- {
- struct obj_section *sec;
- /* If there are mapping symbols, consult them. */
- sec = find_pc_section (memaddr);
- if (sec != NULL)
- {
- arm_per_bfd *data = arm_bfd_data_key.get (sec->objfile->obfd);
- if (data != NULL)
- {
- unsigned int section_idx = sec->the_bfd_section->index;
- arm_mapping_symbol_vec &map
- = data->section_maps[section_idx];
- /* Sort the vector on first use. */
- if (!data->section_maps_sorted[section_idx])
- {
- std::sort (map.begin (), map.end ());
- data->section_maps_sorted[section_idx] = true;
- }
- arm_mapping_symbol map_key = { memaddr - sec->addr (), 0 };
- arm_mapping_symbol_vec::const_iterator it
- = std::lower_bound (map.begin (), map.end (), map_key);
- /* std::lower_bound finds the earliest ordered insertion
- point. If the symbol at this position starts at this exact
- address, we use that; otherwise, the preceding
- mapping symbol covers this address. */
- if (it < map.end ())
- {
- if (it->value == map_key.value)
- {
- if (start)
- *start = it->value + sec->addr ();
- return it->type;
- }
- }
- if (it > map.begin ())
- {
- arm_mapping_symbol_vec::const_iterator prev_it
- = it - 1;
- if (start)
- *start = prev_it->value + sec->addr ();
- return prev_it->type;
- }
- }
- }
- return 0;
- }
- /* Determine if the program counter specified in MEMADDR is in a Thumb
- function. This function should be called for addresses unrelated to
- any executing frame; otherwise, prefer arm_frame_is_thumb. */
- int
- arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
- {
- struct bound_minimal_symbol sym;
- char type;
- arm_displaced_step_copy_insn_closure *dsc = nullptr;
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (gdbarch_displaced_step_copy_insn_closure_by_addr_p (gdbarch))
- dsc = ((arm_displaced_step_copy_insn_closure * )
- gdbarch_displaced_step_copy_insn_closure_by_addr
- (gdbarch, current_inferior (), memaddr));
- /* If checking the mode of displaced instruction in copy area, the mode
- should be determined by instruction on the original address. */
- if (dsc)
- {
- displaced_debug_printf ("check mode of %.8lx instead of %.8lx",
- (unsigned long) dsc->insn_addr,
- (unsigned long) memaddr);
- memaddr = dsc->insn_addr;
- }
- /* If bit 0 of the address is set, assume this is a Thumb address. */
- if (IS_THUMB_ADDR (memaddr))
- return 1;
- /* If the user wants to override the symbol table, let him. */
- if (strcmp (arm_force_mode_string, "arm") == 0)
- return 0;
- if (strcmp (arm_force_mode_string, "thumb") == 0)
- return 1;
- /* ARM v6-M and v7-M are always in Thumb mode. */
- if (tdep->is_m)
- return 1;
- /* If there are mapping symbols, consult them. */
- type = arm_find_mapping_symbol (memaddr, NULL);
- if (type)
- return type == 't';
- /* Thumb functions have a "special" bit set in minimal symbols. */
- sym = lookup_minimal_symbol_by_pc (memaddr);
- if (sym.minsym)
- return (MSYMBOL_IS_SPECIAL (sym.minsym));
- /* If the user wants to override the fallback mode, let them. */
- if (strcmp (arm_fallback_mode_string, "arm") == 0)
- return 0;
- if (strcmp (arm_fallback_mode_string, "thumb") == 0)
- return 1;
- /* If we couldn't find any symbol, but we're talking to a running
- target, then trust the current value of $cpsr. This lets
- "display/i $pc" always show the correct mode (though if there is
- a symbol table we will not reach here, so it still may not be
- displayed in the mode it will be executed). */
- if (target_has_registers ())
- return arm_frame_is_thumb (get_current_frame ());
- /* Otherwise we're out of luck; we assume ARM. */
- return 0;
- }
- /* Determine if the address specified equals any of these magic return
- values, called EXC_RETURN, defined by the ARM v6-M, v7-M and v8-M
- architectures.
- From ARMv6-M Reference Manual B1.5.8
- Table B1-5 Exception return behavior
- EXC_RETURN Return To Return Stack
- 0xFFFFFFF1 Handler mode Main
- 0xFFFFFFF9 Thread mode Main
- 0xFFFFFFFD Thread mode Process
- From ARMv7-M Reference Manual B1.5.8
- Table B1-8 EXC_RETURN definition of exception return behavior, no FP
- EXC_RETURN Return To Return Stack
- 0xFFFFFFF1 Handler mode Main
- 0xFFFFFFF9 Thread mode Main
- 0xFFFFFFFD Thread mode Process
- Table B1-9 EXC_RETURN definition of exception return behavior, with
- FP
- EXC_RETURN Return To Return Stack Frame Type
- 0xFFFFFFE1 Handler mode Main Extended
- 0xFFFFFFE9 Thread mode Main Extended
- 0xFFFFFFED Thread mode Process Extended
- 0xFFFFFFF1 Handler mode Main Basic
- 0xFFFFFFF9 Thread mode Main Basic
- 0xFFFFFFFD Thread mode Process Basic
- For more details see "B1.5.8 Exception return behavior"
- in both ARMv6-M and ARMv7-M Architecture Reference Manuals.
- In the ARMv8-M Architecture Technical Reference also adds
- for implementations without the Security Extension:
- EXC_RETURN Condition
- 0xFFFFFFB0 Return to Handler mode.
- 0xFFFFFFB8 Return to Thread mode using the main stack.
- 0xFFFFFFBC Return to Thread mode using the process stack. */
- static int
- arm_m_addr_is_magic (CORE_ADDR addr)
- {
- switch (addr)
- {
- /* Values from ARMv8-M Architecture Technical Reference. */
- case 0xffffffb0:
- case 0xffffffb8:
- case 0xffffffbc:
- /* Values from Tables in B1.5.8 the EXC_RETURN definitions of
- the exception return behavior. */
- case 0xffffffe1:
- case 0xffffffe9:
- case 0xffffffed:
- case 0xfffffff1:
- case 0xfffffff9:
- case 0xfffffffd:
- /* Address is magic. */
- return 1;
- default:
- /* Address is not magic. */
- return 0;
- }
- }
- /* Remove useless bits from addresses in a running program. */
- static CORE_ADDR
- arm_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR val)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* On M-profile devices, do not strip the low bit from EXC_RETURN
- (the magic exception return address). */
- if (tdep->is_m && arm_m_addr_is_magic (val))
- return val;
- if (arm_apcs_32)
- return UNMAKE_THUMB_ADDR (val);
- else
- return (val & 0x03fffffc);
- }
- /* Return 1 if PC is the start of a compiler helper function which
- can be safely ignored during prologue skipping. IS_THUMB is true
- if the function is known to be a Thumb function due to the way it
- is being called. */
- static int
- skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb)
- {
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- struct bound_minimal_symbol msym;
- msym = lookup_minimal_symbol_by_pc (pc);
- if (msym.minsym != NULL
- && BMSYMBOL_VALUE_ADDRESS (msym) == pc
- && msym.minsym->linkage_name () != NULL)
- {
- const char *name = msym.minsym->linkage_name ();
- /* The GNU linker's Thumb call stub to foo is named
- __foo_from_thumb. */
- if (strstr (name, "_from_thumb") != NULL)
- name += 2;
- /* On soft-float targets, __truncdfsf2 is called to convert promoted
- arguments to their argument types in non-prototyped
- functions. */
- if (startswith (name, "__truncdfsf2"))
- return 1;
- if (startswith (name, "__aeabi_d2f"))
- return 1;
- /* Internal functions related to thread-local storage. */
- if (startswith (name, "__tls_get_addr"))
- return 1;
- if (startswith (name, "__aeabi_read_tp"))
- return 1;
- }
- else
- {
- /* If we run against a stripped glibc, we may be unable to identify
- special functions by name. Check for one important case,
- __aeabi_read_tp, by comparing the *code* against the default
- implementation (this is hand-written ARM assembler in glibc). */
- if (!is_thumb
- && read_code_unsigned_integer (pc, 4, byte_order_for_code)
- == 0xe3e00a0f /* mov r0, #0xffff0fff */
- && read_code_unsigned_integer (pc + 4, 4, byte_order_for_code)
- == 0xe240f01f) /* sub pc, r0, #31 */
- return 1;
- }
- return 0;
- }
- /* Extract the immediate from instruction movw/movt of encoding T. INSN1 is
- the first 16-bit of instruction, and INSN2 is the second 16-bit of
- instruction. */
- #define EXTRACT_MOVW_MOVT_IMM_T(insn1, insn2) \
- ((bits ((insn1), 0, 3) << 12) \
- | (bits ((insn1), 10, 10) << 11) \
- | (bits ((insn2), 12, 14) << 8) \
- | bits ((insn2), 0, 7))
- /* Extract the immediate from instruction movw/movt of encoding A. INSN is
- the 32-bit instruction. */
- #define EXTRACT_MOVW_MOVT_IMM_A(insn) \
- ((bits ((insn), 16, 19) << 12) \
- | bits ((insn), 0, 11))
- /* Decode immediate value; implements ThumbExpandImmediate pseudo-op. */
- static unsigned int
- thumb_expand_immediate (unsigned int imm)
- {
- unsigned int count = imm >> 7;
- if (count < 8)
- switch (count / 2)
- {
- case 0:
- return imm & 0xff;
- case 1:
- return (imm & 0xff) | ((imm & 0xff) << 16);
- case 2:
- return ((imm & 0xff) << 8) | ((imm & 0xff) << 24);
- case 3:
- return (imm & 0xff) | ((imm & 0xff) << 8)
- | ((imm & 0xff) << 16) | ((imm & 0xff) << 24);
- }
- return (0x80 | (imm & 0x7f)) << (32 - count);
- }
- /* Return 1 if the 16-bit Thumb instruction INSN restores SP in
- epilogue, 0 otherwise. */
- static int
- thumb_instruction_restores_sp (unsigned short insn)
- {
- return (insn == 0x46bd /* mov sp, r7 */
- || (insn & 0xff80) == 0xb000 /* add sp, imm */
- || (insn & 0xfe00) == 0xbc00); /* pop <registers> */
- }
- /* Analyze a Thumb prologue, looking for a recognizable stack frame
- and frame pointer. Scan until we encounter a store that could
- clobber the stack frame unexpectedly, or an unknown instruction.
- Return the last address which is definitely safe to skip for an
- initial breakpoint. */
- static CORE_ADDR
- thumb_analyze_prologue (struct gdbarch *gdbarch,
- CORE_ADDR start, CORE_ADDR limit,
- struct arm_prologue_cache *cache)
- {
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- int i;
- pv_t regs[16];
- CORE_ADDR offset;
- CORE_ADDR unrecognized_pc = 0;
- for (i = 0; i < 16; i++)
- regs[i] = pv_register (i, 0);
- pv_area stack (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch));
- while (start < limit)
- {
- unsigned short insn;
- gdb::optional<bool> ra_signed_state;
- insn = read_code_unsigned_integer (start, 2, byte_order_for_code);
- if ((insn & 0xfe00) == 0xb400) /* push { rlist } */
- {
- int regno;
- int mask;
- if (stack.store_would_trash (regs[ARM_SP_REGNUM]))
- break;
- /* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says
- whether to save LR (R14). */
- mask = (insn & 0xff) | ((insn & 0x100) << 6);
- /* Calculate offsets of saved R0-R7 and LR. */
- for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
- if (mask & (1 << regno))
- {
- regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
- -4);
- stack.store (regs[ARM_SP_REGNUM], 4, regs[regno]);
- }
- }
- else if ((insn & 0xff80) == 0xb080) /* sub sp, #imm */
- {
- offset = (insn & 0x7f) << 2; /* get scaled offset */
- regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
- -offset);
- }
- else if (thumb_instruction_restores_sp (insn))
- {
- /* Don't scan past the epilogue. */
- break;
- }
- else if ((insn & 0xf800) == 0xa800) /* add Rd, sp, #imm */
- regs[bits (insn, 8, 10)] = pv_add_constant (regs[ARM_SP_REGNUM],
- (insn & 0xff) << 2);
- else if ((insn & 0xfe00) == 0x1c00 /* add Rd, Rn, #imm */
- && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM))
- regs[bits (insn, 0, 2)] = pv_add_constant (regs[bits (insn, 3, 5)],
- bits (insn, 6, 8));
- else if ((insn & 0xf800) == 0x3000 /* add Rd, #imm */
- && pv_is_register (regs[bits (insn, 8, 10)], ARM_SP_REGNUM))
- regs[bits (insn, 8, 10)] = pv_add_constant (regs[bits (insn, 8, 10)],
- bits (insn, 0, 7));
- else if ((insn & 0xfe00) == 0x1800 /* add Rd, Rn, Rm */
- && pv_is_register (regs[bits (insn, 6, 8)], ARM_SP_REGNUM)
- && pv_is_constant (regs[bits (insn, 3, 5)]))
- regs[bits (insn, 0, 2)] = pv_add (regs[bits (insn, 3, 5)],
- regs[bits (insn, 6, 8)]);
- else if ((insn & 0xff00) == 0x4400 /* add Rd, Rm */
- && pv_is_constant (regs[bits (insn, 3, 6)]))
- {
- int rd = (bit (insn, 7) << 3) + bits (insn, 0, 2);
- int rm = bits (insn, 3, 6);
- regs[rd] = pv_add (regs[rd], regs[rm]);
- }
- else if ((insn & 0xff00) == 0x4600) /* mov hi, lo or mov lo, hi */
- {
- int dst_reg = (insn & 0x7) + ((insn & 0x80) >> 4);
- int src_reg = (insn & 0x78) >> 3;
- regs[dst_reg] = regs[src_reg];
- }
- else if ((insn & 0xf800) == 0x9000) /* str rd, [sp, #off] */
- {
- /* Handle stores to the stack. Normally pushes are used,
- but with GCC -mtpcs-frame, there may be other stores
- in the prologue to create the frame. */
- int regno = (insn >> 8) & 0x7;
- pv_t addr;
- offset = (insn & 0xff) << 2;
- addr = pv_add_constant (regs[ARM_SP_REGNUM], offset);
- if (stack.store_would_trash (addr))
- break;
- stack.store (addr, 4, regs[regno]);
- }
- else if ((insn & 0xf800) == 0x6000) /* str rd, [rn, #off] */
- {
- int rd = bits (insn, 0, 2);
- int rn = bits (insn, 3, 5);
- pv_t addr;
- offset = bits (insn, 6, 10) << 2;
- addr = pv_add_constant (regs[rn], offset);
- if (stack.store_would_trash (addr))
- break;
- stack.store (addr, 4, regs[rd]);
- }
- else if (((insn & 0xf800) == 0x7000 /* strb Rd, [Rn, #off] */
- || (insn & 0xf800) == 0x8000) /* strh Rd, [Rn, #off] */
- && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM))
- /* Ignore stores of argument registers to the stack. */
- ;
- else if ((insn & 0xf800) == 0xc800 /* ldmia Rn!, { registers } */
- && pv_is_register (regs[bits (insn, 8, 10)], ARM_SP_REGNUM))
- /* Ignore block loads from the stack, potentially copying
- parameters from memory. */
- ;
- else if ((insn & 0xf800) == 0x9800 /* ldr Rd, [Rn, #immed] */
- || ((insn & 0xf800) == 0x6800 /* ldr Rd, [sp, #immed] */
- && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM)))
- /* Similarly ignore single loads from the stack. */
- ;
- else if ((insn & 0xffc0) == 0x0000 /* lsls Rd, Rm, #0 */
- || (insn & 0xffc0) == 0x1c00) /* add Rd, Rn, #0 */
- /* Skip register copies, i.e. saves to another register
- instead of the stack. */
- ;
- else if ((insn & 0xf800) == 0x2000) /* movs Rd, #imm */
- /* Recognize constant loads; even with small stacks these are necessary
- on Thumb. */
- regs[bits (insn, 8, 10)] = pv_constant (bits (insn, 0, 7));
- else if ((insn & 0xf800) == 0x4800) /* ldr Rd, [pc, #imm] */
- {
- /* Constant pool loads, for the same reason. */
- unsigned int constant;
- CORE_ADDR loc;
- loc = start + 4 + bits (insn, 0, 7) * 4;
- constant = read_memory_unsigned_integer (loc, 4, byte_order);
- regs[bits (insn, 8, 10)] = pv_constant (constant);
- }
- else if (thumb_insn_size (insn) == 4) /* 32-bit Thumb-2 instructions. */
- {
- unsigned short inst2;
- inst2 = read_code_unsigned_integer (start + 2, 2,
- byte_order_for_code);
- uint32_t whole_insn = (insn << 16) | inst2;
- if ((insn & 0xf800) == 0xf000 && (inst2 & 0xe800) == 0xe800)
- {
- /* BL, BLX. Allow some special function calls when
- skipping the prologue; GCC generates these before
- storing arguments to the stack. */
- CORE_ADDR nextpc;
- int j1, j2, imm1, imm2;
- imm1 = sbits (insn, 0, 10);
- imm2 = bits (inst2, 0, 10);
- j1 = bit (inst2, 13);
- j2 = bit (inst2, 11);
- offset = ((imm1 << 12) + (imm2 << 1));
- offset ^= ((!j2) << 22) | ((!j1) << 23);
- nextpc = start + 4 + offset;
- /* For BLX make sure to clear the low bits. */
- if (bit (inst2, 12) == 0)
- nextpc = nextpc & 0xfffffffc;
- if (!skip_prologue_function (gdbarch, nextpc,
- bit (inst2, 12) != 0))
- break;
- }
- else if ((insn & 0xffd0) == 0xe900 /* stmdb Rn{!},
- { registers } */
- && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
- {
- pv_t addr = regs[bits (insn, 0, 3)];
- int regno;
- if (stack.store_would_trash (addr))
- break;
- /* Calculate offsets of saved registers. */
- for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
- if (inst2 & (1 << regno))
- {
- addr = pv_add_constant (addr, -4);
- stack.store (addr, 4, regs[regno]);
- }
- if (insn & 0x0020)
- regs[bits (insn, 0, 3)] = addr;
- }
- else if ((insn & 0xff50) == 0xe940 /* strd Rt, Rt2,
- [Rn, #+/-imm]{!} */
- && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
- {
- int regno1 = bits (inst2, 12, 15);
- int regno2 = bits (inst2, 8, 11);
- pv_t addr = regs[bits (insn, 0, 3)];
- offset = inst2 & 0xff;
- if (insn & 0x0080)
- addr = pv_add_constant (addr, offset);
- else
- addr = pv_add_constant (addr, -offset);
- if (stack.store_would_trash (addr))
- break;
- stack.store (addr, 4, regs[regno1]);
- stack.store (pv_add_constant (addr, 4),
- 4, regs[regno2]);
- if (insn & 0x0020)
- regs[bits (insn, 0, 3)] = addr;
- }
- else if ((insn & 0xfff0) == 0xf8c0 /* str Rt,[Rn,+/-#imm]{!} */
- && (inst2 & 0x0c00) == 0x0c00
- && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
- {
- int regno = bits (inst2, 12, 15);
- pv_t addr = regs[bits (insn, 0, 3)];
- offset = inst2 & 0xff;
- if (inst2 & 0x0200)
- addr = pv_add_constant (addr, offset);
- else
- addr = pv_add_constant (addr, -offset);
- if (stack.store_would_trash (addr))
- break;
- stack.store (addr, 4, regs[regno]);
- if (inst2 & 0x0100)
- regs[bits (insn, 0, 3)] = addr;
- }
- else if ((insn & 0xfff0) == 0xf8c0 /* str.w Rt,[Rn,#imm] */
- && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
- {
- int regno = bits (inst2, 12, 15);
- pv_t addr;
- offset = inst2 & 0xfff;
- addr = pv_add_constant (regs[bits (insn, 0, 3)], offset);
- if (stack.store_would_trash (addr))
- break;
- stack.store (addr, 4, regs[regno]);
- }
- else if ((insn & 0xffd0) == 0xf880 /* str{bh}.w Rt,[Rn,#imm] */
- && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
- /* Ignore stores of argument registers to the stack. */
- ;
- else if ((insn & 0xffd0) == 0xf800 /* str{bh} Rt,[Rn,#+/-imm] */
- && (inst2 & 0x0d00) == 0x0c00
- && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
- /* Ignore stores of argument registers to the stack. */
- ;
- else if ((insn & 0xffd0) == 0xe890 /* ldmia Rn[!],
- { registers } */
- && (inst2 & 0x8000) == 0x0000
- && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
- /* Ignore block loads from the stack, potentially copying
- parameters from memory. */
- ;
- else if ((insn & 0xff70) == 0xe950 /* ldrd Rt, Rt2,
- [Rn, #+/-imm] */
- && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
- /* Similarly ignore dual loads from the stack. */
- ;
- else if ((insn & 0xfff0) == 0xf850 /* ldr Rt,[Rn,#+/-imm] */
- && (inst2 & 0x0d00) == 0x0c00
- && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
- /* Similarly ignore single loads from the stack. */
- ;
- else if ((insn & 0xfff0) == 0xf8d0 /* ldr.w Rt,[Rn,#imm] */
- && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
- /* Similarly ignore single loads from the stack. */
- ;
- else if ((insn & 0xfbf0) == 0xf100 /* add.w Rd, Rn, #imm */
- && (inst2 & 0x8000) == 0x0000)
- {
- unsigned int imm = ((bits (insn, 10, 10) << 11)
- | (bits (inst2, 12, 14) << 8)
- | bits (inst2, 0, 7));
- regs[bits (inst2, 8, 11)]
- = pv_add_constant (regs[bits (insn, 0, 3)],
- thumb_expand_immediate (imm));
- }
- else if ((insn & 0xfbf0) == 0xf200 /* addw Rd, Rn, #imm */
- && (inst2 & 0x8000) == 0x0000)
- {
- unsigned int imm = ((bits (insn, 10, 10) << 11)
- | (bits (inst2, 12, 14) << 8)
- | bits (inst2, 0, 7));
- regs[bits (inst2, 8, 11)]
- = pv_add_constant (regs[bits (insn, 0, 3)], imm);
- }
- else if ((insn & 0xfbf0) == 0xf1a0 /* sub.w Rd, Rn, #imm */
- && (inst2 & 0x8000) == 0x0000)
- {
- unsigned int imm = ((bits (insn, 10, 10) << 11)
- | (bits (inst2, 12, 14) << 8)
- | bits (inst2, 0, 7));
- regs[bits (inst2, 8, 11)]
- = pv_add_constant (regs[bits (insn, 0, 3)],
- - (CORE_ADDR) thumb_expand_immediate (imm));
- }
- else if ((insn & 0xfbf0) == 0xf2a0 /* subw Rd, Rn, #imm */
- && (inst2 & 0x8000) == 0x0000)
- {
- unsigned int imm = ((bits (insn, 10, 10) << 11)
- | (bits (inst2, 12, 14) << 8)
- | bits (inst2, 0, 7));
- regs[bits (inst2, 8, 11)]
- = pv_add_constant (regs[bits (insn, 0, 3)], - (CORE_ADDR) imm);
- }
- else if ((insn & 0xfbff) == 0xf04f) /* mov.w Rd, #const */
- {
- unsigned int imm = ((bits (insn, 10, 10) << 11)
- | (bits (inst2, 12, 14) << 8)
- | bits (inst2, 0, 7));
- regs[bits (inst2, 8, 11)]
- = pv_constant (thumb_expand_immediate (imm));
- }
- else if ((insn & 0xfbf0) == 0xf240) /* movw Rd, #const */
- {
- unsigned int imm
- = EXTRACT_MOVW_MOVT_IMM_T (insn, inst2);
- regs[bits (inst2, 8, 11)] = pv_constant (imm);
- }
- else if (insn == 0xea5f /* mov.w Rd,Rm */
- && (inst2 & 0xf0f0) == 0)
- {
- int dst_reg = (inst2 & 0x0f00) >> 8;
- int src_reg = inst2 & 0xf;
- regs[dst_reg] = regs[src_reg];
- }
- else if ((insn & 0xff7f) == 0xf85f) /* ldr.w Rt,<label> */
- {
- /* Constant pool loads. */
- unsigned int constant;
- CORE_ADDR loc;
- offset = bits (inst2, 0, 11);
- if (insn & 0x0080)
- loc = start + 4 + offset;
- else
- loc = start + 4 - offset;
- constant = read_memory_unsigned_integer (loc, 4, byte_order);
- regs[bits (inst2, 12, 15)] = pv_constant (constant);
- }
- else if ((insn & 0xff7f) == 0xe95f) /* ldrd Rt,Rt2,<label> */
- {
- /* Constant pool loads. */
- unsigned int constant;
- CORE_ADDR loc;
- offset = bits (inst2, 0, 7) << 2;
- if (insn & 0x0080)
- loc = start + 4 + offset;
- else
- loc = start + 4 - offset;
- constant = read_memory_unsigned_integer (loc, 4, byte_order);
- regs[bits (inst2, 12, 15)] = pv_constant (constant);
- constant = read_memory_unsigned_integer (loc + 4, 4, byte_order);
- regs[bits (inst2, 8, 11)] = pv_constant (constant);
- }
- /* Start of ARMv8.1-m PACBTI extension instructions. */
- else if (IS_PAC (whole_insn))
- {
- /* LR and SP are input registers. PAC is in R12. LR is
- signed from this point onwards. NOP space. */
- ra_signed_state = true;
- }
- else if (IS_PACBTI (whole_insn))
- {
- /* LR and SP are input registers. PAC is in R12 and PC is a
- valid BTI landing pad. LR is signed from this point onwards.
- NOP space. */
- ra_signed_state = true;
- }
- else if (IS_BTI (whole_insn))
- {
- /* Valid BTI landing pad. NOP space. */
- }
- else if (IS_PACG (whole_insn))
- {
- /* Sign Rn using Rm and store the PAC in Rd. Rd is signed from
- this point onwards. */
- ra_signed_state = true;
- }
- else if (IS_AUT (whole_insn) || IS_AUTG (whole_insn))
- {
- /* These instructions appear close to the epilogue, when signed
- pointers are getting authenticated. */
- ra_signed_state = false;
- }
- /* End of ARMv8.1-m PACBTI extension instructions */
- else if (thumb2_instruction_changes_pc (insn, inst2))
- {
- /* Don't scan past anything that might change control flow. */
- break;
- }
- else
- {
- /* The optimizer might shove anything into the prologue,
- so we just skip what we don't recognize. */
- unrecognized_pc = start;
- }
- arm_gdbarch_tdep *tdep
- = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* Make sure we are dealing with a target that supports ARMv8.1-m
- PACBTI. */
- if (cache != nullptr && tdep->have_pacbti
- && ra_signed_state.has_value ())
- {
- arm_debug_printf ("Found pacbti instruction at %s",
- paddress (gdbarch, start));
- arm_debug_printf ("RA is %s",
- *ra_signed_state? "signed" : "not signed");
- cache->ra_signed_state = ra_signed_state;
- }
- start += 2;
- }
- else if (thumb_instruction_changes_pc (insn))
- {
- /* Don't scan past anything that might change control flow. */
- break;
- }
- else
- {
- /* The optimizer might shove anything into the prologue,
- so we just skip what we don't recognize. */
- unrecognized_pc = start;
- }
- start += 2;
- }
- arm_debug_printf ("Prologue scan stopped at %s",
- paddress (gdbarch, start));
- if (unrecognized_pc == 0)
- unrecognized_pc = start;
- if (cache == NULL)
- return unrecognized_pc;
- if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
- {
- /* Frame pointer is fp. Frame size is constant. */
- cache->framereg = ARM_FP_REGNUM;
- cache->framesize = -regs[ARM_FP_REGNUM].k;
- }
- else if (pv_is_register (regs[THUMB_FP_REGNUM], ARM_SP_REGNUM))
- {
- /* Frame pointer is r7. Frame size is constant. */
- cache->framereg = THUMB_FP_REGNUM;
- cache->framesize = -regs[THUMB_FP_REGNUM].k;
- }
- else
- {
- /* Try the stack pointer... this is a bit desperate. */
- cache->framereg = ARM_SP_REGNUM;
- cache->framesize = -regs[ARM_SP_REGNUM].k;
- }
- for (i = 0; i < 16; i++)
- if (stack.find_reg (gdbarch, i, &offset))
- cache->saved_regs[i].set_addr (offset);
- return unrecognized_pc;
- }
- /* Try to analyze the instructions starting from PC, which load symbol
- __stack_chk_guard. Return the address of instruction after loading this
- symbol, set the dest register number to *BASEREG, and set the size of
- instructions for loading symbol in OFFSET. Return 0 if instructions are
- not recognized. */
- static CORE_ADDR
- arm_analyze_load_stack_chk_guard(CORE_ADDR pc, struct gdbarch *gdbarch,
- unsigned int *destreg, int *offset)
- {
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- int is_thumb = arm_pc_is_thumb (gdbarch, pc);
- unsigned int low, high, address;
- address = 0;
- if (is_thumb)
- {
- unsigned short insn1
- = read_code_unsigned_integer (pc, 2, byte_order_for_code);
- if ((insn1 & 0xf800) == 0x4800) /* ldr Rd, #immed */
- {
- *destreg = bits (insn1, 8, 10);
- *offset = 2;
- address = (pc & 0xfffffffc) + 4 + (bits (insn1, 0, 7) << 2);
- address = read_memory_unsigned_integer (address, 4,
- byte_order_for_code);
- }
- else if ((insn1 & 0xfbf0) == 0xf240) /* movw Rd, #const */
- {
- unsigned short insn2
- = read_code_unsigned_integer (pc + 2, 2, byte_order_for_code);
- low = EXTRACT_MOVW_MOVT_IMM_T (insn1, insn2);
- insn1
- = read_code_unsigned_integer (pc + 4, 2, byte_order_for_code);
- insn2
- = read_code_unsigned_integer (pc + 6, 2, byte_order_for_code);
- /* movt Rd, #const */
- if ((insn1 & 0xfbc0) == 0xf2c0)
- {
- high = EXTRACT_MOVW_MOVT_IMM_T (insn1, insn2);
- *destreg = bits (insn2, 8, 11);
- *offset = 8;
- address = (high << 16 | low);
- }
- }
- }
- else
- {
- unsigned int insn
- = read_code_unsigned_integer (pc, 4, byte_order_for_code);
- if ((insn & 0x0e5f0000) == 0x041f0000) /* ldr Rd, [PC, #immed] */
- {
- address = bits (insn, 0, 11) + pc + 8;
- address = read_memory_unsigned_integer (address, 4,
- byte_order_for_code);
- *destreg = bits (insn, 12, 15);
- *offset = 4;
- }
- else if ((insn & 0x0ff00000) == 0x03000000) /* movw Rd, #const */
- {
- low = EXTRACT_MOVW_MOVT_IMM_A (insn);
- insn
- = read_code_unsigned_integer (pc + 4, 4, byte_order_for_code);
- if ((insn & 0x0ff00000) == 0x03400000) /* movt Rd, #const */
- {
- high = EXTRACT_MOVW_MOVT_IMM_A (insn);
- *destreg = bits (insn, 12, 15);
- *offset = 8;
- address = (high << 16 | low);
- }
- }
- }
- return address;
- }
- /* Try to skip a sequence of instructions used for stack protector. If PC
- points to the first instruction of this sequence, return the address of
- first instruction after this sequence, otherwise, return original PC.
- On arm, this sequence of instructions is composed of mainly three steps,
- Step 1: load symbol __stack_chk_guard,
- Step 2: load from address of __stack_chk_guard,
- Step 3: store it to somewhere else.
- Usually, instructions on step 2 and step 3 are the same on various ARM
- architectures. On step 2, it is one instruction 'ldr Rx, [Rn, #0]', and
- on step 3, it is also one instruction 'str Rx, [r7, #immd]'. However,
- instructions in step 1 vary from different ARM architectures. On ARMv7,
- they are,
- movw Rn, #:lower16:__stack_chk_guard
- movt Rn, #:upper16:__stack_chk_guard
- On ARMv5t, it is,
- ldr Rn, .Label
- ....
- .Lable:
- .word __stack_chk_guard
- Since ldr/str is a very popular instruction, we can't use them as
- 'fingerprint' or 'signature' of stack protector sequence. Here we choose
- sequence {movw/movt, ldr}/ldr/str plus symbol __stack_chk_guard, if not
- stripped, as the 'fingerprint' of a stack protector cdoe sequence. */
- static CORE_ADDR
- arm_skip_stack_protector(CORE_ADDR pc, struct gdbarch *gdbarch)
- {
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- unsigned int basereg;
- struct bound_minimal_symbol stack_chk_guard;
- int offset;
- int is_thumb = arm_pc_is_thumb (gdbarch, pc);
- CORE_ADDR addr;
- /* Try to parse the instructions in Step 1. */
- addr = arm_analyze_load_stack_chk_guard (pc, gdbarch,
- &basereg, &offset);
- if (!addr)
- return pc;
- stack_chk_guard = lookup_minimal_symbol_by_pc (addr);
- /* ADDR must correspond to a symbol whose name is __stack_chk_guard.
- Otherwise, this sequence cannot be for stack protector. */
- if (stack_chk_guard.minsym == NULL
- || !startswith (stack_chk_guard.minsym->linkage_name (), "__stack_chk_guard"))
- return pc;
- if (is_thumb)
- {
- unsigned int destreg;
- unsigned short insn
- = read_code_unsigned_integer (pc + offset, 2, byte_order_for_code);
- /* Step 2: ldr Rd, [Rn, #immed], encoding T1. */
- if ((insn & 0xf800) != 0x6800)
- return pc;
- if (bits (insn, 3, 5) != basereg)
- return pc;
- destreg = bits (insn, 0, 2);
- insn = read_code_unsigned_integer (pc + offset + 2, 2,
- byte_order_for_code);
- /* Step 3: str Rd, [Rn, #immed], encoding T1. */
- if ((insn & 0xf800) != 0x6000)
- return pc;
- if (destreg != bits (insn, 0, 2))
- return pc;
- }
- else
- {
- unsigned int destreg;
- unsigned int insn
- = read_code_unsigned_integer (pc + offset, 4, byte_order_for_code);
- /* Step 2: ldr Rd, [Rn, #immed], encoding A1. */
- if ((insn & 0x0e500000) != 0x04100000)
- return pc;
- if (bits (insn, 16, 19) != basereg)
- return pc;
- destreg = bits (insn, 12, 15);
- /* Step 3: str Rd, [Rn, #immed], encoding A1. */
- insn = read_code_unsigned_integer (pc + offset + 4,
- 4, byte_order_for_code);
- if ((insn & 0x0e500000) != 0x04000000)
- return pc;
- if (bits (insn, 12, 15) != destreg)
- return pc;
- }
- /* The size of total two instructions ldr/str is 4 on Thumb-2, while 8
- on arm. */
- if (is_thumb)
- return pc + offset + 4;
- else
- return pc + offset + 8;
- }
- /* Advance the PC across any function entry prologue instructions to
- reach some "real" code.
- The APCS (ARM Procedure Call Standard) defines the following
- prologue:
- mov ip, sp
- [stmfd sp!, {a1,a2,a3,a4}]
- stmfd sp!, {...,fp,ip,lr,pc}
- [stfe f7, [sp, #-12]!]
- [stfe f6, [sp, #-12]!]
- [stfe f5, [sp, #-12]!]
- [stfe f4, [sp, #-12]!]
- sub fp, ip, #nn @@ nn == 20 or 4 depending on second insn. */
- static CORE_ADDR
- arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- CORE_ADDR func_addr, limit_pc;
- /* See if we can determine the end of the prologue via the symbol table.
- If so, then return either PC, or the PC after the prologue, whichever
- is greater. */
- if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
- {
- CORE_ADDR post_prologue_pc
- = skip_prologue_using_sal (gdbarch, func_addr);
- struct compunit_symtab *cust = find_pc_compunit_symtab (func_addr);
- if (post_prologue_pc)
- post_prologue_pc
- = arm_skip_stack_protector (post_prologue_pc, gdbarch);
- /* GCC always emits a line note before the prologue and another
- one after, even if the two are at the same address or on the
- same line. Take advantage of this so that we do not need to
- know every instruction that might appear in the prologue. We
- will have producer information for most binaries; if it is
- missing (e.g. for -gstabs), assuming the GNU tools. */
- if (post_prologue_pc
- && (cust == NULL
- || cust->producer () == NULL
- || startswith (cust->producer (), "GNU ")
- || producer_is_llvm (cust->producer ())))
- return post_prologue_pc;
- if (post_prologue_pc != 0)
- {
- CORE_ADDR analyzed_limit;
- /* For non-GCC compilers, make sure the entire line is an
- acceptable prologue; GDB will round this function's
- return value up to the end of the following line so we
- can not skip just part of a line (and we do not want to).
- RealView does not treat the prologue specially, but does
- associate prologue code with the opening brace; so this
- lets us skip the first line if we think it is the opening
- brace. */
- if (arm_pc_is_thumb (gdbarch, func_addr))
- analyzed_limit = thumb_analyze_prologue (gdbarch, func_addr,
- post_prologue_pc, NULL);
- else
- analyzed_limit
- = arm_analyze_prologue (gdbarch, func_addr, post_prologue_pc,
- NULL, target_arm_instruction_reader ());
- if (analyzed_limit != post_prologue_pc)
- return func_addr;
- return post_prologue_pc;
- }
- }
- /* Can't determine prologue from the symbol table, need to examine
- instructions. */
- /* Find an upper limit on the function prologue using the debug
- information. If the debug information could not be used to provide
- that bound, then use an arbitrary large number as the upper bound. */
- /* Like arm_scan_prologue, stop no later than pc + 64. */
- limit_pc = skip_prologue_using_sal (gdbarch, pc);
- if (limit_pc == 0)
- limit_pc = pc + 64; /* Magic. */
- /* Check if this is Thumb code. */
- if (arm_pc_is_thumb (gdbarch, pc))
- return thumb_analyze_prologue (gdbarch, pc, limit_pc, NULL);
- else
- return arm_analyze_prologue (gdbarch, pc, limit_pc, NULL,
- target_arm_instruction_reader ());
- }
- /* *INDENT-OFF* */
- /* Function: thumb_scan_prologue (helper function for arm_scan_prologue)
- This function decodes a Thumb function prologue to determine:
- 1) the size of the stack frame
- 2) which registers are saved on it
- 3) the offsets of saved regs
- 4) the offset from the stack pointer to the frame pointer
- A typical Thumb function prologue would create this stack frame
- (offsets relative to FP)
- old SP -> 24 stack parameters
- 20 LR
- 16 R7
- R7 -> 0 local variables (16 bytes)
- SP -> -12 additional stack space (12 bytes)
- The frame size would thus be 36 bytes, and the frame offset would be
- 12 bytes. The frame register is R7.
-
- The comments for thumb_skip_prolog() describe the algorithm we use
- to detect the end of the prolog. */
- /* *INDENT-ON* */
- static void
- thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc,
- CORE_ADDR block_addr, struct arm_prologue_cache *cache)
- {
- CORE_ADDR prologue_start;
- CORE_ADDR prologue_end;
- if (find_pc_partial_function (block_addr, NULL, &prologue_start,
- &prologue_end))
- {
- /* See comment in arm_scan_prologue for an explanation of
- this heuristics. */
- if (prologue_end > prologue_start + 64)
- {
- prologue_end = prologue_start + 64;
- }
- }
- else
- /* We're in the boondocks: we have no idea where the start of the
- function is. */
- return;
- prologue_end = std::min (prologue_end, prev_pc);
- thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
- }
- /* Return 1 if the ARM instruction INSN restores SP in epilogue, 0
- otherwise. */
- static int
- arm_instruction_restores_sp (unsigned int insn)
- {
- if (bits (insn, 28, 31) != INST_NV)
- {
- if ((insn & 0x0df0f000) == 0x0080d000
- /* ADD SP (register or immediate). */
- || (insn & 0x0df0f000) == 0x0040d000
- /* SUB SP (register or immediate). */
- || (insn & 0x0ffffff0) == 0x01a0d000
- /* MOV SP. */
- || (insn & 0x0fff0000) == 0x08bd0000
- /* POP (LDMIA). */
- || (insn & 0x0fff0000) == 0x049d0000)
- /* POP of a single register. */
- return 1;
- }
- return 0;
- }
- /* Implement immediate value decoding, as described in section A5.2.4
- (Modified immediate constants in ARM instructions) of the ARM Architecture
- Reference Manual (ARMv7-A and ARMv7-R edition). */
- static uint32_t
- arm_expand_immediate (uint32_t imm)
- {
- /* Immediate values are 12 bits long. */
- gdb_assert ((imm & 0xfffff000) == 0);
- uint32_t unrotated_value = imm & 0xff;
- uint32_t rotate_amount = (imm & 0xf00) >> 7;
- if (rotate_amount == 0)
- return unrotated_value;
- return ((unrotated_value >> rotate_amount)
- | (unrotated_value << (32 - rotate_amount)));
- }
- /* Analyze an ARM mode prologue starting at PROLOGUE_START and
- continuing no further than PROLOGUE_END. If CACHE is non-NULL,
- fill it in. Return the first address not recognized as a prologue
- instruction.
- We recognize all the instructions typically found in ARM prologues,
- plus harmless instructions which can be skipped (either for analysis
- purposes, or a more restrictive set that can be skipped when finding
- the end of the prologue). */
- static CORE_ADDR
- arm_analyze_prologue (struct gdbarch *gdbarch,
- CORE_ADDR prologue_start, CORE_ADDR prologue_end,
- struct arm_prologue_cache *cache,
- const arm_instruction_reader &insn_reader)
- {
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- int regno;
- CORE_ADDR offset, current_pc;
- pv_t regs[ARM_FPS_REGNUM];
- CORE_ADDR unrecognized_pc = 0;
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* Search the prologue looking for instructions that set up the
- frame pointer, adjust the stack pointer, and save registers.
- Be careful, however, and if it doesn't look like a prologue,
- don't try to scan it. If, for instance, a frameless function
- begins with stmfd sp!, then we will tell ourselves there is
- a frame, which will confuse stack traceback, as well as "finish"
- and other operations that rely on a knowledge of the stack
- traceback. */
- for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
- regs[regno] = pv_register (regno, 0);
- pv_area stack (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch));
- for (current_pc = prologue_start;
- current_pc < prologue_end;
- current_pc += 4)
- {
- uint32_t insn = insn_reader.read (current_pc, byte_order_for_code);
- if (insn == 0xe1a0c00d) /* mov ip, sp */
- {
- regs[ARM_IP_REGNUM] = regs[ARM_SP_REGNUM];
- continue;
- }
- else if ((insn & 0xfff00000) == 0xe2800000 /* add Rd, Rn, #n */
- && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
- {
- uint32_t imm = arm_expand_immediate (insn & 0xfff);
- int rd = bits (insn, 12, 15);
- regs[rd] = pv_add_constant (regs[bits (insn, 16, 19)], imm);
- continue;
- }
- else if ((insn & 0xfff00000) == 0xe2400000 /* sub Rd, Rn, #n */
- && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
- {
- uint32_t imm = arm_expand_immediate (insn & 0xfff);
- int rd = bits (insn, 12, 15);
- regs[rd] = pv_add_constant (regs[bits (insn, 16, 19)], -imm);
- continue;
- }
- else if ((insn & 0xffff0fff) == 0xe52d0004) /* str Rd,
- [sp, #-4]! */
- {
- if (stack.store_would_trash (regs[ARM_SP_REGNUM]))
- break;
- regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4);
- stack.store (regs[ARM_SP_REGNUM], 4,
- regs[bits (insn, 12, 15)]);
- continue;
- }
- else if ((insn & 0xffff0000) == 0xe92d0000)
- /* stmfd sp!, {..., fp, ip, lr, pc}
- or
- stmfd sp!, {a1, a2, a3, a4} */
- {
- int mask = insn & 0xffff;
- if (stack.store_would_trash (regs[ARM_SP_REGNUM]))
- break;
- /* Calculate offsets of saved registers. */
- for (regno = ARM_PC_REGNUM; regno >= 0; regno--)
- if (mask & (1 << regno))
- {
- regs[ARM_SP_REGNUM]
- = pv_add_constant (regs[ARM_SP_REGNUM], -4);
- stack.store (regs[ARM_SP_REGNUM], 4, regs[regno]);
- }
- }
- else if ((insn & 0xffff0000) == 0xe54b0000 /* strb rx,[r11,#-n] */
- || (insn & 0xffff00f0) == 0xe14b00b0 /* strh rx,[r11,#-n] */
- || (insn & 0xffffc000) == 0xe50b0000) /* str rx,[r11,#-n] */
- {
- /* No need to add this to saved_regs -- it's just an arg reg. */
- continue;
- }
- else if ((insn & 0xffff0000) == 0xe5cd0000 /* strb rx,[sp,#n] */
- || (insn & 0xffff00f0) == 0xe1cd00b0 /* strh rx,[sp,#n] */
- || (insn & 0xffffc000) == 0xe58d0000) /* str rx,[sp,#n] */
- {
- /* No need to add this to saved_regs -- it's just an arg reg. */
- continue;
- }
- else if ((insn & 0xfff00000) == 0xe8800000 /* stm Rn,
- { registers } */
- && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
- {
- /* No need to add this to saved_regs -- it's just arg regs. */
- continue;
- }
- else if ((insn & 0xfffff000) == 0xe24cb000) /* sub fp, ip #n */
- {
- uint32_t imm = arm_expand_immediate (insn & 0xfff);
- regs[ARM_FP_REGNUM] = pv_add_constant (regs[ARM_IP_REGNUM], -imm);
- }
- else if ((insn & 0xfffff000) == 0xe24dd000) /* sub sp, sp #n */
- {
- uint32_t imm = arm_expand_immediate(insn & 0xfff);
- regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm);
- }
- else if ((insn & 0xffff7fff) == 0xed6d0103 /* stfe f?,
- [sp, -#c]! */
- && tdep->have_fpa_registers)
- {
- if (stack.store_would_trash (regs[ARM_SP_REGNUM]))
- break;
- regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
- regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
- stack.store (regs[ARM_SP_REGNUM], 12, regs[regno]);
- }
- else if ((insn & 0xffbf0fff) == 0xec2d0200 /* sfmfd f0, 4,
- [sp!] */
- && tdep->have_fpa_registers)
- {
- int n_saved_fp_regs;
- unsigned int fp_start_reg, fp_bound_reg;
- if (stack.store_would_trash (regs[ARM_SP_REGNUM]))
- break;
- if ((insn & 0x800) == 0x800) /* N0 is set */
- {
- if ((insn & 0x40000) == 0x40000) /* N1 is set */
- n_saved_fp_regs = 3;
- else
- n_saved_fp_regs = 1;
- }
- else
- {
- if ((insn & 0x40000) == 0x40000) /* N1 is set */
- n_saved_fp_regs = 2;
- else
- n_saved_fp_regs = 4;
- }
- fp_start_reg = ARM_F0_REGNUM + ((insn >> 12) & 0x7);
- fp_bound_reg = fp_start_reg + n_saved_fp_regs;
- for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
- {
- regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
- stack.store (regs[ARM_SP_REGNUM], 12,
- regs[fp_start_reg++]);
- }
- }
- else if ((insn & 0xff000000) == 0xeb000000 && cache == NULL) /* bl */
- {
- /* Allow some special function calls when skipping the
- prologue; GCC generates these before storing arguments to
- the stack. */
- CORE_ADDR dest = BranchDest (current_pc, insn);
- if (skip_prologue_function (gdbarch, dest, 0))
- continue;
- else
- break;
- }
- else if ((insn & 0xf0000000) != 0xe0000000)
- break; /* Condition not true, exit early. */
- else if (arm_instruction_changes_pc (insn))
- /* Don't scan past anything that might change control flow. */
- break;
- else if (arm_instruction_restores_sp (insn))
- {
- /* Don't scan past the epilogue. */
- break;
- }
- else if ((insn & 0xfe500000) == 0xe8100000 /* ldm */
- && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
- /* Ignore block loads from the stack, potentially copying
- parameters from memory. */
- continue;
- else if ((insn & 0xfc500000) == 0xe4100000
- && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
- /* Similarly ignore single loads from the stack. */
- continue;
- else if ((insn & 0xffff0ff0) == 0xe1a00000)
- /* MOV Rd, Rm. Skip register copies, i.e. saves to another
- register instead of the stack. */
- continue;
- else
- {
- /* The optimizer might shove anything into the prologue, if
- we build up cache (cache != NULL) from scanning prologue,
- we just skip what we don't recognize and scan further to
- make cache as complete as possible. However, if we skip
- prologue, we'll stop immediately on unrecognized
- instruction. */
- unrecognized_pc = current_pc;
- if (cache != NULL)
- continue;
- else
- break;
- }
- }
- if (unrecognized_pc == 0)
- unrecognized_pc = current_pc;
- if (cache)
- {
- int framereg, framesize;
- /* The frame size is just the distance from the frame register
- to the original stack pointer. */
- if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
- {
- /* Frame pointer is fp. */
- framereg = ARM_FP_REGNUM;
- framesize = -regs[ARM_FP_REGNUM].k;
- }
- else
- {
- /* Try the stack pointer... this is a bit desperate. */
- framereg = ARM_SP_REGNUM;
- framesize = -regs[ARM_SP_REGNUM].k;
- }
- cache->framereg = framereg;
- cache->framesize = framesize;
- for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
- if (stack.find_reg (gdbarch, regno, &offset))
- cache->saved_regs[regno].set_addr (offset);
- }
- arm_debug_printf ("Prologue scan stopped at %s",
- paddress (gdbarch, unrecognized_pc));
- return unrecognized_pc;
- }
- static void
- arm_scan_prologue (struct frame_info *this_frame,
- struct arm_prologue_cache *cache)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- CORE_ADDR prologue_start, prologue_end;
- CORE_ADDR prev_pc = get_frame_pc (this_frame);
- CORE_ADDR block_addr = get_frame_address_in_block (this_frame);
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* Assume there is no frame until proven otherwise. */
- cache->framereg = ARM_SP_REGNUM;
- cache->framesize = 0;
- /* Check for Thumb prologue. */
- if (arm_frame_is_thumb (this_frame))
- {
- thumb_scan_prologue (gdbarch, prev_pc, block_addr, cache);
- return;
- }
- /* Find the function prologue. If we can't find the function in
- the symbol table, peek in the stack frame to find the PC. */
- if (find_pc_partial_function (block_addr, NULL, &prologue_start,
- &prologue_end))
- {
- /* One way to find the end of the prologue (which works well
- for unoptimized code) is to do the following:
- struct symtab_and_line sal = find_pc_line (prologue_start, 0);
- if (sal.line == 0)
- prologue_end = prev_pc;
- else if (sal.end < prologue_end)
- prologue_end = sal.end;
- This mechanism is very accurate so long as the optimizer
- doesn't move any instructions from the function body into the
- prologue. If this happens, sal.end will be the last
- instruction in the first hunk of prologue code just before
- the first instruction that the scheduler has moved from
- the body to the prologue.
- In order to make sure that we scan all of the prologue
- instructions, we use a slightly less accurate mechanism which
- may scan more than necessary. To help compensate for this
- lack of accuracy, the prologue scanning loop below contains
- several clauses which'll cause the loop to terminate early if
- an implausible prologue instruction is encountered.
- The expression
- prologue_start + 64
- is a suitable endpoint since it accounts for the largest
- possible prologue plus up to five instructions inserted by
- the scheduler. */
- if (prologue_end > prologue_start + 64)
- {
- prologue_end = prologue_start + 64; /* See above. */
- }
- }
- else
- {
- /* We have no symbol information. Our only option is to assume this
- function has a standard stack frame and the normal frame register.
- Then, we can find the value of our frame pointer on entrance to
- the callee (or at the present moment if this is the innermost frame).
- The value stored there should be the address of the stmfd + 8. */
- CORE_ADDR frame_loc;
- ULONGEST return_value;
- /* AAPCS does not use a frame register, so we can abort here. */
- if (tdep->arm_abi == ARM_ABI_AAPCS)
- return;
- frame_loc = get_frame_register_unsigned (this_frame, ARM_FP_REGNUM);
- if (!safe_read_memory_unsigned_integer (frame_loc, 4, byte_order,
- &return_value))
- return;
- else
- {
- prologue_start = gdbarch_addr_bits_remove
- (gdbarch, return_value) - 8;
- prologue_end = prologue_start + 64; /* See above. */
- }
- }
- if (prev_pc < prologue_end)
- prologue_end = prev_pc;
- arm_analyze_prologue (gdbarch, prologue_start, prologue_end, cache,
- target_arm_instruction_reader ());
- }
- static struct arm_prologue_cache *
- arm_make_prologue_cache (struct frame_info *this_frame)
- {
- int reg;
- struct arm_prologue_cache *cache;
- CORE_ADDR unwound_fp;
- cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
- cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
- arm_scan_prologue (this_frame, cache);
- unwound_fp = get_frame_register_unsigned (this_frame, cache->framereg);
- if (unwound_fp == 0)
- return cache;
- cache->prev_sp = unwound_fp + cache->framesize;
- /* Calculate actual addresses of saved registers using offsets
- determined by arm_scan_prologue. */
- for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++)
- if (cache->saved_regs[reg].is_addr ())
- cache->saved_regs[reg].set_addr (cache->saved_regs[reg].addr ()
- + cache->prev_sp);
- return cache;
- }
- /* Implementation of the stop_reason hook for arm_prologue frames. */
- static enum unwind_stop_reason
- arm_prologue_unwind_stop_reason (struct frame_info *this_frame,
- void **this_cache)
- {
- struct arm_prologue_cache *cache;
- CORE_ADDR pc;
- if (*this_cache == NULL)
- *this_cache = arm_make_prologue_cache (this_frame);
- cache = (struct arm_prologue_cache *) *this_cache;
- /* This is meant to halt the backtrace at "_start". */
- pc = get_frame_pc (this_frame);
- gdbarch *arch = get_frame_arch (this_frame);
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (arch);
- if (pc <= tdep->lowest_pc)
- return UNWIND_OUTERMOST;
- /* If we've hit a wall, stop. */
- if (cache->prev_sp == 0)
- return UNWIND_OUTERMOST;
- return UNWIND_NO_REASON;
- }
- /* Our frame ID for a normal frame is the current function's starting PC
- and the caller's SP when we were called. */
- static void
- arm_prologue_this_id (struct frame_info *this_frame,
- void **this_cache,
- struct frame_id *this_id)
- {
- struct arm_prologue_cache *cache;
- struct frame_id id;
- CORE_ADDR pc, func;
- if (*this_cache == NULL)
- *this_cache = arm_make_prologue_cache (this_frame);
- cache = (struct arm_prologue_cache *) *this_cache;
- /* Use function start address as part of the frame ID. If we cannot
- identify the start address (due to missing symbol information),
- fall back to just using the current PC. */
- pc = get_frame_pc (this_frame);
- func = get_frame_func (this_frame);
- if (!func)
- func = pc;
- id = frame_id_build (cache->prev_sp, func);
- *this_id = id;
- }
- static struct value *
- arm_prologue_prev_register (struct frame_info *this_frame,
- void **this_cache,
- int prev_regnum)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- struct arm_prologue_cache *cache;
- if (*this_cache == NULL)
- *this_cache = arm_make_prologue_cache (this_frame);
- cache = (struct arm_prologue_cache *) *this_cache;
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* If this frame has signed the return address, mark it as so. */
- if (tdep->have_pacbti && cache->ra_signed_state.has_value ()
- && *cache->ra_signed_state)
- set_frame_previous_pc_masked (this_frame);
- /* If we are asked to unwind the PC, then we need to return the LR
- instead. The prologue may save PC, but it will point into this
- frame's prologue, not the next frame's resume location. Also
- strip the saved T bit. A valid LR may have the low bit set, but
- a valid PC never does. */
- if (prev_regnum == ARM_PC_REGNUM)
- {
- CORE_ADDR lr;
- lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
- return frame_unwind_got_constant (this_frame, prev_regnum,
- arm_addr_bits_remove (gdbarch, lr));
- }
- /* SP is generally not saved to the stack, but this frame is
- identified by the next frame's stack pointer at the time of the call.
- The value was already reconstructed into PREV_SP. */
- if (prev_regnum == ARM_SP_REGNUM)
- return frame_unwind_got_constant (this_frame, prev_regnum, cache->prev_sp);
- /* The CPSR may have been changed by the call instruction and by the
- called function. The only bit we can reconstruct is the T bit,
- by checking the low bit of LR as of the call. This is a reliable
- indicator of Thumb-ness except for some ARM v4T pre-interworking
- Thumb code, which could get away with a clear low bit as long as
- the called function did not use bx. Guess that all other
- bits are unchanged; the condition flags are presumably lost,
- but the processor status is likely valid. */
- if (prev_regnum == ARM_PS_REGNUM)
- {
- CORE_ADDR lr, cpsr;
- ULONGEST t_bit = arm_psr_thumb_bit (gdbarch);
- cpsr = get_frame_register_unsigned (this_frame, prev_regnum);
- lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
- if (IS_THUMB_ADDR (lr))
- cpsr |= t_bit;
- else
- cpsr &= ~t_bit;
- return frame_unwind_got_constant (this_frame, prev_regnum, cpsr);
- }
- return trad_frame_get_prev_register (this_frame, cache->saved_regs,
- prev_regnum);
- }
- static frame_unwind arm_prologue_unwind = {
- "arm prologue",
- NORMAL_FRAME,
- arm_prologue_unwind_stop_reason,
- arm_prologue_this_id,
- arm_prologue_prev_register,
- NULL,
- default_frame_sniffer
- };
- /* Maintain a list of ARM exception table entries per objfile, similar to the
- list of mapping symbols. We only cache entries for standard ARM-defined
- personality routines; the cache will contain only the frame unwinding
- instructions associated with the entry (not the descriptors). */
- struct arm_exidx_entry
- {
- CORE_ADDR addr;
- gdb_byte *entry;
- bool operator< (const arm_exidx_entry &other) const
- {
- return addr < other.addr;
- }
- };
- struct arm_exidx_data
- {
- std::vector<std::vector<arm_exidx_entry>> section_maps;
- };
- /* Per-BFD key to store exception handling information. */
- static const struct bfd_key<arm_exidx_data> arm_exidx_data_key;
- static struct obj_section *
- arm_obj_section_from_vma (struct objfile *objfile, bfd_vma vma)
- {
- struct obj_section *osect;
- ALL_OBJFILE_OSECTIONS (objfile, osect)
- if (bfd_section_flags (osect->the_bfd_section) & SEC_ALLOC)
- {
- bfd_vma start, size;
- start = bfd_section_vma (osect->the_bfd_section);
- size = bfd_section_size (osect->the_bfd_section);
- if (start <= vma && vma < start + size)
- return osect;
- }
- return NULL;
- }
- /* Parse contents of exception table and exception index sections
- of OBJFILE, and fill in the exception table entry cache.
- For each entry that refers to a standard ARM-defined personality
- routine, extract the frame unwinding instructions (from either
- the index or the table section). The unwinding instructions
- are normalized by:
- - extracting them from the rest of the table data
- - converting to host endianness
- - appending the implicit 0xb0 ("Finish") code
- The extracted and normalized instructions are stored for later
- retrieval by the arm_find_exidx_entry routine. */
-
- static void
- arm_exidx_new_objfile (struct objfile *objfile)
- {
- struct arm_exidx_data *data;
- asection *exidx, *extab;
- bfd_vma exidx_vma = 0, extab_vma = 0;
- LONGEST i;
- /* If we've already touched this file, do nothing. */
- if (!objfile || arm_exidx_data_key.get (objfile->obfd) != NULL)
- return;
- /* Read contents of exception table and index. */
- exidx = bfd_get_section_by_name (objfile->obfd, ELF_STRING_ARM_unwind);
- gdb::byte_vector exidx_data;
- if (exidx)
- {
- exidx_vma = bfd_section_vma (exidx);
- exidx_data.resize (bfd_section_size (exidx));
- if (!bfd_get_section_contents (objfile->obfd, exidx,
- exidx_data.data (), 0,
- exidx_data.size ()))
- return;
- }
- extab = bfd_get_section_by_name (objfile->obfd, ".ARM.extab");
- gdb::byte_vector extab_data;
- if (extab)
- {
- extab_vma = bfd_section_vma (extab);
- extab_data.resize (bfd_section_size (extab));
- if (!bfd_get_section_contents (objfile->obfd, extab,
- extab_data.data (), 0,
- extab_data.size ()))
- return;
- }
- /* Allocate exception table data structure. */
- data = arm_exidx_data_key.emplace (objfile->obfd);
- data->section_maps.resize (objfile->obfd->section_count);
- /* Fill in exception table. */
- for (i = 0; i < exidx_data.size () / 8; i++)
- {
- struct arm_exidx_entry new_exidx_entry;
- bfd_vma idx = bfd_h_get_32 (objfile->obfd, exidx_data.data () + i * 8);
- bfd_vma val = bfd_h_get_32 (objfile->obfd,
- exidx_data.data () + i * 8 + 4);
- bfd_vma addr = 0, word = 0;
- int n_bytes = 0, n_words = 0;
- struct obj_section *sec;
- gdb_byte *entry = NULL;
- /* Extract address of start of function. */
- idx = ((idx & 0x7fffffff) ^ 0x40000000) - 0x40000000;
- idx += exidx_vma + i * 8;
- /* Find section containing function and compute section offset. */
- sec = arm_obj_section_from_vma (objfile, idx);
- if (sec == NULL)
- continue;
- idx -= bfd_section_vma (sec->the_bfd_section);
- /* Determine address of exception table entry. */
- if (val == 1)
- {
- /* EXIDX_CANTUNWIND -- no exception table entry present. */
- }
- else if ((val & 0xff000000) == 0x80000000)
- {
- /* Exception table entry embedded in .ARM.exidx
- -- must be short form. */
- word = val;
- n_bytes = 3;
- }
- else if (!(val & 0x80000000))
- {
- /* Exception table entry in .ARM.extab. */
- addr = ((val & 0x7fffffff) ^ 0x40000000) - 0x40000000;
- addr += exidx_vma + i * 8 + 4;
- if (addr >= extab_vma && addr + 4 <= extab_vma + extab_data.size ())
- {
- word = bfd_h_get_32 (objfile->obfd,
- extab_data.data () + addr - extab_vma);
- addr += 4;
- if ((word & 0xff000000) == 0x80000000)
- {
- /* Short form. */
- n_bytes = 3;
- }
- else if ((word & 0xff000000) == 0x81000000
- || (word & 0xff000000) == 0x82000000)
- {
- /* Long form. */
- n_bytes = 2;
- n_words = ((word >> 16) & 0xff);
- }
- else if (!(word & 0x80000000))
- {
- bfd_vma pers;
- struct obj_section *pers_sec;
- int gnu_personality = 0;
- /* Custom personality routine. */
- pers = ((word & 0x7fffffff) ^ 0x40000000) - 0x40000000;
- pers = UNMAKE_THUMB_ADDR (pers + addr - 4);
- /* Check whether we've got one of the variants of the
- GNU personality routines. */
- pers_sec = arm_obj_section_from_vma (objfile, pers);
- if (pers_sec)
- {
- static const char *personality[] =
- {
- "__gcc_personality_v0",
- "__gxx_personality_v0",
- "__gcj_personality_v0",
- "__gnu_objc_personality_v0",
- NULL
- };
- CORE_ADDR pc = pers + pers_sec->offset ();
- int k;
- for (k = 0; personality[k]; k++)
- if (lookup_minimal_symbol_by_pc_name
- (pc, personality[k], objfile))
- {
- gnu_personality = 1;
- break;
- }
- }
- /* If so, the next word contains a word count in the high
- byte, followed by the same unwind instructions as the
- pre-defined forms. */
- if (gnu_personality
- && addr + 4 <= extab_vma + extab_data.size ())
- {
- word = bfd_h_get_32 (objfile->obfd,
- (extab_data.data ()
- + addr - extab_vma));
- addr += 4;
- n_bytes = 3;
- n_words = ((word >> 24) & 0xff);
- }
- }
- }
- }
- /* Sanity check address. */
- if (n_words)
- if (addr < extab_vma
- || addr + 4 * n_words > extab_vma + extab_data.size ())
- n_words = n_bytes = 0;
- /* The unwind instructions reside in WORD (only the N_BYTES least
- significant bytes are valid), followed by N_WORDS words in the
- extab section starting at ADDR. */
- if (n_bytes || n_words)
- {
- gdb_byte *p = entry
- = (gdb_byte *) obstack_alloc (&objfile->objfile_obstack,
- n_bytes + n_words * 4 + 1);
- while (n_bytes--)
- *p++ = (gdb_byte) ((word >> (8 * n_bytes)) & 0xff);
- while (n_words--)
- {
- word = bfd_h_get_32 (objfile->obfd,
- extab_data.data () + addr - extab_vma);
- addr += 4;
- *p++ = (gdb_byte) ((word >> 24) & 0xff);
- *p++ = (gdb_byte) ((word >> 16) & 0xff);
- *p++ = (gdb_byte) ((word >> 8) & 0xff);
- *p++ = (gdb_byte) (word & 0xff);
- }
- /* Implied "Finish" to terminate the list. */
- *p++ = 0xb0;
- }
- /* Push entry onto vector. They are guaranteed to always
- appear in order of increasing addresses. */
- new_exidx_entry.addr = idx;
- new_exidx_entry.entry = entry;
- data->section_maps[sec->the_bfd_section->index].push_back
- (new_exidx_entry);
- }
- }
- /* Search for the exception table entry covering MEMADDR. If one is found,
- return a pointer to its data. Otherwise, return 0. If START is non-NULL,
- set *START to the start of the region covered by this entry. */
- static gdb_byte *
- arm_find_exidx_entry (CORE_ADDR memaddr, CORE_ADDR *start)
- {
- struct obj_section *sec;
- sec = find_pc_section (memaddr);
- if (sec != NULL)
- {
- struct arm_exidx_data *data;
- struct arm_exidx_entry map_key = { memaddr - sec->addr (), 0 };
- data = arm_exidx_data_key.get (sec->objfile->obfd);
- if (data != NULL)
- {
- std::vector<arm_exidx_entry> &map
- = data->section_maps[sec->the_bfd_section->index];
- if (!map.empty ())
- {
- auto idx = std::lower_bound (map.begin (), map.end (), map_key);
- /* std::lower_bound finds the earliest ordered insertion
- point. If the following symbol starts at this exact
- address, we use that; otherwise, the preceding
- exception table entry covers this address. */
- if (idx < map.end ())
- {
- if (idx->addr == map_key.addr)
- {
- if (start)
- *start = idx->addr + sec->addr ();
- return idx->entry;
- }
- }
- if (idx > map.begin ())
- {
- idx = idx - 1;
- if (start)
- *start = idx->addr + sec->addr ();
- return idx->entry;
- }
- }
- }
- }
- return NULL;
- }
- /* Given the current frame THIS_FRAME, and its associated frame unwinding
- instruction list from the ARM exception table entry ENTRY, allocate and
- return a prologue cache structure describing how to unwind this frame.
- Return NULL if the unwinding instruction list contains a "spare",
- "reserved" or "refuse to unwind" instruction as defined in section
- "9.3 Frame unwinding instructions" of the "Exception Handling ABI
- for the ARM Architecture" document. */
- static struct arm_prologue_cache *
- arm_exidx_fill_cache (struct frame_info *this_frame, gdb_byte *entry)
- {
- CORE_ADDR vsp = 0;
- int vsp_valid = 0;
- struct arm_prologue_cache *cache;
- cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
- cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
- for (;;)
- {
- gdb_byte insn;
- /* Whenever we reload SP, we actually have to retrieve its
- actual value in the current frame. */
- if (!vsp_valid)
- {
- if (cache->saved_regs[ARM_SP_REGNUM].is_realreg ())
- {
- int reg = cache->saved_regs[ARM_SP_REGNUM].realreg ();
- vsp = get_frame_register_unsigned (this_frame, reg);
- }
- else
- {
- CORE_ADDR addr = cache->saved_regs[ARM_SP_REGNUM].addr ();
- vsp = get_frame_memory_unsigned (this_frame, addr, 4);
- }
- vsp_valid = 1;
- }
- /* Decode next unwind instruction. */
- insn = *entry++;
- if ((insn & 0xc0) == 0)
- {
- int offset = insn & 0x3f;
- vsp += (offset << 2) + 4;
- }
- else if ((insn & 0xc0) == 0x40)
- {
- int offset = insn & 0x3f;
- vsp -= (offset << 2) + 4;
- }
- else if ((insn & 0xf0) == 0x80)
- {
- int mask = ((insn & 0xf) << 8) | *entry++;
- int i;
- /* The special case of an all-zero mask identifies
- "Refuse to unwind". We return NULL to fall back
- to the prologue analyzer. */
- if (mask == 0)
- return NULL;
- /* Pop registers r4..r15 under mask. */
- for (i = 0; i < 12; i++)
- if (mask & (1 << i))
- {
- cache->saved_regs[4 + i].set_addr (vsp);
- vsp += 4;
- }
- /* Special-case popping SP -- we need to reload vsp. */
- if (mask & (1 << (ARM_SP_REGNUM - 4)))
- vsp_valid = 0;
- }
- else if ((insn & 0xf0) == 0x90)
- {
- int reg = insn & 0xf;
- /* Reserved cases. */
- if (reg == ARM_SP_REGNUM || reg == ARM_PC_REGNUM)
- return NULL;
- /* Set SP from another register and mark VSP for reload. */
- cache->saved_regs[ARM_SP_REGNUM] = cache->saved_regs[reg];
- vsp_valid = 0;
- }
- else if ((insn & 0xf0) == 0xa0)
- {
- int count = insn & 0x7;
- int pop_lr = (insn & 0x8) != 0;
- int i;
- /* Pop r4..r[4+count]. */
- for (i = 0; i <= count; i++)
- {
- cache->saved_regs[4 + i].set_addr (vsp);
- vsp += 4;
- }
- /* If indicated by flag, pop LR as well. */
- if (pop_lr)
- {
- cache->saved_regs[ARM_LR_REGNUM].set_addr (vsp);
- vsp += 4;
- }
- }
- else if (insn == 0xb0)
- {
- /* We could only have updated PC by popping into it; if so, it
- will show up as address. Otherwise, copy LR into PC. */
- if (!cache->saved_regs[ARM_PC_REGNUM].is_addr ())
- cache->saved_regs[ARM_PC_REGNUM]
- = cache->saved_regs[ARM_LR_REGNUM];
- /* We're done. */
- break;
- }
- else if (insn == 0xb1)
- {
- int mask = *entry++;
- int i;
- /* All-zero mask and mask >= 16 is "spare". */
- if (mask == 0 || mask >= 16)
- return NULL;
- /* Pop r0..r3 under mask. */
- for (i = 0; i < 4; i++)
- if (mask & (1 << i))
- {
- cache->saved_regs[i].set_addr (vsp);
- vsp += 4;
- }
- }
- else if (insn == 0xb2)
- {
- ULONGEST offset = 0;
- unsigned shift = 0;
- do
- {
- offset |= (*entry & 0x7f) << shift;
- shift += 7;
- }
- while (*entry++ & 0x80);
- vsp += 0x204 + (offset << 2);
- }
- else if (insn == 0xb3)
- {
- int start = *entry >> 4;
- int count = (*entry++) & 0xf;
- int i;
- /* Only registers D0..D15 are valid here. */
- if (start + count >= 16)
- return NULL;
- /* Pop VFP double-precision registers D[start]..D[start+count]. */
- for (i = 0; i <= count; i++)
- {
- cache->saved_regs[ARM_D0_REGNUM + start + i].set_addr (vsp);
- vsp += 8;
- }
- /* Add an extra 4 bytes for FSTMFDX-style stack. */
- vsp += 4;
- }
- else if ((insn & 0xf8) == 0xb8)
- {
- int count = insn & 0x7;
- int i;
- /* Pop VFP double-precision registers D[8]..D[8+count]. */
- for (i = 0; i <= count; i++)
- {
- cache->saved_regs[ARM_D0_REGNUM + 8 + i].set_addr (vsp);
- vsp += 8;
- }
- /* Add an extra 4 bytes for FSTMFDX-style stack. */
- vsp += 4;
- }
- else if (insn == 0xc6)
- {
- int start = *entry >> 4;
- int count = (*entry++) & 0xf;
- int i;
- /* Only registers WR0..WR15 are valid. */
- if (start + count >= 16)
- return NULL;
- /* Pop iwmmx registers WR[start]..WR[start+count]. */
- for (i = 0; i <= count; i++)
- {
- cache->saved_regs[ARM_WR0_REGNUM + start + i].set_addr (vsp);
- vsp += 8;
- }
- }
- else if (insn == 0xc7)
- {
- int mask = *entry++;
- int i;
- /* All-zero mask and mask >= 16 is "spare". */
- if (mask == 0 || mask >= 16)
- return NULL;
- /* Pop iwmmx general-purpose registers WCGR0..WCGR3 under mask. */
- for (i = 0; i < 4; i++)
- if (mask & (1 << i))
- {
- cache->saved_regs[ARM_WCGR0_REGNUM + i].set_addr (vsp);
- vsp += 4;
- }
- }
- else if ((insn & 0xf8) == 0xc0)
- {
- int count = insn & 0x7;
- int i;
- /* Pop iwmmx registers WR[10]..WR[10+count]. */
- for (i = 0; i <= count; i++)
- {
- cache->saved_regs[ARM_WR0_REGNUM + 10 + i].set_addr (vsp);
- vsp += 8;
- }
- }
- else if (insn == 0xc8)
- {
- int start = *entry >> 4;
- int count = (*entry++) & 0xf;
- int i;
- /* Only registers D0..D31 are valid. */
- if (start + count >= 16)
- return NULL;
- /* Pop VFP double-precision registers
- D[16+start]..D[16+start+count]. */
- for (i = 0; i <= count; i++)
- {
- cache->saved_regs[ARM_D0_REGNUM + 16 + start + i].set_addr (vsp);
- vsp += 8;
- }
- }
- else if (insn == 0xc9)
- {
- int start = *entry >> 4;
- int count = (*entry++) & 0xf;
- int i;
- /* Pop VFP double-precision registers D[start]..D[start+count]. */
- for (i = 0; i <= count; i++)
- {
- cache->saved_regs[ARM_D0_REGNUM + start + i].set_addr (vsp);
- vsp += 8;
- }
- }
- else if ((insn & 0xf8) == 0xd0)
- {
- int count = insn & 0x7;
- int i;
- /* Pop VFP double-precision registers D[8]..D[8+count]. */
- for (i = 0; i <= count; i++)
- {
- cache->saved_regs[ARM_D0_REGNUM + 8 + i].set_addr (vsp);
- vsp += 8;
- }
- }
- else
- {
- /* Everything else is "spare". */
- return NULL;
- }
- }
- /* If we restore SP from a register, assume this was the frame register.
- Otherwise just fall back to SP as frame register. */
- if (cache->saved_regs[ARM_SP_REGNUM].is_realreg ())
- cache->framereg = cache->saved_regs[ARM_SP_REGNUM].realreg ();
- else
- cache->framereg = ARM_SP_REGNUM;
- /* Determine offset to previous frame. */
- cache->framesize
- = vsp - get_frame_register_unsigned (this_frame, cache->framereg);
- /* We already got the previous SP. */
- cache->prev_sp = vsp;
- return cache;
- }
- /* Unwinding via ARM exception table entries. Note that the sniffer
- already computes a filled-in prologue cache, which is then used
- with the same arm_prologue_this_id and arm_prologue_prev_register
- routines also used for prologue-parsing based unwinding. */
- static int
- arm_exidx_unwind_sniffer (const struct frame_unwind *self,
- struct frame_info *this_frame,
- void **this_prologue_cache)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- CORE_ADDR addr_in_block, exidx_region, func_start;
- struct arm_prologue_cache *cache;
- gdb_byte *entry;
- /* See if we have an ARM exception table entry covering this address. */
- addr_in_block = get_frame_address_in_block (this_frame);
- entry = arm_find_exidx_entry (addr_in_block, &exidx_region);
- if (!entry)
- return 0;
- /* The ARM exception table does not describe unwind information
- for arbitrary PC values, but is guaranteed to be correct only
- at call sites. We have to decide here whether we want to use
- ARM exception table information for this frame, or fall back
- to using prologue parsing. (Note that if we have DWARF CFI,
- this sniffer isn't even called -- CFI is always preferred.)
- Before we make this decision, however, we check whether we
- actually have *symbol* information for the current frame.
- If not, prologue parsing would not work anyway, so we might
- as well use the exception table and hope for the best. */
- if (find_pc_partial_function (addr_in_block, NULL, &func_start, NULL))
- {
- int exc_valid = 0;
- /* If the next frame is "normal", we are at a call site in this
- frame, so exception information is guaranteed to be valid. */
- if (get_next_frame (this_frame)
- && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME)
- exc_valid = 1;
- /* We also assume exception information is valid if we're currently
- blocked in a system call. The system library is supposed to
- ensure this, so that e.g. pthread cancellation works. */
- if (arm_frame_is_thumb (this_frame))
- {
- ULONGEST insn;
- if (safe_read_memory_unsigned_integer (get_frame_pc (this_frame) - 2,
- 2, byte_order_for_code, &insn)
- && (insn & 0xff00) == 0xdf00 /* svc */)
- exc_valid = 1;
- }
- else
- {
- ULONGEST insn;
- if (safe_read_memory_unsigned_integer (get_frame_pc (this_frame) - 4,
- 4, byte_order_for_code, &insn)
- && (insn & 0x0f000000) == 0x0f000000 /* svc */)
- exc_valid = 1;
- }
-
- /* Bail out if we don't know that exception information is valid. */
- if (!exc_valid)
- return 0;
- /* The ARM exception index does not mark the *end* of the region
- covered by the entry, and some functions will not have any entry.
- To correctly recognize the end of the covered region, the linker
- should have inserted dummy records with a CANTUNWIND marker.
- Unfortunately, current versions of GNU ld do not reliably do
- this, and thus we may have found an incorrect entry above.
- As a (temporary) sanity check, we only use the entry if it
- lies *within* the bounds of the function. Note that this check
- might reject perfectly valid entries that just happen to cover
- multiple functions; therefore this check ought to be removed
- once the linker is fixed. */
- if (func_start > exidx_region)
- return 0;
- }
- /* Decode the list of unwinding instructions into a prologue cache.
- Note that this may fail due to e.g. a "refuse to unwind" code. */
- cache = arm_exidx_fill_cache (this_frame, entry);
- if (!cache)
- return 0;
- *this_prologue_cache = cache;
- return 1;
- }
- struct frame_unwind arm_exidx_unwind = {
- "arm exidx",
- NORMAL_FRAME,
- default_frame_unwind_stop_reason,
- arm_prologue_this_id,
- arm_prologue_prev_register,
- NULL,
- arm_exidx_unwind_sniffer
- };
- static struct arm_prologue_cache *
- arm_make_epilogue_frame_cache (struct frame_info *this_frame)
- {
- struct arm_prologue_cache *cache;
- int reg;
- cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
- cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
- /* Still rely on the offset calculated from prologue. */
- arm_scan_prologue (this_frame, cache);
- /* Since we are in epilogue, the SP has been restored. */
- cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
- /* Calculate actual addresses of saved registers using offsets
- determined by arm_scan_prologue. */
- for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++)
- if (cache->saved_regs[reg].is_addr ())
- cache->saved_regs[reg].set_addr (cache->saved_regs[reg].addr ()
- + cache->prev_sp);
- return cache;
- }
- /* Implementation of function hook 'this_id' in
- 'struct frame_uwnind' for epilogue unwinder. */
- static void
- arm_epilogue_frame_this_id (struct frame_info *this_frame,
- void **this_cache,
- struct frame_id *this_id)
- {
- struct arm_prologue_cache *cache;
- CORE_ADDR pc, func;
- if (*this_cache == NULL)
- *this_cache = arm_make_epilogue_frame_cache (this_frame);
- cache = (struct arm_prologue_cache *) *this_cache;
- /* Use function start address as part of the frame ID. If we cannot
- identify the start address (due to missing symbol information),
- fall back to just using the current PC. */
- pc = get_frame_pc (this_frame);
- func = get_frame_func (this_frame);
- if (func == 0)
- func = pc;
- (*this_id) = frame_id_build (cache->prev_sp, pc);
- }
- /* Implementation of function hook 'prev_register' in
- 'struct frame_uwnind' for epilogue unwinder. */
- static struct value *
- arm_epilogue_frame_prev_register (struct frame_info *this_frame,
- void **this_cache, int regnum)
- {
- if (*this_cache == NULL)
- *this_cache = arm_make_epilogue_frame_cache (this_frame);
- return arm_prologue_prev_register (this_frame, this_cache, regnum);
- }
- static int arm_stack_frame_destroyed_p_1 (struct gdbarch *gdbarch,
- CORE_ADDR pc);
- static int thumb_stack_frame_destroyed_p (struct gdbarch *gdbarch,
- CORE_ADDR pc);
- /* Implementation of function hook 'sniffer' in
- 'struct frame_uwnind' for epilogue unwinder. */
- static int
- arm_epilogue_frame_sniffer (const struct frame_unwind *self,
- struct frame_info *this_frame,
- void **this_prologue_cache)
- {
- if (frame_relative_level (this_frame) == 0)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- CORE_ADDR pc = get_frame_pc (this_frame);
- if (arm_frame_is_thumb (this_frame))
- return thumb_stack_frame_destroyed_p (gdbarch, pc);
- else
- return arm_stack_frame_destroyed_p_1 (gdbarch, pc);
- }
- else
- return 0;
- }
- /* Frame unwinder from epilogue. */
- static const struct frame_unwind arm_epilogue_frame_unwind =
- {
- "arm epilogue",
- NORMAL_FRAME,
- default_frame_unwind_stop_reason,
- arm_epilogue_frame_this_id,
- arm_epilogue_frame_prev_register,
- NULL,
- arm_epilogue_frame_sniffer,
- };
- /* Recognize GCC's trampoline for thumb call-indirect. If we are in a
- trampoline, return the target PC. Otherwise return 0.
- void call0a (char c, short s, int i, long l) {}
- int main (void)
- {
- (*pointer_to_call0a) (c, s, i, l);
- }
- Instead of calling a stub library function _call_via_xx (xx is
- the register name), GCC may inline the trampoline in the object
- file as below (register r2 has the address of call0a).
- .global main
- .type main, %function
- ...
- bl .L1
- ...
- .size main, .-main
- .L1:
- bx r2
- The trampoline 'bx r2' doesn't belong to main. */
- static CORE_ADDR
- arm_skip_bx_reg (struct frame_info *frame, CORE_ADDR pc)
- {
- /* The heuristics of recognizing such trampoline is that FRAME is
- executing in Thumb mode and the instruction on PC is 'bx Rm'. */
- if (arm_frame_is_thumb (frame))
- {
- gdb_byte buf[2];
- if (target_read_memory (pc, buf, 2) == 0)
- {
- struct gdbarch *gdbarch = get_frame_arch (frame);
- enum bfd_endian byte_order_for_code
- = gdbarch_byte_order_for_code (gdbarch);
- uint16_t insn
- = extract_unsigned_integer (buf, 2, byte_order_for_code);
- if ((insn & 0xff80) == 0x4700) /* bx <Rm> */
- {
- CORE_ADDR dest
- = get_frame_register_unsigned (frame, bits (insn, 3, 6));
- /* Clear the LSB so that gdb core sets step-resume
- breakpoint at the right address. */
- return UNMAKE_THUMB_ADDR (dest);
- }
- }
- }
- return 0;
- }
- static struct arm_prologue_cache *
- arm_make_stub_cache (struct frame_info *this_frame)
- {
- struct arm_prologue_cache *cache;
- cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
- cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
- cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
- return cache;
- }
- /* Our frame ID for a stub frame is the current SP and LR. */
- static void
- arm_stub_this_id (struct frame_info *this_frame,
- void **this_cache,
- struct frame_id *this_id)
- {
- struct arm_prologue_cache *cache;
- if (*this_cache == NULL)
- *this_cache = arm_make_stub_cache (this_frame);
- cache = (struct arm_prologue_cache *) *this_cache;
- *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame));
- }
- static int
- arm_stub_unwind_sniffer (const struct frame_unwind *self,
- struct frame_info *this_frame,
- void **this_prologue_cache)
- {
- CORE_ADDR addr_in_block;
- gdb_byte dummy[4];
- CORE_ADDR pc, start_addr;
- const char *name;
- addr_in_block = get_frame_address_in_block (this_frame);
- pc = get_frame_pc (this_frame);
- if (in_plt_section (addr_in_block)
- /* We also use the stub winder if the target memory is unreadable
- to avoid having the prologue unwinder trying to read it. */
- || target_read_memory (pc, dummy, 4) != 0)
- return 1;
- if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0
- && arm_skip_bx_reg (this_frame, pc) != 0)
- return 1;
- return 0;
- }
- struct frame_unwind arm_stub_unwind = {
- "arm stub",
- NORMAL_FRAME,
- default_frame_unwind_stop_reason,
- arm_stub_this_id,
- arm_prologue_prev_register,
- NULL,
- arm_stub_unwind_sniffer
- };
- /* Put here the code to store, into CACHE->saved_regs, the addresses
- of the saved registers of frame described by THIS_FRAME. CACHE is
- returned. */
- static struct arm_prologue_cache *
- arm_m_exception_cache (struct frame_info *this_frame)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- struct arm_prologue_cache *cache;
- CORE_ADDR lr;
- CORE_ADDR sp;
- CORE_ADDR unwound_sp;
- LONGEST xpsr;
- uint32_t exc_return;
- uint32_t process_stack_used;
- uint32_t extended_frame_used;
- uint32_t secure_stack_used;
- cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
- cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
- /* ARMv7-M Architecture Reference "B1.5.6 Exception entry behavior"
- describes which bits in LR that define which stack was used prior
- to the exception and if FPU is used (causing extended stack frame). */
- lr = get_frame_register_unsigned (this_frame, ARM_LR_REGNUM);
- sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
- /* Check EXC_RETURN indicator bits. */
- exc_return = (((lr >> 28) & 0xf) == 0xf);
- /* Check EXC_RETURN bit SPSEL if Main or Thread (process) stack used. */
- process_stack_used = ((lr & (1 << 2)) != 0);
- if (exc_return && process_stack_used)
- {
- /* Thread (process) stack used.
- Potentially this could be other register defined by target, but PSP
- can be considered a standard name for the "Process Stack Pointer".
- To be fully aware of system registers like MSP and PSP, these could
- be added to a separate XML arm-m-system-profile that is valid for
- ARMv6-M and ARMv7-M architectures. Also to be able to debug eg a
- corefile off-line, then these registers must be defined by GDB,
- and also be included in the corefile regsets. */
- int psp_regnum = user_reg_map_name_to_regnum (gdbarch, "psp", -1);
- if (psp_regnum == -1)
- {
- /* Thread (process) stack could not be fetched,
- give warning and exit. */
- warning (_("no PSP thread stack unwinding supported."));
- /* Terminate any further stack unwinding by refer to self. */
- cache->prev_sp = sp;
- return cache;
- }
- else
- {
- /* Thread (process) stack used, use PSP as SP. */
- unwound_sp = get_frame_register_unsigned (this_frame, psp_regnum);
- }
- }
- else
- {
- /* Main stack used, use MSP as SP. */
- unwound_sp = sp;
- }
- /* The hardware saves eight 32-bit words, comprising xPSR,
- ReturnAddress, LR (R14), R12, R3, R2, R1, R0. See details in
- "B1.5.6 Exception entry behavior" in
- "ARMv7-M Architecture Reference Manual". */
- cache->saved_regs[0].set_addr (unwound_sp);
- cache->saved_regs[1].set_addr (unwound_sp + 4);
- cache->saved_regs[2].set_addr (unwound_sp + 8);
- cache->saved_regs[3].set_addr (unwound_sp + 12);
- cache->saved_regs[ARM_IP_REGNUM].set_addr (unwound_sp + 16);
- cache->saved_regs[ARM_LR_REGNUM].set_addr (unwound_sp + 20);
- cache->saved_regs[ARM_PC_REGNUM].set_addr (unwound_sp + 24);
- cache->saved_regs[ARM_PS_REGNUM].set_addr (unwound_sp + 28);
- /* Check EXC_RETURN bit FTYPE if extended stack frame (FPU regs stored)
- type used. */
- extended_frame_used = ((lr & (1 << 4)) == 0);
- if (exc_return && extended_frame_used)
- {
- int i;
- int fpu_regs_stack_offset;
- /* This code does not take into account the lazy stacking, see "Lazy
- context save of FP state", in B1.5.7, also ARM AN298, supported
- by Cortex-M4F architecture.
- To fully handle this the FPCCR register (Floating-point Context
- Control Register) needs to be read out and the bits ASPEN and LSPEN
- could be checked to setup correct lazy stacked FP registers.
- This register is located at address 0xE000EF34. */
- /* Extended stack frame type used. */
- fpu_regs_stack_offset = unwound_sp + 0x20;
- for (i = 0; i < 16; i++)
- {
- cache->saved_regs[ARM_D0_REGNUM + i].set_addr (fpu_regs_stack_offset);
- fpu_regs_stack_offset += 4;
- }
- cache->saved_regs[ARM_FPSCR_REGNUM].set_addr (unwound_sp + 0x60);
- /* Offset 0x64 is reserved. */
- cache->prev_sp = unwound_sp + 0x68;
- }
- else
- {
- /* Standard stack frame type used. */
- cache->prev_sp = unwound_sp + 0x20;
- }
- /* Check EXC_RETURN bit S if Secure or Non-secure stack used. */
- secure_stack_used = ((lr & (1 << 6)) != 0);
- if (exc_return && secure_stack_used)
- {
- /* ARMv8-M Exception and interrupt handling is not considered here.
- In the ARMv8-M architecture also EXC_RETURN bit S is controlling if
- the Secure or Non-secure stack was used. To separate Secure and
- Non-secure stacks, processors that are based on the ARMv8-M
- architecture support 4 stack pointers: MSP_S, PSP_S, MSP_NS, PSP_NS.
- In addition, a stack limit feature is provided using stack limit
- registers (accessible using MSR and MRS instructions) in Privileged
- level. */
- }
- /* If bit 9 of the saved xPSR is set, then there is a four-byte
- aligner between the top of the 32-byte stack frame and the
- previous context's stack pointer. */
- if (safe_read_memory_integer (unwound_sp + 28, 4, byte_order, &xpsr)
- && (xpsr & (1 << 9)) != 0)
- cache->prev_sp += 4;
- return cache;
- }
- /* Implementation of function hook 'this_id' in
- 'struct frame_uwnind'. */
- static void
- arm_m_exception_this_id (struct frame_info *this_frame,
- void **this_cache,
- struct frame_id *this_id)
- {
- struct arm_prologue_cache *cache;
- if (*this_cache == NULL)
- *this_cache = arm_m_exception_cache (this_frame);
- cache = (struct arm_prologue_cache *) *this_cache;
- /* Our frame ID for a stub frame is the current SP and LR. */
- *this_id = frame_id_build (cache->prev_sp,
- get_frame_pc (this_frame));
- }
- /* Implementation of function hook 'prev_register' in
- 'struct frame_uwnind'. */
- static struct value *
- arm_m_exception_prev_register (struct frame_info *this_frame,
- void **this_cache,
- int prev_regnum)
- {
- struct arm_prologue_cache *cache;
- if (*this_cache == NULL)
- *this_cache = arm_m_exception_cache (this_frame);
- cache = (struct arm_prologue_cache *) *this_cache;
- /* The value was already reconstructed into PREV_SP. */
- if (prev_regnum == ARM_SP_REGNUM)
- return frame_unwind_got_constant (this_frame, prev_regnum,
- cache->prev_sp);
- return trad_frame_get_prev_register (this_frame, cache->saved_regs,
- prev_regnum);
- }
- /* Implementation of function hook 'sniffer' in
- 'struct frame_uwnind'. */
- static int
- arm_m_exception_unwind_sniffer (const struct frame_unwind *self,
- struct frame_info *this_frame,
- void **this_prologue_cache)
- {
- CORE_ADDR this_pc = get_frame_pc (this_frame);
- /* No need to check is_m; this sniffer is only registered for
- M-profile architectures. */
- /* Check if exception frame returns to a magic PC value. */
- return arm_m_addr_is_magic (this_pc);
- }
- /* Frame unwinder for M-profile exceptions. */
- struct frame_unwind arm_m_exception_unwind =
- {
- "arm m exception",
- SIGTRAMP_FRAME,
- default_frame_unwind_stop_reason,
- arm_m_exception_this_id,
- arm_m_exception_prev_register,
- NULL,
- arm_m_exception_unwind_sniffer
- };
- static CORE_ADDR
- arm_normal_frame_base (struct frame_info *this_frame, void **this_cache)
- {
- struct arm_prologue_cache *cache;
- if (*this_cache == NULL)
- *this_cache = arm_make_prologue_cache (this_frame);
- cache = (struct arm_prologue_cache *) *this_cache;
- return cache->prev_sp - cache->framesize;
- }
- struct frame_base arm_normal_base = {
- &arm_prologue_unwind,
- arm_normal_frame_base,
- arm_normal_frame_base,
- arm_normal_frame_base
- };
- static struct value *
- arm_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache,
- int regnum)
- {
- struct gdbarch * gdbarch = get_frame_arch (this_frame);
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- CORE_ADDR lr, cpsr;
- ULONGEST t_bit = arm_psr_thumb_bit (gdbarch);
- switch (regnum)
- {
- case ARM_PC_REGNUM:
- /* The PC is normally copied from the return column, which
- describes saves of LR. However, that version may have an
- extra bit set to indicate Thumb state. The bit is not
- part of the PC. */
- /* Record in the frame whether the return address was signed. */
- if (tdep->have_pacbti)
- {
- CORE_ADDR ra_auth_code
- = frame_unwind_register_unsigned (this_frame,
- tdep->pacbti_pseudo_base);
- if (ra_auth_code != 0)
- set_frame_previous_pc_masked (this_frame);
- }
- lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
- return frame_unwind_got_constant (this_frame, regnum,
- arm_addr_bits_remove (gdbarch, lr));
- case ARM_PS_REGNUM:
- /* Reconstruct the T bit; see arm_prologue_prev_register for details. */
- cpsr = get_frame_register_unsigned (this_frame, regnum);
- lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
- if (IS_THUMB_ADDR (lr))
- cpsr |= t_bit;
- else
- cpsr &= ~t_bit;
- return frame_unwind_got_constant (this_frame, regnum, cpsr);
- default:
- internal_error (__FILE__, __LINE__,
- _("Unexpected register %d"), regnum);
- }
- }
- /* Implement the stack_frame_destroyed_p gdbarch method. */
- static int
- thumb_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- unsigned int insn, insn2;
- int found_return = 0, found_stack_adjust = 0;
- CORE_ADDR func_start, func_end;
- CORE_ADDR scan_pc;
- gdb_byte buf[4];
- if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
- return 0;
- /* The epilogue is a sequence of instructions along the following lines:
- - add stack frame size to SP or FP
- - [if frame pointer used] restore SP from FP
- - restore registers from SP [may include PC]
- - a return-type instruction [if PC wasn't already restored]
- In a first pass, we scan forward from the current PC and verify the
- instructions we find as compatible with this sequence, ending in a
- return instruction.
- However, this is not sufficient to distinguish indirect function calls
- within a function from indirect tail calls in the epilogue in some cases.
- Therefore, if we didn't already find any SP-changing instruction during
- forward scan, we add a backward scanning heuristic to ensure we actually
- are in the epilogue. */
- scan_pc = pc;
- while (scan_pc < func_end && !found_return)
- {
- if (target_read_memory (scan_pc, buf, 2))
- break;
- scan_pc += 2;
- insn = extract_unsigned_integer (buf, 2, byte_order_for_code);
- if ((insn & 0xff80) == 0x4700) /* bx <Rm> */
- found_return = 1;
- else if (insn == 0x46f7) /* mov pc, lr */
- found_return = 1;
- else if (thumb_instruction_restores_sp (insn))
- {
- if ((insn & 0xff00) == 0xbd00) /* pop <registers, PC> */
- found_return = 1;
- }
- else if (thumb_insn_size (insn) == 4) /* 32-bit Thumb-2 instruction */
- {
- if (target_read_memory (scan_pc, buf, 2))
- break;
- scan_pc += 2;
- insn2 = extract_unsigned_integer (buf, 2, byte_order_for_code);
- if (insn == 0xe8bd) /* ldm.w sp!, <registers> */
- {
- if (insn2 & 0x8000) /* <registers> include PC. */
- found_return = 1;
- }
- else if (insn == 0xf85d /* ldr.w <Rt>, [sp], #4 */
- && (insn2 & 0x0fff) == 0x0b04)
- {
- if ((insn2 & 0xf000) == 0xf000) /* <Rt> is PC. */
- found_return = 1;
- }
- else if ((insn & 0xffbf) == 0xecbd /* vldm sp!, <list> */
- && (insn2 & 0x0e00) == 0x0a00)
- ;
- else
- break;
- }
- else
- break;
- }
- if (!found_return)
- return 0;
- /* Since any instruction in the epilogue sequence, with the possible
- exception of return itself, updates the stack pointer, we need to
- scan backwards for at most one instruction. Try either a 16-bit or
- a 32-bit instruction. This is just a heuristic, so we do not worry
- too much about false positives. */
- if (pc - 4 < func_start)
- return 0;
- if (target_read_memory (pc - 4, buf, 4))
- return 0;
- insn = extract_unsigned_integer (buf, 2, byte_order_for_code);
- insn2 = extract_unsigned_integer (buf + 2, 2, byte_order_for_code);
- if (thumb_instruction_restores_sp (insn2))
- found_stack_adjust = 1;
- else if (insn == 0xe8bd) /* ldm.w sp!, <registers> */
- found_stack_adjust = 1;
- else if (insn == 0xf85d /* ldr.w <Rt>, [sp], #4 */
- && (insn2 & 0x0fff) == 0x0b04)
- found_stack_adjust = 1;
- else if ((insn & 0xffbf) == 0xecbd /* vldm sp!, <list> */
- && (insn2 & 0x0e00) == 0x0a00)
- found_stack_adjust = 1;
- return found_stack_adjust;
- }
- static int
- arm_stack_frame_destroyed_p_1 (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- unsigned int insn;
- int found_return;
- CORE_ADDR func_start, func_end;
- if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
- return 0;
- /* We are in the epilogue if the previous instruction was a stack
- adjustment and the next instruction is a possible return (bx, mov
- pc, or pop). We could have to scan backwards to find the stack
- adjustment, or forwards to find the return, but this is a decent
- approximation. First scan forwards. */
- found_return = 0;
- insn = read_memory_unsigned_integer (pc, 4, byte_order_for_code);
- if (bits (insn, 28, 31) != INST_NV)
- {
- if ((insn & 0x0ffffff0) == 0x012fff10)
- /* BX. */
- found_return = 1;
- else if ((insn & 0x0ffffff0) == 0x01a0f000)
- /* MOV PC. */
- found_return = 1;
- else if ((insn & 0x0fff0000) == 0x08bd0000
- && (insn & 0x0000c000) != 0)
- /* POP (LDMIA), including PC or LR. */
- found_return = 1;
- }
- if (!found_return)
- return 0;
- /* Scan backwards. This is just a heuristic, so do not worry about
- false positives from mode changes. */
- if (pc < func_start + 4)
- return 0;
- insn = read_memory_unsigned_integer (pc - 4, 4, byte_order_for_code);
- if (arm_instruction_restores_sp (insn))
- return 1;
- return 0;
- }
- /* Implement the stack_frame_destroyed_p gdbarch method. */
- static int
- arm_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- if (arm_pc_is_thumb (gdbarch, pc))
- return thumb_stack_frame_destroyed_p (gdbarch, pc);
- else
- return arm_stack_frame_destroyed_p_1 (gdbarch, pc);
- }
- /* When arguments must be pushed onto the stack, they go on in reverse
- order. The code below implements a FILO (stack) to do this. */
- struct stack_item
- {
- int len;
- struct stack_item *prev;
- gdb_byte *data;
- };
- static struct stack_item *
- push_stack_item (struct stack_item *prev, const gdb_byte *contents, int len)
- {
- struct stack_item *si;
- si = XNEW (struct stack_item);
- si->data = (gdb_byte *) xmalloc (len);
- si->len = len;
- si->prev = prev;
- memcpy (si->data, contents, len);
- return si;
- }
- static struct stack_item *
- pop_stack_item (struct stack_item *si)
- {
- struct stack_item *dead = si;
- si = si->prev;
- xfree (dead->data);
- xfree (dead);
- return si;
- }
- /* Implement the gdbarch type alignment method, overrides the generic
- alignment algorithm for anything that is arm specific. */
- static ULONGEST
- arm_type_align (gdbarch *gdbarch, struct type *t)
- {
- t = check_typedef (t);
- if (t->code () == TYPE_CODE_ARRAY && t->is_vector ())
- {
- /* Use the natural alignment for vector types (the same for
- scalar type), but the maximum alignment is 64-bit. */
- if (TYPE_LENGTH (t) > 8)
- return 8;
- else
- return TYPE_LENGTH (t);
- }
- /* Allow the common code to calculate the alignment. */
- return 0;
- }
- /* Possible base types for a candidate for passing and returning in
- VFP registers. */
- enum arm_vfp_cprc_base_type
- {
- VFP_CPRC_UNKNOWN,
- VFP_CPRC_SINGLE,
- VFP_CPRC_DOUBLE,
- VFP_CPRC_VEC64,
- VFP_CPRC_VEC128
- };
- /* The length of one element of base type B. */
- static unsigned
- arm_vfp_cprc_unit_length (enum arm_vfp_cprc_base_type b)
- {
- switch (b)
- {
- case VFP_CPRC_SINGLE:
- return 4;
- case VFP_CPRC_DOUBLE:
- return 8;
- case VFP_CPRC_VEC64:
- return 8;
- case VFP_CPRC_VEC128:
- return 16;
- default:
- internal_error (__FILE__, __LINE__, _("Invalid VFP CPRC type: %d."),
- (int) b);
- }
- }
- /* The character ('s', 'd' or 'q') for the type of VFP register used
- for passing base type B. */
- static int
- arm_vfp_cprc_reg_char (enum arm_vfp_cprc_base_type b)
- {
- switch (b)
- {
- case VFP_CPRC_SINGLE:
- return 's';
- case VFP_CPRC_DOUBLE:
- return 'd';
- case VFP_CPRC_VEC64:
- return 'd';
- case VFP_CPRC_VEC128:
- return 'q';
- default:
- internal_error (__FILE__, __LINE__, _("Invalid VFP CPRC type: %d."),
- (int) b);
- }
- }
- /* Determine whether T may be part of a candidate for passing and
- returning in VFP registers, ignoring the limit on the total number
- of components. If *BASE_TYPE is VFP_CPRC_UNKNOWN, set it to the
- classification of the first valid component found; if it is not
- VFP_CPRC_UNKNOWN, all components must have the same classification
- as *BASE_TYPE. If it is found that T contains a type not permitted
- for passing and returning in VFP registers, a type differently
- classified from *BASE_TYPE, or two types differently classified
- from each other, return -1, otherwise return the total number of
- base-type elements found (possibly 0 in an empty structure or
- array). Vector types are not currently supported, matching the
- generic AAPCS support. */
- static int
- arm_vfp_cprc_sub_candidate (struct type *t,
- enum arm_vfp_cprc_base_type *base_type)
- {
- t = check_typedef (t);
- switch (t->code ())
- {
- case TYPE_CODE_FLT:
- switch (TYPE_LENGTH (t))
- {
- case 4:
- if (*base_type == VFP_CPRC_UNKNOWN)
- *base_type = VFP_CPRC_SINGLE;
- else if (*base_type != VFP_CPRC_SINGLE)
- return -1;
- return 1;
- case 8:
- if (*base_type == VFP_CPRC_UNKNOWN)
- *base_type = VFP_CPRC_DOUBLE;
- else if (*base_type != VFP_CPRC_DOUBLE)
- return -1;
- return 1;
- default:
- return -1;
- }
- break;
- case TYPE_CODE_COMPLEX:
- /* Arguments of complex T where T is one of the types float or
- double get treated as if they are implemented as:
- struct complexT
- {
- T real;
- T imag;
- };
- */
- switch (TYPE_LENGTH (t))
- {
- case 8:
- if (*base_type == VFP_CPRC_UNKNOWN)
- *base_type = VFP_CPRC_SINGLE;
- else if (*base_type != VFP_CPRC_SINGLE)
- return -1;
- return 2;
- case 16:
- if (*base_type == VFP_CPRC_UNKNOWN)
- *base_type = VFP_CPRC_DOUBLE;
- else if (*base_type != VFP_CPRC_DOUBLE)
- return -1;
- return 2;
- default:
- return -1;
- }
- break;
- case TYPE_CODE_ARRAY:
- {
- if (t->is_vector ())
- {
- /* A 64-bit or 128-bit containerized vector type are VFP
- CPRCs. */
- switch (TYPE_LENGTH (t))
- {
- case 8:
- if (*base_type == VFP_CPRC_UNKNOWN)
- *base_type = VFP_CPRC_VEC64;
- return 1;
- case 16:
- if (*base_type == VFP_CPRC_UNKNOWN)
- *base_type = VFP_CPRC_VEC128;
- return 1;
- default:
- return -1;
- }
- }
- else
- {
- int count;
- unsigned unitlen;
- count = arm_vfp_cprc_sub_candidate (TYPE_TARGET_TYPE (t),
- base_type);
- if (count == -1)
- return -1;
- if (TYPE_LENGTH (t) == 0)
- {
- gdb_assert (count == 0);
- return 0;
- }
- else if (count == 0)
- return -1;
- unitlen = arm_vfp_cprc_unit_length (*base_type);
- gdb_assert ((TYPE_LENGTH (t) % unitlen) == 0);
- return TYPE_LENGTH (t) / unitlen;
- }
- }
- break;
- case TYPE_CODE_STRUCT:
- {
- int count = 0;
- unsigned unitlen;
- int i;
- for (i = 0; i < t->num_fields (); i++)
- {
- int sub_count = 0;
- if (!field_is_static (&t->field (i)))
- sub_count = arm_vfp_cprc_sub_candidate (t->field (i).type (),
- base_type);
- if (sub_count == -1)
- return -1;
- count += sub_count;
- }
- if (TYPE_LENGTH (t) == 0)
- {
- gdb_assert (count == 0);
- return 0;
- }
- else if (count == 0)
- return -1;
- unitlen = arm_vfp_cprc_unit_length (*base_type);
- if (TYPE_LENGTH (t) != unitlen * count)
- return -1;
- return count;
- }
- case TYPE_CODE_UNION:
- {
- int count = 0;
- unsigned unitlen;
- int i;
- for (i = 0; i < t->num_fields (); i++)
- {
- int sub_count = arm_vfp_cprc_sub_candidate (t->field (i).type (),
- base_type);
- if (sub_count == -1)
- return -1;
- count = (count > sub_count ? count : sub_count);
- }
- if (TYPE_LENGTH (t) == 0)
- {
- gdb_assert (count == 0);
- return 0;
- }
- else if (count == 0)
- return -1;
- unitlen = arm_vfp_cprc_unit_length (*base_type);
- if (TYPE_LENGTH (t) != unitlen * count)
- return -1;
- return count;
- }
- default:
- break;
- }
- return -1;
- }
- /* Determine whether T is a VFP co-processor register candidate (CPRC)
- if passed to or returned from a non-variadic function with the VFP
- ABI in effect. Return 1 if it is, 0 otherwise. If it is, set
- *BASE_TYPE to the base type for T and *COUNT to the number of
- elements of that base type before returning. */
- static int
- arm_vfp_call_candidate (struct type *t, enum arm_vfp_cprc_base_type *base_type,
- int *count)
- {
- enum arm_vfp_cprc_base_type b = VFP_CPRC_UNKNOWN;
- int c = arm_vfp_cprc_sub_candidate (t, &b);
- if (c <= 0 || c > 4)
- return 0;
- *base_type = b;
- *count = c;
- return 1;
- }
- /* Return 1 if the VFP ABI should be used for passing arguments to and
- returning values from a function of type FUNC_TYPE, 0
- otherwise. */
- static int
- arm_vfp_abi_for_function (struct gdbarch *gdbarch, struct type *func_type)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* Variadic functions always use the base ABI. Assume that functions
- without debug info are not variadic. */
- if (func_type && check_typedef (func_type)->has_varargs ())
- return 0;
- /* The VFP ABI is only supported as a variant of AAPCS. */
- if (tdep->arm_abi != ARM_ABI_AAPCS)
- return 0;
- return tdep->fp_model == ARM_FLOAT_VFP;
- }
- /* We currently only support passing parameters in integer registers, which
- conforms with GCC's default model, and VFP argument passing following
- the VFP variant of AAPCS. Several other variants exist and
- we should probably support some of them based on the selected ABI. */
- static CORE_ADDR
- arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
- struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
- struct value **args, CORE_ADDR sp,
- function_call_return_method return_method,
- CORE_ADDR struct_addr)
- {
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- int argnum;
- int argreg;
- int nstack;
- struct stack_item *si = NULL;
- int use_vfp_abi;
- struct type *ftype;
- unsigned vfp_regs_free = (1 << 16) - 1;
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* Determine the type of this function and whether the VFP ABI
- applies. */
- ftype = check_typedef (value_type (function));
- if (ftype->code () == TYPE_CODE_PTR)
- ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
- use_vfp_abi = arm_vfp_abi_for_function (gdbarch, ftype);
- /* Set the return address. For the ARM, the return breakpoint is
- always at BP_ADDR. */
- if (arm_pc_is_thumb (gdbarch, bp_addr))
- bp_addr |= 1;
- regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr);
- /* Walk through the list of args and determine how large a temporary
- stack is required. Need to take care here as structs may be
- passed on the stack, and we have to push them. */
- nstack = 0;
- argreg = ARM_A1_REGNUM;
- nstack = 0;
- /* The struct_return pointer occupies the first parameter
- passing register. */
- if (return_method == return_method_struct)
- {
- arm_debug_printf ("struct return in %s = %s",
- gdbarch_register_name (gdbarch, argreg),
- paddress (gdbarch, struct_addr));
- regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
- argreg++;
- }
- for (argnum = 0; argnum < nargs; argnum++)
- {
- int len;
- struct type *arg_type;
- struct type *target_type;
- enum type_code typecode;
- const bfd_byte *val;
- int align;
- enum arm_vfp_cprc_base_type vfp_base_type;
- int vfp_base_count;
- int may_use_core_reg = 1;
- arg_type = check_typedef (value_type (args[argnum]));
- len = TYPE_LENGTH (arg_type);
- target_type = TYPE_TARGET_TYPE (arg_type);
- typecode = arg_type->code ();
- val = value_contents (args[argnum]).data ();
- align = type_align (arg_type);
- /* Round alignment up to a whole number of words. */
- align = (align + ARM_INT_REGISTER_SIZE - 1)
- & ~(ARM_INT_REGISTER_SIZE - 1);
- /* Different ABIs have different maximum alignments. */
- if (tdep->arm_abi == ARM_ABI_APCS)
- {
- /* The APCS ABI only requires word alignment. */
- align = ARM_INT_REGISTER_SIZE;
- }
- else
- {
- /* The AAPCS requires at most doubleword alignment. */
- if (align > ARM_INT_REGISTER_SIZE * 2)
- align = ARM_INT_REGISTER_SIZE * 2;
- }
- if (use_vfp_abi
- && arm_vfp_call_candidate (arg_type, &vfp_base_type,
- &vfp_base_count))
- {
- int regno;
- int unit_length;
- int shift;
- unsigned mask;
- /* Because this is a CPRC it cannot go in a core register or
- cause a core register to be skipped for alignment.
- Either it goes in VFP registers and the rest of this loop
- iteration is skipped for this argument, or it goes on the
- stack (and the stack alignment code is correct for this
- case). */
- may_use_core_reg = 0;
- unit_length = arm_vfp_cprc_unit_length (vfp_base_type);
- shift = unit_length / 4;
- mask = (1 << (shift * vfp_base_count)) - 1;
- for (regno = 0; regno < 16; regno += shift)
- if (((vfp_regs_free >> regno) & mask) == mask)
- break;
- if (regno < 16)
- {
- int reg_char;
- int reg_scaled;
- int i;
- vfp_regs_free &= ~(mask << regno);
- reg_scaled = regno / shift;
- reg_char = arm_vfp_cprc_reg_char (vfp_base_type);
- for (i = 0; i < vfp_base_count; i++)
- {
- char name_buf[4];
- int regnum;
- if (reg_char == 'q')
- arm_neon_quad_write (gdbarch, regcache, reg_scaled + i,
- val + i * unit_length);
- else
- {
- xsnprintf (name_buf, sizeof (name_buf), "%c%d",
- reg_char, reg_scaled + i);
- regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
- strlen (name_buf));
- regcache->cooked_write (regnum, val + i * unit_length);
- }
- }
- continue;
- }
- else
- {
- /* This CPRC could not go in VFP registers, so all VFP
- registers are now marked as used. */
- vfp_regs_free = 0;
- }
- }
- /* Push stack padding for doubleword alignment. */
- if (nstack & (align - 1))
- {
- si = push_stack_item (si, val, ARM_INT_REGISTER_SIZE);
- nstack += ARM_INT_REGISTER_SIZE;
- }
-
- /* Doubleword aligned quantities must go in even register pairs. */
- if (may_use_core_reg
- && argreg <= ARM_LAST_ARG_REGNUM
- && align > ARM_INT_REGISTER_SIZE
- && argreg & 1)
- argreg++;
- /* If the argument is a pointer to a function, and it is a
- Thumb function, create a LOCAL copy of the value and set
- the THUMB bit in it. */
- if (TYPE_CODE_PTR == typecode
- && target_type != NULL
- && TYPE_CODE_FUNC == check_typedef (target_type)->code ())
- {
- CORE_ADDR regval = extract_unsigned_integer (val, len, byte_order);
- if (arm_pc_is_thumb (gdbarch, regval))
- {
- bfd_byte *copy = (bfd_byte *) alloca (len);
- store_unsigned_integer (copy, len, byte_order,
- MAKE_THUMB_ADDR (regval));
- val = copy;
- }
- }
- /* Copy the argument to general registers or the stack in
- register-sized pieces. Large arguments are split between
- registers and stack. */
- while (len > 0)
- {
- int partial_len = len < ARM_INT_REGISTER_SIZE
- ? len : ARM_INT_REGISTER_SIZE;
- CORE_ADDR regval
- = extract_unsigned_integer (val, partial_len, byte_order);
- if (may_use_core_reg && argreg <= ARM_LAST_ARG_REGNUM)
- {
- /* The argument is being passed in a general purpose
- register. */
- if (byte_order == BFD_ENDIAN_BIG)
- regval <<= (ARM_INT_REGISTER_SIZE - partial_len) * 8;
- arm_debug_printf ("arg %d in %s = 0x%s", argnum,
- gdbarch_register_name (gdbarch, argreg),
- phex (regval, ARM_INT_REGISTER_SIZE));
- regcache_cooked_write_unsigned (regcache, argreg, regval);
- argreg++;
- }
- else
- {
- gdb_byte buf[ARM_INT_REGISTER_SIZE];
- memset (buf, 0, sizeof (buf));
- store_unsigned_integer (buf, partial_len, byte_order, regval);
- /* Push the arguments onto the stack. */
- arm_debug_printf ("arg %d @ sp + %d", argnum, nstack);
- si = push_stack_item (si, buf, ARM_INT_REGISTER_SIZE);
- nstack += ARM_INT_REGISTER_SIZE;
- }
-
- len -= partial_len;
- val += partial_len;
- }
- }
- /* If we have an odd number of words to push, then decrement the stack
- by one word now, so first stack argument will be dword aligned. */
- if (nstack & 4)
- sp -= 4;
- while (si)
- {
- sp -= si->len;
- write_memory (sp, si->data, si->len);
- si = pop_stack_item (si);
- }
- /* Finally, update teh SP register. */
- regcache_cooked_write_unsigned (regcache, ARM_SP_REGNUM, sp);
- return sp;
- }
- /* Always align the frame to an 8-byte boundary. This is required on
- some platforms and harmless on the rest. */
- static CORE_ADDR
- arm_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
- {
- /* Align the stack to eight bytes. */
- return sp & ~ (CORE_ADDR) 7;
- }
- static void
- print_fpu_flags (struct ui_file *file, int flags)
- {
- if (flags & (1 << 0))
- gdb_puts ("IVO ", file);
- if (flags & (1 << 1))
- gdb_puts ("DVZ ", file);
- if (flags & (1 << 2))
- gdb_puts ("OFL ", file);
- if (flags & (1 << 3))
- gdb_puts ("UFL ", file);
- if (flags & (1 << 4))
- gdb_puts ("INX ", file);
- gdb_putc ('\n', file);
- }
- /* Print interesting information about the floating point processor
- (if present) or emulator. */
- static void
- arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
- struct frame_info *frame, const char *args)
- {
- unsigned long status = get_frame_register_unsigned (frame, ARM_FPS_REGNUM);
- int type;
- type = (status >> 24) & 127;
- if (status & (1 << 31))
- gdb_printf (file, _("Hardware FPU type %d\n"), type);
- else
- gdb_printf (file, _("Software FPU type %d\n"), type);
- /* i18n: [floating point unit] mask */
- gdb_puts (_("mask: "), file);
- print_fpu_flags (file, status >> 16);
- /* i18n: [floating point unit] flags */
- gdb_puts (_("flags: "), file);
- print_fpu_flags (file, status);
- }
- /* Construct the ARM extended floating point type. */
- static struct type *
- arm_ext_type (struct gdbarch *gdbarch)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (!tdep->arm_ext_type)
- tdep->arm_ext_type
- = arch_float_type (gdbarch, -1, "builtin_type_arm_ext",
- floatformats_arm_ext);
- return tdep->arm_ext_type;
- }
- static struct type *
- arm_neon_double_type (struct gdbarch *gdbarch)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->neon_double_type == NULL)
- {
- struct type *t, *elem;
- t = arch_composite_type (gdbarch, "__gdb_builtin_type_neon_d",
- TYPE_CODE_UNION);
- elem = builtin_type (gdbarch)->builtin_uint8;
- append_composite_type_field (t, "u8", init_vector_type (elem, 8));
- elem = builtin_type (gdbarch)->builtin_uint16;
- append_composite_type_field (t, "u16", init_vector_type (elem, 4));
- elem = builtin_type (gdbarch)->builtin_uint32;
- append_composite_type_field (t, "u32", init_vector_type (elem, 2));
- elem = builtin_type (gdbarch)->builtin_uint64;
- append_composite_type_field (t, "u64", elem);
- elem = builtin_type (gdbarch)->builtin_float;
- append_composite_type_field (t, "f32", init_vector_type (elem, 2));
- elem = builtin_type (gdbarch)->builtin_double;
- append_composite_type_field (t, "f64", elem);
- t->set_is_vector (true);
- t->set_name ("neon_d");
- tdep->neon_double_type = t;
- }
- return tdep->neon_double_type;
- }
- /* FIXME: The vector types are not correctly ordered on big-endian
- targets. Just as s0 is the low bits of d0, d0[0] is also the low
- bits of d0 - regardless of what unit size is being held in d0. So
- the offset of the first uint8 in d0 is 7, but the offset of the
- first float is 4. This code works as-is for little-endian
- targets. */
- static struct type *
- arm_neon_quad_type (struct gdbarch *gdbarch)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->neon_quad_type == NULL)
- {
- struct type *t, *elem;
- t = arch_composite_type (gdbarch, "__gdb_builtin_type_neon_q",
- TYPE_CODE_UNION);
- elem = builtin_type (gdbarch)->builtin_uint8;
- append_composite_type_field (t, "u8", init_vector_type (elem, 16));
- elem = builtin_type (gdbarch)->builtin_uint16;
- append_composite_type_field (t, "u16", init_vector_type (elem, 8));
- elem = builtin_type (gdbarch)->builtin_uint32;
- append_composite_type_field (t, "u32", init_vector_type (elem, 4));
- elem = builtin_type (gdbarch)->builtin_uint64;
- append_composite_type_field (t, "u64", init_vector_type (elem, 2));
- elem = builtin_type (gdbarch)->builtin_float;
- append_composite_type_field (t, "f32", init_vector_type (elem, 4));
- elem = builtin_type (gdbarch)->builtin_double;
- append_composite_type_field (t, "f64", init_vector_type (elem, 2));
- t->set_is_vector (true);
- t->set_name ("neon_q");
- tdep->neon_quad_type = t;
- }
- return tdep->neon_quad_type;
- }
- /* Return true if REGNUM is a Q pseudo register. Return false
- otherwise.
- REGNUM is the raw register number and not a pseudo-relative register
- number. */
- static bool
- is_q_pseudo (struct gdbarch *gdbarch, int regnum)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* Q pseudo registers are available for both NEON (Q0~Q15) and
- MVE (Q0~Q7) features. */
- if (tdep->have_q_pseudos
- && regnum >= tdep->q_pseudo_base
- && regnum < (tdep->q_pseudo_base + tdep->q_pseudo_count))
- return true;
- return false;
- }
- /* Return true if REGNUM is a VFP S pseudo register. Return false
- otherwise.
- REGNUM is the raw register number and not a pseudo-relative register
- number. */
- static bool
- is_s_pseudo (struct gdbarch *gdbarch, int regnum)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->have_s_pseudos
- && regnum >= tdep->s_pseudo_base
- && regnum < (tdep->s_pseudo_base + tdep->s_pseudo_count))
- return true;
- return false;
- }
- /* Return true if REGNUM is a MVE pseudo register (P0). Return false
- otherwise.
- REGNUM is the raw register number and not a pseudo-relative register
- number. */
- static bool
- is_mve_pseudo (struct gdbarch *gdbarch, int regnum)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->have_mve
- && regnum >= tdep->mve_pseudo_base
- && regnum < tdep->mve_pseudo_base + tdep->mve_pseudo_count)
- return true;
- return false;
- }
- /* Return true if REGNUM is a PACBTI pseudo register (ra_auth_code). Return
- false otherwise.
- REGNUM is the raw register number and not a pseudo-relative register
- number. */
- static bool
- is_pacbti_pseudo (struct gdbarch *gdbarch, int regnum)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->have_pacbti
- && regnum >= tdep->pacbti_pseudo_base
- && regnum < tdep->pacbti_pseudo_base + tdep->pacbti_pseudo_count)
- return true;
- return false;
- }
- /* Return the GDB type object for the "standard" data type of data in
- register N. */
- static struct type *
- arm_register_type (struct gdbarch *gdbarch, int regnum)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (is_s_pseudo (gdbarch, regnum))
- return builtin_type (gdbarch)->builtin_float;
- if (is_q_pseudo (gdbarch, regnum))
- return arm_neon_quad_type (gdbarch);
- if (is_mve_pseudo (gdbarch, regnum))
- return builtin_type (gdbarch)->builtin_int16;
- if (is_pacbti_pseudo (gdbarch, regnum))
- return builtin_type (gdbarch)->builtin_uint32;
- /* If the target description has register information, we are only
- in this function so that we can override the types of
- double-precision registers for NEON. */
- if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
- {
- struct type *t = tdesc_register_type (gdbarch, regnum);
- if (regnum >= ARM_D0_REGNUM && regnum < ARM_D0_REGNUM + 32
- && t->code () == TYPE_CODE_FLT
- && tdep->have_neon)
- return arm_neon_double_type (gdbarch);
- else
- return t;
- }
- if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
- {
- if (!tdep->have_fpa_registers)
- return builtin_type (gdbarch)->builtin_void;
- return arm_ext_type (gdbarch);
- }
- else if (regnum == ARM_SP_REGNUM)
- return builtin_type (gdbarch)->builtin_data_ptr;
- else if (regnum == ARM_PC_REGNUM)
- return builtin_type (gdbarch)->builtin_func_ptr;
- else if (regnum >= ARRAY_SIZE (arm_register_names))
- /* These registers are only supported on targets which supply
- an XML description. */
- return builtin_type (gdbarch)->builtin_int0;
- else
- return builtin_type (gdbarch)->builtin_uint32;
- }
- /* Map a DWARF register REGNUM onto the appropriate GDB register
- number. */
- static int
- arm_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
- {
- /* Core integer regs. */
- if (reg >= 0 && reg <= 15)
- return reg;
- /* Legacy FPA encoding. These were once used in a way which
- overlapped with VFP register numbering, so their use is
- discouraged, but GDB doesn't support the ARM toolchain
- which used them for VFP. */
- if (reg >= 16 && reg <= 23)
- return ARM_F0_REGNUM + reg - 16;
- /* New assignments for the FPA registers. */
- if (reg >= 96 && reg <= 103)
- return ARM_F0_REGNUM + reg - 96;
- /* WMMX register assignments. */
- if (reg >= 104 && reg <= 111)
- return ARM_WCGR0_REGNUM + reg - 104;
- if (reg >= 112 && reg <= 127)
- return ARM_WR0_REGNUM + reg - 112;
- /* PACBTI register containing the Pointer Authentication Code. */
- if (reg == ARM_DWARF_RA_AUTH_CODE)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->have_pacbti)
- return tdep->pacbti_pseudo_base;
- return -1;
- }
- if (reg >= 192 && reg <= 199)
- return ARM_WC0_REGNUM + reg - 192;
- /* VFP v2 registers. A double precision value is actually
- in d1 rather than s2, but the ABI only defines numbering
- for the single precision registers. This will "just work"
- in GDB for little endian targets (we'll read eight bytes,
- starting in s0 and then progressing to s1), but will be
- reversed on big endian targets with VFP. This won't
- be a problem for the new Neon quad registers; you're supposed
- to use DW_OP_piece for those. */
- if (reg >= 64 && reg <= 95)
- {
- char name_buf[4];
- xsnprintf (name_buf, sizeof (name_buf), "s%d", reg - 64);
- return user_reg_map_name_to_regnum (gdbarch, name_buf,
- strlen (name_buf));
- }
- /* VFP v3 / Neon registers. This range is also used for VFP v2
- registers, except that it now describes d0 instead of s0. */
- if (reg >= 256 && reg <= 287)
- {
- char name_buf[4];
- xsnprintf (name_buf, sizeof (name_buf), "d%d", reg - 256);
- return user_reg_map_name_to_regnum (gdbarch, name_buf,
- strlen (name_buf));
- }
- return -1;
- }
- /* Map GDB internal REGNUM onto the Arm simulator register numbers. */
- static int
- arm_register_sim_regno (struct gdbarch *gdbarch, int regnum)
- {
- int reg = regnum;
- gdb_assert (reg >= 0 && reg < gdbarch_num_regs (gdbarch));
- if (regnum >= ARM_WR0_REGNUM && regnum <= ARM_WR15_REGNUM)
- return regnum - ARM_WR0_REGNUM + SIM_ARM_IWMMXT_COP0R0_REGNUM;
- if (regnum >= ARM_WC0_REGNUM && regnum <= ARM_WC7_REGNUM)
- return regnum - ARM_WC0_REGNUM + SIM_ARM_IWMMXT_COP1R0_REGNUM;
- if (regnum >= ARM_WCGR0_REGNUM && regnum <= ARM_WCGR7_REGNUM)
- return regnum - ARM_WCGR0_REGNUM + SIM_ARM_IWMMXT_COP1R8_REGNUM;
- if (reg < NUM_GREGS)
- return SIM_ARM_R0_REGNUM + reg;
- reg -= NUM_GREGS;
- if (reg < NUM_FREGS)
- return SIM_ARM_FP0_REGNUM + reg;
- reg -= NUM_FREGS;
- if (reg < NUM_SREGS)
- return SIM_ARM_FPS_REGNUM + reg;
- reg -= NUM_SREGS;
- internal_error (__FILE__, __LINE__, _("Bad REGNUM %d"), regnum);
- }
- static const unsigned char op_lit0 = DW_OP_lit0;
- static void
- arm_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg,
- struct frame_info *this_frame)
- {
- if (is_pacbti_pseudo (gdbarch, regnum))
- {
- /* Initialize RA_AUTH_CODE to zero. */
- reg->how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
- reg->loc.exp.start = &op_lit0;
- reg->loc.exp.len = 1;
- return;
- }
- switch (regnum)
- {
- case ARM_PC_REGNUM:
- case ARM_PS_REGNUM:
- reg->how = DWARF2_FRAME_REG_FN;
- reg->loc.fn = arm_dwarf2_prev_register;
- break;
- case ARM_SP_REGNUM:
- reg->how = DWARF2_FRAME_REG_CFA;
- break;
- }
- }
- /* Given BUF, which is OLD_LEN bytes ending at ENDADDR, expand
- the buffer to be NEW_LEN bytes ending at ENDADDR. Return
- NULL if an error occurs. BUF is freed. */
- static gdb_byte *
- extend_buffer_earlier (gdb_byte *buf, CORE_ADDR endaddr,
- int old_len, int new_len)
- {
- gdb_byte *new_buf;
- int bytes_to_read = new_len - old_len;
- new_buf = (gdb_byte *) xmalloc (new_len);
- memcpy (new_buf + bytes_to_read, buf, old_len);
- xfree (buf);
- if (target_read_code (endaddr - new_len, new_buf, bytes_to_read) != 0)
- {
- xfree (new_buf);
- return NULL;
- }
- return new_buf;
- }
- /* An IT block is at most the 2-byte IT instruction followed by
- four 4-byte instructions. The furthest back we must search to
- find an IT block that affects the current instruction is thus
- 2 + 3 * 4 == 14 bytes. */
- #define MAX_IT_BLOCK_PREFIX 14
- /* Use a quick scan if there are more than this many bytes of
- code. */
- #define IT_SCAN_THRESHOLD 32
- /* Adjust a breakpoint's address to move breakpoints out of IT blocks.
- A breakpoint in an IT block may not be hit, depending on the
- condition flags. */
- static CORE_ADDR
- arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
- {
- gdb_byte *buf;
- char map_type;
- CORE_ADDR boundary, func_start;
- int buf_len;
- enum bfd_endian order = gdbarch_byte_order_for_code (gdbarch);
- int i, any, last_it, last_it_count;
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* If we are using BKPT breakpoints, none of this is necessary. */
- if (tdep->thumb2_breakpoint == NULL)
- return bpaddr;
- /* ARM mode does not have this problem. */
- if (!arm_pc_is_thumb (gdbarch, bpaddr))
- return bpaddr;
- /* We are setting a breakpoint in Thumb code that could potentially
- contain an IT block. The first step is to find how much Thumb
- code there is; we do not need to read outside of known Thumb
- sequences. */
- map_type = arm_find_mapping_symbol (bpaddr, &boundary);
- if (map_type == 0)
- /* Thumb-2 code must have mapping symbols to have a chance. */
- return bpaddr;
- bpaddr = gdbarch_addr_bits_remove (gdbarch, bpaddr);
- if (find_pc_partial_function (bpaddr, NULL, &func_start, NULL)
- && func_start > boundary)
- boundary = func_start;
- /* Search for a candidate IT instruction. We have to do some fancy
- footwork to distinguish a real IT instruction from the second
- half of a 32-bit instruction, but there is no need for that if
- there's no candidate. */
- buf_len = std::min (bpaddr - boundary, (CORE_ADDR) MAX_IT_BLOCK_PREFIX);
- if (buf_len == 0)
- /* No room for an IT instruction. */
- return bpaddr;
- buf = (gdb_byte *) xmalloc (buf_len);
- if (target_read_code (bpaddr - buf_len, buf, buf_len) != 0)
- return bpaddr;
- any = 0;
- for (i = 0; i < buf_len; i += 2)
- {
- unsigned short inst1 = extract_unsigned_integer (&buf[i], 2, order);
- if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
- {
- any = 1;
- break;
- }
- }
- if (any == 0)
- {
- xfree (buf);
- return bpaddr;
- }
- /* OK, the code bytes before this instruction contain at least one
- halfword which resembles an IT instruction. We know that it's
- Thumb code, but there are still two possibilities. Either the
- halfword really is an IT instruction, or it is the second half of
- a 32-bit Thumb instruction. The only way we can tell is to
- scan forwards from a known instruction boundary. */
- if (bpaddr - boundary > IT_SCAN_THRESHOLD)
- {
- int definite;
- /* There's a lot of code before this instruction. Start with an
- optimistic search; it's easy to recognize halfwords that can
- not be the start of a 32-bit instruction, and use that to
- lock on to the instruction boundaries. */
- buf = extend_buffer_earlier (buf, bpaddr, buf_len, IT_SCAN_THRESHOLD);
- if (buf == NULL)
- return bpaddr;
- buf_len = IT_SCAN_THRESHOLD;
- definite = 0;
- for (i = 0; i < buf_len - sizeof (buf) && ! definite; i += 2)
- {
- unsigned short inst1 = extract_unsigned_integer (&buf[i], 2, order);
- if (thumb_insn_size (inst1) == 2)
- {
- definite = 1;
- break;
- }
- }
- /* At this point, if DEFINITE, BUF[I] is the first place we
- are sure that we know the instruction boundaries, and it is far
- enough from BPADDR that we could not miss an IT instruction
- affecting BPADDR. If ! DEFINITE, give up - start from a
- known boundary. */
- if (! definite)
- {
- buf = extend_buffer_earlier (buf, bpaddr, buf_len,
- bpaddr - boundary);
- if (buf == NULL)
- return bpaddr;
- buf_len = bpaddr - boundary;
- i = 0;
- }
- }
- else
- {
- buf = extend_buffer_earlier (buf, bpaddr, buf_len, bpaddr - boundary);
- if (buf == NULL)
- return bpaddr;
- buf_len = bpaddr - boundary;
- i = 0;
- }
- /* Scan forwards. Find the last IT instruction before BPADDR. */
- last_it = -1;
- last_it_count = 0;
- while (i < buf_len)
- {
- unsigned short inst1 = extract_unsigned_integer (&buf[i], 2, order);
- last_it_count--;
- if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
- {
- last_it = i;
- if (inst1 & 0x0001)
- last_it_count = 4;
- else if (inst1 & 0x0002)
- last_it_count = 3;
- else if (inst1 & 0x0004)
- last_it_count = 2;
- else
- last_it_count = 1;
- }
- i += thumb_insn_size (inst1);
- }
- xfree (buf);
- if (last_it == -1)
- /* There wasn't really an IT instruction after all. */
- return bpaddr;
- if (last_it_count < 1)
- /* It was too far away. */
- return bpaddr;
- /* This really is a trouble spot. Move the breakpoint to the IT
- instruction. */
- return bpaddr - buf_len + last_it;
- }
- /* ARM displaced stepping support.
- Generally ARM displaced stepping works as follows:
- 1. When an instruction is to be single-stepped, it is first decoded by
- arm_process_displaced_insn. Depending on the type of instruction, it is
- then copied to a scratch location, possibly in a modified form. The
- copy_* set of functions performs such modification, as necessary. A
- breakpoint is placed after the modified instruction in the scratch space
- to return control to GDB. Note in particular that instructions which
- modify the PC will no longer do so after modification.
- 2. The instruction is single-stepped, by setting the PC to the scratch
- location address, and resuming. Control returns to GDB when the
- breakpoint is hit.
- 3. A cleanup function (cleanup_*) is called corresponding to the copy_*
- function used for the current instruction. This function's job is to
- put the CPU/memory state back to what it would have been if the
- instruction had been executed unmodified in its original location. */
- /* NOP instruction (mov r0, r0). */
- #define ARM_NOP 0xe1a00000
- #define THUMB_NOP 0x4600
- /* Helper for register reads for displaced stepping. In particular, this
- returns the PC as it would be seen by the instruction at its original
- location. */
- ULONGEST
- displaced_read_reg (regcache *regs, arm_displaced_step_copy_insn_closure *dsc,
- int regno)
- {
- ULONGEST ret;
- CORE_ADDR from = dsc->insn_addr;
- if (regno == ARM_PC_REGNUM)
- {
- /* Compute pipeline offset:
- - When executing an ARM instruction, PC reads as the address of the
- current instruction plus 8.
- - When executing a Thumb instruction, PC reads as the address of the
- current instruction plus 4. */
- if (!dsc->is_thumb)
- from += 8;
- else
- from += 4;
- displaced_debug_printf ("read pc value %.8lx",
- (unsigned long) from);
- return (ULONGEST) from;
- }
- else
- {
- regcache_cooked_read_unsigned (regs, regno, &ret);
- displaced_debug_printf ("read r%d value %.8lx",
- regno, (unsigned long) ret);
- return ret;
- }
- }
- static int
- displaced_in_arm_mode (struct regcache *regs)
- {
- ULONGEST ps;
- ULONGEST t_bit = arm_psr_thumb_bit (regs->arch ());
- regcache_cooked_read_unsigned (regs, ARM_PS_REGNUM, &ps);
- return (ps & t_bit) == 0;
- }
- /* Write to the PC as from a branch instruction. */
- static void
- branch_write_pc (regcache *regs, arm_displaced_step_copy_insn_closure *dsc,
- ULONGEST val)
- {
- if (!dsc->is_thumb)
- /* Note: If bits 0/1 are set, this branch would be unpredictable for
- architecture versions < 6. */
- regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM,
- val & ~(ULONGEST) 0x3);
- else
- regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM,
- val & ~(ULONGEST) 0x1);
- }
- /* Write to the PC as from a branch-exchange instruction. */
- static void
- bx_write_pc (struct regcache *regs, ULONGEST val)
- {
- ULONGEST ps;
- ULONGEST t_bit = arm_psr_thumb_bit (regs->arch ());
- regcache_cooked_read_unsigned (regs, ARM_PS_REGNUM, &ps);
- if ((val & 1) == 1)
- {
- regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, ps | t_bit);
- regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM, val & 0xfffffffe);
- }
- else if ((val & 2) == 0)
- {
- regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, ps & ~t_bit);
- regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM, val);
- }
- else
- {
- /* Unpredictable behaviour. Try to do something sensible (switch to ARM
- mode, align dest to 4 bytes). */
- warning (_("Single-stepping BX to non-word-aligned ARM instruction."));
- regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, ps & ~t_bit);
- regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM, val & 0xfffffffc);
- }
- }
- /* Write to the PC as if from a load instruction. */
- static void
- load_write_pc (regcache *regs, arm_displaced_step_copy_insn_closure *dsc,
- ULONGEST val)
- {
- if (DISPLACED_STEPPING_ARCH_VERSION >= 5)
- bx_write_pc (regs, val);
- else
- branch_write_pc (regs, dsc, val);
- }
- /* Write to the PC as if from an ALU instruction. */
- static void
- alu_write_pc (regcache *regs, arm_displaced_step_copy_insn_closure *dsc,
- ULONGEST val)
- {
- if (DISPLACED_STEPPING_ARCH_VERSION >= 7 && !dsc->is_thumb)
- bx_write_pc (regs, val);
- else
- branch_write_pc (regs, dsc, val);
- }
- /* Helper for writing to registers for displaced stepping. Writing to the PC
- has a varying effects depending on the instruction which does the write:
- this is controlled by the WRITE_PC argument. */
- void
- displaced_write_reg (regcache *regs, arm_displaced_step_copy_insn_closure *dsc,
- int regno, ULONGEST val, enum pc_write_style write_pc)
- {
- if (regno == ARM_PC_REGNUM)
- {
- displaced_debug_printf ("writing pc %.8lx", (unsigned long) val);
- switch (write_pc)
- {
- case BRANCH_WRITE_PC:
- branch_write_pc (regs, dsc, val);
- break;
- case BX_WRITE_PC:
- bx_write_pc (regs, val);
- break;
- case LOAD_WRITE_PC:
- load_write_pc (regs, dsc, val);
- break;
- case ALU_WRITE_PC:
- alu_write_pc (regs, dsc, val);
- break;
- case CANNOT_WRITE_PC:
- warning (_("Instruction wrote to PC in an unexpected way when "
- "single-stepping"));
- break;
- default:
- internal_error (__FILE__, __LINE__,
- _("Invalid argument to displaced_write_reg"));
- }
- dsc->wrote_to_pc = 1;
- }
- else
- {
- displaced_debug_printf ("writing r%d value %.8lx",
- regno, (unsigned long) val);
- regcache_cooked_write_unsigned (regs, regno, val);
- }
- }
- /* This function is used to concisely determine if an instruction INSN
- references PC. Register fields of interest in INSN should have the
- corresponding fields of BITMASK set to 0b1111. The function
- returns return 1 if any of these fields in INSN reference the PC
- (also 0b1111, r15), else it returns 0. */
- static int
- insn_references_pc (uint32_t insn, uint32_t bitmask)
- {
- uint32_t lowbit = 1;
- while (bitmask != 0)
- {
- uint32_t mask;
- for (; lowbit && (bitmask & lowbit) == 0; lowbit <<= 1)
- ;
- if (!lowbit)
- break;
- mask = lowbit * 0xf;
- if ((insn & mask) == mask)
- return 1;
- bitmask &= ~mask;
- }
- return 0;
- }
- /* The simplest copy function. Many instructions have the same effect no
- matter what address they are executed at: in those cases, use this. */
- static int
- arm_copy_unmodified (struct gdbarch *gdbarch, uint32_t insn, const char *iname,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- displaced_debug_printf ("copying insn %.8lx, opcode/class '%s' unmodified",
- (unsigned long) insn, iname);
- dsc->modinsn[0] = insn;
- return 0;
- }
- static int
- thumb_copy_unmodified_32bit (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, const char *iname,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- displaced_debug_printf ("copying insn %.4x %.4x, opcode/class '%s' "
- "unmodified", insn1, insn2, iname);
- dsc->modinsn[0] = insn1;
- dsc->modinsn[1] = insn2;
- dsc->numinsns = 2;
- return 0;
- }
- /* Copy 16-bit Thumb(Thumb and 16-bit Thumb-2) instruction without any
- modification. */
- static int
- thumb_copy_unmodified_16bit (struct gdbarch *gdbarch, uint16_t insn,
- const char *iname,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- displaced_debug_printf ("copying insn %.4x, opcode/class '%s' unmodified",
- insn, iname);
- dsc->modinsn[0] = insn;
- return 0;
- }
- /* Preload instructions with immediate offset. */
- static void
- cleanup_preload (struct gdbarch *gdbarch, regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
- if (!dsc->u.preload.immed)
- displaced_write_reg (regs, dsc, 1, dsc->tmp[1], CANNOT_WRITE_PC);
- }
- static void
- install_preload (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc, unsigned int rn)
- {
- ULONGEST rn_val;
- /* Preload instructions:
- {pli/pld} [rn, #+/-imm]
- ->
- {pli/pld} [r0, #+/-imm]. */
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
- rn_val = displaced_read_reg (regs, dsc, rn);
- displaced_write_reg (regs, dsc, 0, rn_val, CANNOT_WRITE_PC);
- dsc->u.preload.immed = 1;
- dsc->cleanup = &cleanup_preload;
- }
- static int
- arm_copy_preload (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int rn = bits (insn, 16, 19);
- if (!insn_references_pc (insn, 0x000f0000ul))
- return arm_copy_unmodified (gdbarch, insn, "preload", dsc);
- displaced_debug_printf ("copying preload insn %.8lx", (unsigned long) insn);
- dsc->modinsn[0] = insn & 0xfff0ffff;
- install_preload (gdbarch, regs, dsc, rn);
- return 0;
- }
- static int
- thumb2_copy_preload (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
- regcache *regs, arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int rn = bits (insn1, 0, 3);
- unsigned int u_bit = bit (insn1, 7);
- int imm12 = bits (insn2, 0, 11);
- ULONGEST pc_val;
- if (rn != ARM_PC_REGNUM)
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2, "preload", dsc);
- /* PC is only allowed to use in PLI (immediate,literal) Encoding T3, and
- PLD (literal) Encoding T1. */
- displaced_debug_printf ("copying pld/pli pc (0x%x) %c imm12 %.4x",
- (unsigned int) dsc->insn_addr, u_bit ? '+' : '-',
- imm12);
- if (!u_bit)
- imm12 = -1 * imm12;
- /* Rewrite instruction {pli/pld} PC imm12 into:
- Prepare: tmp[0] <- r0, tmp[1] <- r1, r0 <- pc, r1 <- imm12
- {pli/pld} [r0, r1]
- Cleanup: r0 <- tmp[0], r1 <- tmp[1]. */
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
- dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
- pc_val = displaced_read_reg (regs, dsc, ARM_PC_REGNUM);
- displaced_write_reg (regs, dsc, 0, pc_val, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 1, imm12, CANNOT_WRITE_PC);
- dsc->u.preload.immed = 0;
- /* {pli/pld} [r0, r1] */
- dsc->modinsn[0] = insn1 & 0xfff0;
- dsc->modinsn[1] = 0xf001;
- dsc->numinsns = 2;
- dsc->cleanup = &cleanup_preload;
- return 0;
- }
- /* Preload instructions with register offset. */
- static void
- install_preload_reg(struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc, unsigned int rn,
- unsigned int rm)
- {
- ULONGEST rn_val, rm_val;
- /* Preload register-offset instructions:
- {pli/pld} [rn, rm {, shift}]
- ->
- {pli/pld} [r0, r1 {, shift}]. */
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
- dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
- rn_val = displaced_read_reg (regs, dsc, rn);
- rm_val = displaced_read_reg (regs, dsc, rm);
- displaced_write_reg (regs, dsc, 0, rn_val, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 1, rm_val, CANNOT_WRITE_PC);
- dsc->u.preload.immed = 0;
- dsc->cleanup = &cleanup_preload;
- }
- static int
- arm_copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int rn = bits (insn, 16, 19);
- unsigned int rm = bits (insn, 0, 3);
- if (!insn_references_pc (insn, 0x000f000ful))
- return arm_copy_unmodified (gdbarch, insn, "preload reg", dsc);
- displaced_debug_printf ("copying preload insn %.8lx",
- (unsigned long) insn);
- dsc->modinsn[0] = (insn & 0xfff0fff0) | 0x1;
- install_preload_reg (gdbarch, regs, dsc, rn, rm);
- return 0;
- }
- /* Copy/cleanup coprocessor load and store instructions. */
- static void
- cleanup_copro_load_store (struct gdbarch *gdbarch,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- ULONGEST rn_val = displaced_read_reg (regs, dsc, 0);
- displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
- if (dsc->u.ldst.writeback)
- displaced_write_reg (regs, dsc, dsc->u.ldst.rn, rn_val, LOAD_WRITE_PC);
- }
- static void
- install_copro_load_store (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc,
- int writeback, unsigned int rn)
- {
- ULONGEST rn_val;
- /* Coprocessor load/store instructions:
- {stc/stc2} [<Rn>, #+/-imm] (and other immediate addressing modes)
- ->
- {stc/stc2} [r0, #+/-imm].
- ldc/ldc2 are handled identically. */
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
- rn_val = displaced_read_reg (regs, dsc, rn);
- /* PC should be 4-byte aligned. */
- rn_val = rn_val & 0xfffffffc;
- displaced_write_reg (regs, dsc, 0, rn_val, CANNOT_WRITE_PC);
- dsc->u.ldst.writeback = writeback;
- dsc->u.ldst.rn = rn;
- dsc->cleanup = &cleanup_copro_load_store;
- }
- static int
- arm_copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int rn = bits (insn, 16, 19);
- if (!insn_references_pc (insn, 0x000f0000ul))
- return arm_copy_unmodified (gdbarch, insn, "copro load/store", dsc);
- displaced_debug_printf ("copying coprocessor load/store insn %.8lx",
- (unsigned long) insn);
- dsc->modinsn[0] = insn & 0xfff0ffff;
- install_copro_load_store (gdbarch, regs, dsc, bit (insn, 25), rn);
- return 0;
- }
- static int
- thumb2_copy_copro_load_store (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int rn = bits (insn1, 0, 3);
- if (rn != ARM_PC_REGNUM)
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "copro load/store", dsc);
- displaced_debug_printf ("copying coprocessor load/store insn %.4x%.4x",
- insn1, insn2);
- dsc->modinsn[0] = insn1 & 0xfff0;
- dsc->modinsn[1] = insn2;
- dsc->numinsns = 2;
- /* This function is called for copying instruction LDC/LDC2/VLDR, which
- doesn't support writeback, so pass 0. */
- install_copro_load_store (gdbarch, regs, dsc, 0, rn);
- return 0;
- }
- /* Clean up branch instructions (actually perform the branch, by setting
- PC). */
- static void
- cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
- int branch_taken = condition_true (dsc->u.branch.cond, status);
- enum pc_write_style write_pc = dsc->u.branch.exchange
- ? BX_WRITE_PC : BRANCH_WRITE_PC;
- if (!branch_taken)
- return;
- if (dsc->u.branch.link)
- {
- /* The value of LR should be the next insn of current one. In order
- not to confuse logic handling later insn `bx lr', if current insn mode
- is Thumb, the bit 0 of LR value should be set to 1. */
- ULONGEST next_insn_addr = dsc->insn_addr + dsc->insn_size;
- if (dsc->is_thumb)
- next_insn_addr |= 0x1;
- displaced_write_reg (regs, dsc, ARM_LR_REGNUM, next_insn_addr,
- CANNOT_WRITE_PC);
- }
- displaced_write_reg (regs, dsc, ARM_PC_REGNUM, dsc->u.branch.dest, write_pc);
- }
- /* Copy B/BL/BLX instructions with immediate destinations. */
- static void
- install_b_bl_blx (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc,
- unsigned int cond, int exchange, int link, long offset)
- {
- /* Implement "BL<cond> <label>" as:
- Preparation: cond <- instruction condition
- Insn: mov r0, r0 (nop)
- Cleanup: if (condition true) { r14 <- pc; pc <- label }.
- B<cond> similar, but don't set r14 in cleanup. */
- dsc->u.branch.cond = cond;
- dsc->u.branch.link = link;
- dsc->u.branch.exchange = exchange;
- dsc->u.branch.dest = dsc->insn_addr;
- if (link && exchange)
- /* For BLX, offset is computed from the Align (PC, 4). */
- dsc->u.branch.dest = dsc->u.branch.dest & 0xfffffffc;
- if (dsc->is_thumb)
- dsc->u.branch.dest += 4 + offset;
- else
- dsc->u.branch.dest += 8 + offset;
- dsc->cleanup = &cleanup_branch;
- }
- static int
- arm_copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn,
- regcache *regs, arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int cond = bits (insn, 28, 31);
- int exchange = (cond == 0xf);
- int link = exchange || bit (insn, 24);
- long offset;
- displaced_debug_printf ("copying %s immediate insn %.8lx",
- (exchange) ? "blx" : (link) ? "bl" : "b",
- (unsigned long) insn);
- if (exchange)
- /* For BLX, set bit 0 of the destination. The cleanup_branch function will
- then arrange the switch into Thumb mode. */
- offset = (bits (insn, 0, 23) << 2) | (bit (insn, 24) << 1) | 1;
- else
- offset = bits (insn, 0, 23) << 2;
- if (bit (offset, 25))
- offset = offset | ~0x3ffffff;
- dsc->modinsn[0] = ARM_NOP;
- install_b_bl_blx (gdbarch, regs, dsc, cond, exchange, link, offset);
- return 0;
- }
- static int
- thumb2_copy_b_bl_blx (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- int link = bit (insn2, 14);
- int exchange = link && !bit (insn2, 12);
- int cond = INST_AL;
- long offset = 0;
- int j1 = bit (insn2, 13);
- int j2 = bit (insn2, 11);
- int s = sbits (insn1, 10, 10);
- int i1 = !(j1 ^ bit (insn1, 10));
- int i2 = !(j2 ^ bit (insn1, 10));
- if (!link && !exchange) /* B */
- {
- offset = (bits (insn2, 0, 10) << 1);
- if (bit (insn2, 12)) /* Encoding T4 */
- {
- offset |= (bits (insn1, 0, 9) << 12)
- | (i2 << 22)
- | (i1 << 23)
- | (s << 24);
- cond = INST_AL;
- }
- else /* Encoding T3 */
- {
- offset |= (bits (insn1, 0, 5) << 12)
- | (j1 << 18)
- | (j2 << 19)
- | (s << 20);
- cond = bits (insn1, 6, 9);
- }
- }
- else
- {
- offset = (bits (insn1, 0, 9) << 12);
- offset |= ((i2 << 22) | (i1 << 23) | (s << 24));
- offset |= exchange ?
- (bits (insn2, 1, 10) << 2) : (bits (insn2, 0, 10) << 1);
- }
- displaced_debug_printf ("copying %s insn %.4x %.4x with offset %.8lx",
- link ? (exchange) ? "blx" : "bl" : "b",
- insn1, insn2, offset);
- dsc->modinsn[0] = THUMB_NOP;
- install_b_bl_blx (gdbarch, regs, dsc, cond, exchange, link, offset);
- return 0;
- }
- /* Copy B Thumb instructions. */
- static int
- thumb_copy_b (struct gdbarch *gdbarch, uint16_t insn,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int cond = 0;
- int offset = 0;
- unsigned short bit_12_15 = bits (insn, 12, 15);
- CORE_ADDR from = dsc->insn_addr;
- if (bit_12_15 == 0xd)
- {
- /* offset = SignExtend (imm8:0, 32) */
- offset = sbits ((insn << 1), 0, 8);
- cond = bits (insn, 8, 11);
- }
- else if (bit_12_15 == 0xe) /* Encoding T2 */
- {
- offset = sbits ((insn << 1), 0, 11);
- cond = INST_AL;
- }
- displaced_debug_printf ("copying b immediate insn %.4x with offset %d",
- insn, offset);
- dsc->u.branch.cond = cond;
- dsc->u.branch.link = 0;
- dsc->u.branch.exchange = 0;
- dsc->u.branch.dest = from + 4 + offset;
- dsc->modinsn[0] = THUMB_NOP;
- dsc->cleanup = &cleanup_branch;
- return 0;
- }
- /* Copy BX/BLX with register-specified destinations. */
- static void
- install_bx_blx_reg (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc, int link,
- unsigned int cond, unsigned int rm)
- {
- /* Implement {BX,BLX}<cond> <reg>" as:
- Preparation: cond <- instruction condition
- Insn: mov r0, r0 (nop)
- Cleanup: if (condition true) { r14 <- pc; pc <- dest; }.
- Don't set r14 in cleanup for BX. */
- dsc->u.branch.dest = displaced_read_reg (regs, dsc, rm);
- dsc->u.branch.cond = cond;
- dsc->u.branch.link = link;
- dsc->u.branch.exchange = 1;
- dsc->cleanup = &cleanup_branch;
- }
- static int
- arm_copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn,
- regcache *regs, arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int cond = bits (insn, 28, 31);
- /* BX: x12xxx1x
- BLX: x12xxx3x. */
- int link = bit (insn, 5);
- unsigned int rm = bits (insn, 0, 3);
- displaced_debug_printf ("copying insn %.8lx", (unsigned long) insn);
- dsc->modinsn[0] = ARM_NOP;
- install_bx_blx_reg (gdbarch, regs, dsc, link, cond, rm);
- return 0;
- }
- static int
- thumb_copy_bx_blx_reg (struct gdbarch *gdbarch, uint16_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- int link = bit (insn, 7);
- unsigned int rm = bits (insn, 3, 6);
- displaced_debug_printf ("copying insn %.4x", (unsigned short) insn);
- dsc->modinsn[0] = THUMB_NOP;
- install_bx_blx_reg (gdbarch, regs, dsc, link, INST_AL, rm);
- return 0;
- }
- /* Copy/cleanup arithmetic/logic instruction with immediate RHS. */
- static void
- cleanup_alu_imm (struct gdbarch *gdbarch,
- regcache *regs, arm_displaced_step_copy_insn_closure *dsc)
- {
- ULONGEST rd_val = displaced_read_reg (regs, dsc, 0);
- displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 1, dsc->tmp[1], CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, dsc->rd, rd_val, ALU_WRITE_PC);
- }
- static int
- arm_copy_alu_imm (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int rn = bits (insn, 16, 19);
- unsigned int rd = bits (insn, 12, 15);
- unsigned int op = bits (insn, 21, 24);
- int is_mov = (op == 0xd);
- ULONGEST rd_val, rn_val;
- if (!insn_references_pc (insn, 0x000ff000ul))
- return arm_copy_unmodified (gdbarch, insn, "ALU immediate", dsc);
- displaced_debug_printf ("copying immediate %s insn %.8lx",
- is_mov ? "move" : "ALU",
- (unsigned long) insn);
- /* Instruction is of form:
- <op><cond> rd, [rn,] #imm
- Rewrite as:
- Preparation: tmp1, tmp2 <- r0, r1;
- r0, r1 <- rd, rn
- Insn: <op><cond> r0, r1, #imm
- Cleanup: rd <- r0; r0 <- tmp1; r1 <- tmp2
- */
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
- dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
- rn_val = displaced_read_reg (regs, dsc, rn);
- rd_val = displaced_read_reg (regs, dsc, rd);
- displaced_write_reg (regs, dsc, 0, rd_val, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 1, rn_val, CANNOT_WRITE_PC);
- dsc->rd = rd;
- if (is_mov)
- dsc->modinsn[0] = insn & 0xfff00fff;
- else
- dsc->modinsn[0] = (insn & 0xfff00fff) | 0x10000;
- dsc->cleanup = &cleanup_alu_imm;
- return 0;
- }
- static int
- thumb2_copy_alu_imm (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int op = bits (insn1, 5, 8);
- unsigned int rn, rm, rd;
- ULONGEST rd_val, rn_val;
- rn = bits (insn1, 0, 3); /* Rn */
- rm = bits (insn2, 0, 3); /* Rm */
- rd = bits (insn2, 8, 11); /* Rd */
- /* This routine is only called for instruction MOV. */
- gdb_assert (op == 0x2 && rn == 0xf);
- if (rm != ARM_PC_REGNUM && rd != ARM_PC_REGNUM)
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2, "ALU imm", dsc);
- displaced_debug_printf ("copying reg %s insn %.4x%.4x", "ALU", insn1, insn2);
- /* Instruction is of form:
- <op><cond> rd, [rn,] #imm
- Rewrite as:
- Preparation: tmp1, tmp2 <- r0, r1;
- r0, r1 <- rd, rn
- Insn: <op><cond> r0, r1, #imm
- Cleanup: rd <- r0; r0 <- tmp1; r1 <- tmp2
- */
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
- dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
- rn_val = displaced_read_reg (regs, dsc, rn);
- rd_val = displaced_read_reg (regs, dsc, rd);
- displaced_write_reg (regs, dsc, 0, rd_val, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 1, rn_val, CANNOT_WRITE_PC);
- dsc->rd = rd;
- dsc->modinsn[0] = insn1;
- dsc->modinsn[1] = ((insn2 & 0xf0f0) | 0x1);
- dsc->numinsns = 2;
- dsc->cleanup = &cleanup_alu_imm;
- return 0;
- }
- /* Copy/cleanup arithmetic/logic insns with register RHS. */
- static void
- cleanup_alu_reg (struct gdbarch *gdbarch,
- regcache *regs, arm_displaced_step_copy_insn_closure *dsc)
- {
- ULONGEST rd_val;
- int i;
- rd_val = displaced_read_reg (regs, dsc, 0);
- for (i = 0; i < 3; i++)
- displaced_write_reg (regs, dsc, i, dsc->tmp[i], CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, dsc->rd, rd_val, ALU_WRITE_PC);
- }
- static void
- install_alu_reg (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc,
- unsigned int rd, unsigned int rn, unsigned int rm)
- {
- ULONGEST rd_val, rn_val, rm_val;
- /* Instruction is of form:
- <op><cond> rd, [rn,] rm [, <shift>]
- Rewrite as:
- Preparation: tmp1, tmp2, tmp3 <- r0, r1, r2;
- r0, r1, r2 <- rd, rn, rm
- Insn: <op><cond> r0, [r1,] r2 [, <shift>]
- Cleanup: rd <- r0; r0, r1, r2 <- tmp1, tmp2, tmp3
- */
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
- dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
- dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
- rd_val = displaced_read_reg (regs, dsc, rd);
- rn_val = displaced_read_reg (regs, dsc, rn);
- rm_val = displaced_read_reg (regs, dsc, rm);
- displaced_write_reg (regs, dsc, 0, rd_val, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 1, rn_val, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 2, rm_val, CANNOT_WRITE_PC);
- dsc->rd = rd;
- dsc->cleanup = &cleanup_alu_reg;
- }
- static int
- arm_copy_alu_reg (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int op = bits (insn, 21, 24);
- int is_mov = (op == 0xd);
- if (!insn_references_pc (insn, 0x000ff00ful))
- return arm_copy_unmodified (gdbarch, insn, "ALU reg", dsc);
- displaced_debug_printf ("copying reg %s insn %.8lx",
- is_mov ? "move" : "ALU", (unsigned long) insn);
- if (is_mov)
- dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x2;
- else
- dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x10002;
- install_alu_reg (gdbarch, regs, dsc, bits (insn, 12, 15), bits (insn, 16, 19),
- bits (insn, 0, 3));
- return 0;
- }
- static int
- thumb_copy_alu_reg (struct gdbarch *gdbarch, uint16_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned rm, rd;
- rm = bits (insn, 3, 6);
- rd = (bit (insn, 7) << 3) | bits (insn, 0, 2);
- if (rd != ARM_PC_REGNUM && rm != ARM_PC_REGNUM)
- return thumb_copy_unmodified_16bit (gdbarch, insn, "ALU reg", dsc);
- displaced_debug_printf ("copying ALU reg insn %.4x", (unsigned short) insn);
- dsc->modinsn[0] = ((insn & 0xff00) | 0x10);
- install_alu_reg (gdbarch, regs, dsc, rd, rd, rm);
- return 0;
- }
- /* Cleanup/copy arithmetic/logic insns with shifted register RHS. */
- static void
- cleanup_alu_shifted_reg (struct gdbarch *gdbarch,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- ULONGEST rd_val = displaced_read_reg (regs, dsc, 0);
- int i;
- for (i = 0; i < 4; i++)
- displaced_write_reg (regs, dsc, i, dsc->tmp[i], CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, dsc->rd, rd_val, ALU_WRITE_PC);
- }
- static void
- install_alu_shifted_reg (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc,
- unsigned int rd, unsigned int rn, unsigned int rm,
- unsigned rs)
- {
- int i;
- ULONGEST rd_val, rn_val, rm_val, rs_val;
- /* Instruction is of form:
- <op><cond> rd, [rn,] rm, <shift> rs
- Rewrite as:
- Preparation: tmp1, tmp2, tmp3, tmp4 <- r0, r1, r2, r3
- r0, r1, r2, r3 <- rd, rn, rm, rs
- Insn: <op><cond> r0, r1, r2, <shift> r3
- Cleanup: tmp5 <- r0
- r0, r1, r2, r3 <- tmp1, tmp2, tmp3, tmp4
- rd <- tmp5
- */
- for (i = 0; i < 4; i++)
- dsc->tmp[i] = displaced_read_reg (regs, dsc, i);
- rd_val = displaced_read_reg (regs, dsc, rd);
- rn_val = displaced_read_reg (regs, dsc, rn);
- rm_val = displaced_read_reg (regs, dsc, rm);
- rs_val = displaced_read_reg (regs, dsc, rs);
- displaced_write_reg (regs, dsc, 0, rd_val, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 1, rn_val, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 2, rm_val, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 3, rs_val, CANNOT_WRITE_PC);
- dsc->rd = rd;
- dsc->cleanup = &cleanup_alu_shifted_reg;
- }
- static int
- arm_copy_alu_shifted_reg (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int op = bits (insn, 21, 24);
- int is_mov = (op == 0xd);
- unsigned int rd, rn, rm, rs;
- if (!insn_references_pc (insn, 0x000fff0ful))
- return arm_copy_unmodified (gdbarch, insn, "ALU shifted reg", dsc);
- displaced_debug_printf ("copying shifted reg %s insn %.8lx",
- is_mov ? "move" : "ALU",
- (unsigned long) insn);
- rn = bits (insn, 16, 19);
- rm = bits (insn, 0, 3);
- rs = bits (insn, 8, 11);
- rd = bits (insn, 12, 15);
- if (is_mov)
- dsc->modinsn[0] = (insn & 0xfff000f0) | 0x302;
- else
- dsc->modinsn[0] = (insn & 0xfff000f0) | 0x10302;
- install_alu_shifted_reg (gdbarch, regs, dsc, rd, rn, rm, rs);
- return 0;
- }
- /* Clean up load instructions. */
- static void
- cleanup_load (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- ULONGEST rt_val, rt_val2 = 0, rn_val;
- rt_val = displaced_read_reg (regs, dsc, 0);
- if (dsc->u.ldst.xfersize == 8)
- rt_val2 = displaced_read_reg (regs, dsc, 1);
- rn_val = displaced_read_reg (regs, dsc, 2);
- displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
- if (dsc->u.ldst.xfersize > 4)
- displaced_write_reg (regs, dsc, 1, dsc->tmp[1], CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 2, dsc->tmp[2], CANNOT_WRITE_PC);
- if (!dsc->u.ldst.immed)
- displaced_write_reg (regs, dsc, 3, dsc->tmp[3], CANNOT_WRITE_PC);
- /* Handle register writeback. */
- if (dsc->u.ldst.writeback)
- displaced_write_reg (regs, dsc, dsc->u.ldst.rn, rn_val, CANNOT_WRITE_PC);
- /* Put result in right place. */
- displaced_write_reg (regs, dsc, dsc->rd, rt_val, LOAD_WRITE_PC);
- if (dsc->u.ldst.xfersize == 8)
- displaced_write_reg (regs, dsc, dsc->rd + 1, rt_val2, LOAD_WRITE_PC);
- }
- /* Clean up store instructions. */
- static void
- cleanup_store (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- ULONGEST rn_val = displaced_read_reg (regs, dsc, 2);
- displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
- if (dsc->u.ldst.xfersize > 4)
- displaced_write_reg (regs, dsc, 1, dsc->tmp[1], CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 2, dsc->tmp[2], CANNOT_WRITE_PC);
- if (!dsc->u.ldst.immed)
- displaced_write_reg (regs, dsc, 3, dsc->tmp[3], CANNOT_WRITE_PC);
- if (!dsc->u.ldst.restore_r4)
- displaced_write_reg (regs, dsc, 4, dsc->tmp[4], CANNOT_WRITE_PC);
- /* Writeback. */
- if (dsc->u.ldst.writeback)
- displaced_write_reg (regs, dsc, dsc->u.ldst.rn, rn_val, CANNOT_WRITE_PC);
- }
- /* Copy "extra" load/store instructions. These are halfword/doubleword
- transfers, which have a different encoding to byte/word transfers. */
- static int
- arm_copy_extra_ld_st (struct gdbarch *gdbarch, uint32_t insn, int unprivileged,
- regcache *regs, arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int op1 = bits (insn, 20, 24);
- unsigned int op2 = bits (insn, 5, 6);
- unsigned int rt = bits (insn, 12, 15);
- unsigned int rn = bits (insn, 16, 19);
- unsigned int rm = bits (insn, 0, 3);
- char load[12] = {0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1};
- char bytesize[12] = {2, 2, 2, 2, 8, 1, 8, 1, 8, 2, 8, 2};
- int immed = (op1 & 0x4) != 0;
- int opcode;
- ULONGEST rt_val, rt_val2 = 0, rn_val, rm_val = 0;
- if (!insn_references_pc (insn, 0x000ff00ful))
- return arm_copy_unmodified (gdbarch, insn, "extra load/store", dsc);
- displaced_debug_printf ("copying %sextra load/store insn %.8lx",
- unprivileged ? "unprivileged " : "",
- (unsigned long) insn);
- opcode = ((op2 << 2) | (op1 & 0x1) | ((op1 & 0x4) >> 1)) - 4;
- if (opcode < 0)
- internal_error (__FILE__, __LINE__,
- _("copy_extra_ld_st: instruction decode error"));
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
- dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
- dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
- if (!immed)
- dsc->tmp[3] = displaced_read_reg (regs, dsc, 3);
- rt_val = displaced_read_reg (regs, dsc, rt);
- if (bytesize[opcode] == 8)
- rt_val2 = displaced_read_reg (regs, dsc, rt + 1);
- rn_val = displaced_read_reg (regs, dsc, rn);
- if (!immed)
- rm_val = displaced_read_reg (regs, dsc, rm);
- displaced_write_reg (regs, dsc, 0, rt_val, CANNOT_WRITE_PC);
- if (bytesize[opcode] == 8)
- displaced_write_reg (regs, dsc, 1, rt_val2, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 2, rn_val, CANNOT_WRITE_PC);
- if (!immed)
- displaced_write_reg (regs, dsc, 3, rm_val, CANNOT_WRITE_PC);
- dsc->rd = rt;
- dsc->u.ldst.xfersize = bytesize[opcode];
- dsc->u.ldst.rn = rn;
- dsc->u.ldst.immed = immed;
- dsc->u.ldst.writeback = bit (insn, 24) == 0 || bit (insn, 21) != 0;
- dsc->u.ldst.restore_r4 = 0;
- if (immed)
- /* {ldr,str}<width><cond> rt, [rt2,] [rn, #imm]
- ->
- {ldr,str}<width><cond> r0, [r1,] [r2, #imm]. */
- dsc->modinsn[0] = (insn & 0xfff00fff) | 0x20000;
- else
- /* {ldr,str}<width><cond> rt, [rt2,] [rn, +/-rm]
- ->
- {ldr,str}<width><cond> r0, [r1,] [r2, +/-r3]. */
- dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x20003;
- dsc->cleanup = load[opcode] ? &cleanup_load : &cleanup_store;
- return 0;
- }
- /* Copy byte/half word/word loads and stores. */
- static void
- install_load_store (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc, int load,
- int immed, int writeback, int size, int usermode,
- int rt, int rm, int rn)
- {
- ULONGEST rt_val, rn_val, rm_val = 0;
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
- dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
- if (!immed)
- dsc->tmp[3] = displaced_read_reg (regs, dsc, 3);
- if (!load)
- dsc->tmp[4] = displaced_read_reg (regs, dsc, 4);
- rt_val = displaced_read_reg (regs, dsc, rt);
- rn_val = displaced_read_reg (regs, dsc, rn);
- if (!immed)
- rm_val = displaced_read_reg (regs, dsc, rm);
- displaced_write_reg (regs, dsc, 0, rt_val, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 2, rn_val, CANNOT_WRITE_PC);
- if (!immed)
- displaced_write_reg (regs, dsc, 3, rm_val, CANNOT_WRITE_PC);
- dsc->rd = rt;
- dsc->u.ldst.xfersize = size;
- dsc->u.ldst.rn = rn;
- dsc->u.ldst.immed = immed;
- dsc->u.ldst.writeback = writeback;
- /* To write PC we can do:
- Before this sequence of instructions:
- r0 is the PC value got from displaced_read_reg, so r0 = from + 8;
- r2 is the Rn value got from displaced_read_reg.
- Insn1: push {pc} Write address of STR instruction + offset on stack
- Insn2: pop {r4} Read it back from stack, r4 = addr(Insn1) + offset
- Insn3: sub r4, r4, pc r4 = addr(Insn1) + offset - pc
- = addr(Insn1) + offset - addr(Insn3) - 8
- = offset - 16
- Insn4: add r4, r4, #8 r4 = offset - 8
- Insn5: add r0, r0, r4 r0 = from + 8 + offset - 8
- = from + offset
- Insn6: str r0, [r2, #imm] (or str r0, [r2, r3])
- Otherwise we don't know what value to write for PC, since the offset is
- architecture-dependent (sometimes PC+8, sometimes PC+12). More details
- of this can be found in Section "Saving from r15" in
- http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204g/Cihbjifh.html */
- dsc->cleanup = load ? &cleanup_load : &cleanup_store;
- }
- static int
- thumb2_copy_load_literal (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc, int size)
- {
- unsigned int u_bit = bit (insn1, 7);
- unsigned int rt = bits (insn2, 12, 15);
- int imm12 = bits (insn2, 0, 11);
- ULONGEST pc_val;
- displaced_debug_printf ("copying ldr pc (0x%x) R%d %c imm12 %.4x",
- (unsigned int) dsc->insn_addr, rt, u_bit ? '+' : '-',
- imm12);
- if (!u_bit)
- imm12 = -1 * imm12;
- /* Rewrite instruction LDR Rt imm12 into:
- Prepare: tmp[0] <- r0, tmp[1] <- r2, tmp[2] <- r3, r2 <- pc, r3 <- imm12
- LDR R0, R2, R3,
- Cleanup: rt <- r0, r0 <- tmp[0], r2 <- tmp[1], r3 <- tmp[2]. */
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
- dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
- dsc->tmp[3] = displaced_read_reg (regs, dsc, 3);
- pc_val = displaced_read_reg (regs, dsc, ARM_PC_REGNUM);
- pc_val = pc_val & 0xfffffffc;
- displaced_write_reg (regs, dsc, 2, pc_val, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 3, imm12, CANNOT_WRITE_PC);
- dsc->rd = rt;
- dsc->u.ldst.xfersize = size;
- dsc->u.ldst.immed = 0;
- dsc->u.ldst.writeback = 0;
- dsc->u.ldst.restore_r4 = 0;
- /* LDR R0, R2, R3 */
- dsc->modinsn[0] = 0xf852;
- dsc->modinsn[1] = 0x3;
- dsc->numinsns = 2;
- dsc->cleanup = &cleanup_load;
- return 0;
- }
- static int
- thumb2_copy_load_reg_imm (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc,
- int writeback, int immed)
- {
- unsigned int rt = bits (insn2, 12, 15);
- unsigned int rn = bits (insn1, 0, 3);
- unsigned int rm = bits (insn2, 0, 3); /* Only valid if !immed. */
- /* In LDR (register), there is also a register Rm, which is not allowed to
- be PC, so we don't have to check it. */
- if (rt != ARM_PC_REGNUM && rn != ARM_PC_REGNUM)
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2, "load",
- dsc);
- displaced_debug_printf ("copying ldr r%d [r%d] insn %.4x%.4x",
- rt, rn, insn1, insn2);
- install_load_store (gdbarch, regs, dsc, 1, immed, writeback, 4,
- 0, rt, rm, rn);
- dsc->u.ldst.restore_r4 = 0;
- if (immed)
- /* ldr[b]<cond> rt, [rn, #imm], etc.
- ->
- ldr[b]<cond> r0, [r2, #imm]. */
- {
- dsc->modinsn[0] = (insn1 & 0xfff0) | 0x2;
- dsc->modinsn[1] = insn2 & 0x0fff;
- }
- else
- /* ldr[b]<cond> rt, [rn, rm], etc.
- ->
- ldr[b]<cond> r0, [r2, r3]. */
- {
- dsc->modinsn[0] = (insn1 & 0xfff0) | 0x2;
- dsc->modinsn[1] = (insn2 & 0x0ff0) | 0x3;
- }
- dsc->numinsns = 2;
- return 0;
- }
- static int
- arm_copy_ldr_str_ldrb_strb (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc,
- int load, int size, int usermode)
- {
- int immed = !bit (insn, 25);
- int writeback = (bit (insn, 24) == 0 || bit (insn, 21) != 0);
- unsigned int rt = bits (insn, 12, 15);
- unsigned int rn = bits (insn, 16, 19);
- unsigned int rm = bits (insn, 0, 3); /* Only valid if !immed. */
- if (!insn_references_pc (insn, 0x000ff00ful))
- return arm_copy_unmodified (gdbarch, insn, "load/store", dsc);
- displaced_debug_printf ("copying %s%s r%d [r%d] insn %.8lx",
- load ? (size == 1 ? "ldrb" : "ldr")
- : (size == 1 ? "strb" : "str"),
- usermode ? "t" : "",
- rt, rn,
- (unsigned long) insn);
- install_load_store (gdbarch, regs, dsc, load, immed, writeback, size,
- usermode, rt, rm, rn);
- if (load || rt != ARM_PC_REGNUM)
- {
- dsc->u.ldst.restore_r4 = 0;
- if (immed)
- /* {ldr,str}[b]<cond> rt, [rn, #imm], etc.
- ->
- {ldr,str}[b]<cond> r0, [r2, #imm]. */
- dsc->modinsn[0] = (insn & 0xfff00fff) | 0x20000;
- else
- /* {ldr,str}[b]<cond> rt, [rn, rm], etc.
- ->
- {ldr,str}[b]<cond> r0, [r2, r3]. */
- dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x20003;
- }
- else
- {
- /* We need to use r4 as scratch. Make sure it's restored afterwards. */
- dsc->u.ldst.restore_r4 = 1;
- dsc->modinsn[0] = 0xe92d8000; /* push {pc} */
- dsc->modinsn[1] = 0xe8bd0010; /* pop {r4} */
- dsc->modinsn[2] = 0xe044400f; /* sub r4, r4, pc. */
- dsc->modinsn[3] = 0xe2844008; /* add r4, r4, #8. */
- dsc->modinsn[4] = 0xe0800004; /* add r0, r0, r4. */
- /* As above. */
- if (immed)
- dsc->modinsn[5] = (insn & 0xfff00fff) | 0x20000;
- else
- dsc->modinsn[5] = (insn & 0xfff00ff0) | 0x20003;
- dsc->numinsns = 6;
- }
- dsc->cleanup = load ? &cleanup_load : &cleanup_store;
- return 0;
- }
- /* Cleanup LDM instructions with fully-populated register list. This is an
- unfortunate corner case: it's impossible to implement correctly by modifying
- the instruction. The issue is as follows: we have an instruction,
- ldm rN, {r0-r15}
- which we must rewrite to avoid loading PC. A possible solution would be to
- do the load in two halves, something like (with suitable cleanup
- afterwards):
- mov r8, rN
- ldm[id][ab] r8!, {r0-r7}
- str r7, <temp>
- ldm[id][ab] r8, {r7-r14}
- <bkpt>
- but at present there's no suitable place for <temp>, since the scratch space
- is overwritten before the cleanup routine is called. For now, we simply
- emulate the instruction. */
- static void
- cleanup_block_load_all (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- int inc = dsc->u.block.increment;
- int bump_before = dsc->u.block.before ? (inc ? 4 : -4) : 0;
- int bump_after = dsc->u.block.before ? 0 : (inc ? 4 : -4);
- uint32_t regmask = dsc->u.block.regmask;
- int regno = inc ? 0 : 15;
- CORE_ADDR xfer_addr = dsc->u.block.xfer_addr;
- int exception_return = dsc->u.block.load && dsc->u.block.user
- && (regmask & 0x8000) != 0;
- uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
- int do_transfer = condition_true (dsc->u.block.cond, status);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- if (!do_transfer)
- return;
- /* If the instruction is ldm rN, {...pc}^, I don't think there's anything
- sensible we can do here. Complain loudly. */
- if (exception_return)
- error (_("Cannot single-step exception return"));
- /* We don't handle any stores here for now. */
- gdb_assert (dsc->u.block.load != 0);
- displaced_debug_printf ("emulating block transfer: %s %s %s",
- dsc->u.block.load ? "ldm" : "stm",
- dsc->u.block.increment ? "inc" : "dec",
- dsc->u.block.before ? "before" : "after");
- while (regmask)
- {
- uint32_t memword;
- if (inc)
- while (regno <= ARM_PC_REGNUM && (regmask & (1 << regno)) == 0)
- regno++;
- else
- while (regno >= 0 && (regmask & (1 << regno)) == 0)
- regno--;
- xfer_addr += bump_before;
- memword = read_memory_unsigned_integer (xfer_addr, 4, byte_order);
- displaced_write_reg (regs, dsc, regno, memword, LOAD_WRITE_PC);
- xfer_addr += bump_after;
- regmask &= ~(1 << regno);
- }
- if (dsc->u.block.writeback)
- displaced_write_reg (regs, dsc, dsc->u.block.rn, xfer_addr,
- CANNOT_WRITE_PC);
- }
- /* Clean up an STM which included the PC in the register list. */
- static void
- cleanup_block_store_pc (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
- int store_executed = condition_true (dsc->u.block.cond, status);
- CORE_ADDR pc_stored_at, transferred_regs
- = count_one_bits (dsc->u.block.regmask);
- CORE_ADDR stm_insn_addr;
- uint32_t pc_val;
- long offset;
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- /* If condition code fails, there's nothing else to do. */
- if (!store_executed)
- return;
- if (dsc->u.block.increment)
- {
- pc_stored_at = dsc->u.block.xfer_addr + 4 * transferred_regs;
- if (dsc->u.block.before)
- pc_stored_at += 4;
- }
- else
- {
- pc_stored_at = dsc->u.block.xfer_addr;
- if (dsc->u.block.before)
- pc_stored_at -= 4;
- }
- pc_val = read_memory_unsigned_integer (pc_stored_at, 4, byte_order);
- stm_insn_addr = dsc->scratch_base;
- offset = pc_val - stm_insn_addr;
- displaced_debug_printf ("detected PC offset %.8lx for STM instruction",
- offset);
- /* Rewrite the stored PC to the proper value for the non-displaced original
- instruction. */
- write_memory_unsigned_integer (pc_stored_at, 4, byte_order,
- dsc->insn_addr + offset);
- }
- /* Clean up an LDM which includes the PC in the register list. We clumped all
- the registers in the transferred list into a contiguous range r0...rX (to
- avoid loading PC directly and losing control of the debugged program), so we
- must undo that here. */
- static void
- cleanup_block_load_pc (struct gdbarch *gdbarch,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM);
- int load_executed = condition_true (dsc->u.block.cond, status);
- unsigned int mask = dsc->u.block.regmask, write_reg = ARM_PC_REGNUM;
- unsigned int regs_loaded = count_one_bits (mask);
- unsigned int num_to_shuffle = regs_loaded, clobbered;
- /* The method employed here will fail if the register list is fully populated
- (we need to avoid loading PC directly). */
- gdb_assert (num_to_shuffle < 16);
- if (!load_executed)
- return;
- clobbered = (1 << num_to_shuffle) - 1;
- while (num_to_shuffle > 0)
- {
- if ((mask & (1 << write_reg)) != 0)
- {
- unsigned int read_reg = num_to_shuffle - 1;
- if (read_reg != write_reg)
- {
- ULONGEST rval = displaced_read_reg (regs, dsc, read_reg);
- displaced_write_reg (regs, dsc, write_reg, rval, LOAD_WRITE_PC);
- displaced_debug_printf ("LDM: move loaded register r%d to r%d",
- read_reg, write_reg);
- }
- else
- displaced_debug_printf ("LDM: register r%d already in the right "
- "place", write_reg);
- clobbered &= ~(1 << write_reg);
- num_to_shuffle--;
- }
- write_reg--;
- }
- /* Restore any registers we scribbled over. */
- for (write_reg = 0; clobbered != 0; write_reg++)
- {
- if ((clobbered & (1 << write_reg)) != 0)
- {
- displaced_write_reg (regs, dsc, write_reg, dsc->tmp[write_reg],
- CANNOT_WRITE_PC);
- displaced_debug_printf ("LDM: restored clobbered register r%d",
- write_reg);
- clobbered &= ~(1 << write_reg);
- }
- }
- /* Perform register writeback manually. */
- if (dsc->u.block.writeback)
- {
- ULONGEST new_rn_val = dsc->u.block.xfer_addr;
- if (dsc->u.block.increment)
- new_rn_val += regs_loaded * 4;
- else
- new_rn_val -= regs_loaded * 4;
- displaced_write_reg (regs, dsc, dsc->u.block.rn, new_rn_val,
- CANNOT_WRITE_PC);
- }
- }
- /* Handle ldm/stm, apart from some tricky cases which are unlikely to occur
- in user-level code (in particular exception return, ldm rn, {...pc}^). */
- static int
- arm_copy_block_xfer (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- int load = bit (insn, 20);
- int user = bit (insn, 22);
- int increment = bit (insn, 23);
- int before = bit (insn, 24);
- int writeback = bit (insn, 21);
- int rn = bits (insn, 16, 19);
- /* Block transfers which don't mention PC can be run directly
- out-of-line. */
- if (rn != ARM_PC_REGNUM && (insn & 0x8000) == 0)
- return arm_copy_unmodified (gdbarch, insn, "ldm/stm", dsc);
- if (rn == ARM_PC_REGNUM)
- {
- warning (_("displaced: Unpredictable LDM or STM with "
- "base register r15"));
- return arm_copy_unmodified (gdbarch, insn, "unpredictable ldm/stm", dsc);
- }
- displaced_debug_printf ("copying block transfer insn %.8lx",
- (unsigned long) insn);
- dsc->u.block.xfer_addr = displaced_read_reg (regs, dsc, rn);
- dsc->u.block.rn = rn;
- dsc->u.block.load = load;
- dsc->u.block.user = user;
- dsc->u.block.increment = increment;
- dsc->u.block.before = before;
- dsc->u.block.writeback = writeback;
- dsc->u.block.cond = bits (insn, 28, 31);
- dsc->u.block.regmask = insn & 0xffff;
- if (load)
- {
- if ((insn & 0xffff) == 0xffff)
- {
- /* LDM with a fully-populated register list. This case is
- particularly tricky. Implement for now by fully emulating the
- instruction (which might not behave perfectly in all cases, but
- these instructions should be rare enough for that not to matter
- too much). */
- dsc->modinsn[0] = ARM_NOP;
- dsc->cleanup = &cleanup_block_load_all;
- }
- else
- {
- /* LDM of a list of registers which includes PC. Implement by
- rewriting the list of registers to be transferred into a
- contiguous chunk r0...rX before doing the transfer, then shuffling
- registers into the correct places in the cleanup routine. */
- unsigned int regmask = insn & 0xffff;
- unsigned int num_in_list = count_one_bits (regmask), new_regmask;
- unsigned int i;
- for (i = 0; i < num_in_list; i++)
- dsc->tmp[i] = displaced_read_reg (regs, dsc, i);
- /* Writeback makes things complicated. We need to avoid clobbering
- the base register with one of the registers in our modified
- register list, but just using a different register can't work in
- all cases, e.g.:
- ldm r14!, {r0-r13,pc}
- which would need to be rewritten as:
- ldm rN!, {r0-r14}
- but that can't work, because there's no free register for N.
- Solve this by turning off the writeback bit, and emulating
- writeback manually in the cleanup routine. */
- if (writeback)
- insn &= ~(1 << 21);
- new_regmask = (1 << num_in_list) - 1;
- displaced_debug_printf ("LDM r%d%s, {..., pc}: original reg list "
- "%.4x, modified list %.4x",
- rn, writeback ? "!" : "",
- (int) insn & 0xffff, new_regmask);
- dsc->modinsn[0] = (insn & ~0xffff) | (new_regmask & 0xffff);
- dsc->cleanup = &cleanup_block_load_pc;
- }
- }
- else
- {
- /* STM of a list of registers which includes PC. Run the instruction
- as-is, but out of line: this will store the wrong value for the PC,
- so we must manually fix up the memory in the cleanup routine.
- Doing things this way has the advantage that we can auto-detect
- the offset of the PC write (which is architecture-dependent) in
- the cleanup routine. */
- dsc->modinsn[0] = insn;
- dsc->cleanup = &cleanup_block_store_pc;
- }
- return 0;
- }
- static int
- thumb2_copy_block_xfer (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- int rn = bits (insn1, 0, 3);
- int load = bit (insn1, 4);
- int writeback = bit (insn1, 5);
- /* Block transfers which don't mention PC can be run directly
- out-of-line. */
- if (rn != ARM_PC_REGNUM && (insn2 & 0x8000) == 0)
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2, "ldm/stm", dsc);
- if (rn == ARM_PC_REGNUM)
- {
- warning (_("displaced: Unpredictable LDM or STM with "
- "base register r15"));
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "unpredictable ldm/stm", dsc);
- }
- displaced_debug_printf ("copying block transfer insn %.4x%.4x",
- insn1, insn2);
- /* Clear bit 13, since it should be always zero. */
- dsc->u.block.regmask = (insn2 & 0xdfff);
- dsc->u.block.rn = rn;
- dsc->u.block.load = load;
- dsc->u.block.user = 0;
- dsc->u.block.increment = bit (insn1, 7);
- dsc->u.block.before = bit (insn1, 8);
- dsc->u.block.writeback = writeback;
- dsc->u.block.cond = INST_AL;
- dsc->u.block.xfer_addr = displaced_read_reg (regs, dsc, rn);
- if (load)
- {
- if (dsc->u.block.regmask == 0xffff)
- {
- /* This branch is impossible to happen. */
- gdb_assert (0);
- }
- else
- {
- unsigned int regmask = dsc->u.block.regmask;
- unsigned int num_in_list = count_one_bits (regmask), new_regmask;
- unsigned int i;
- for (i = 0; i < num_in_list; i++)
- dsc->tmp[i] = displaced_read_reg (regs, dsc, i);
- if (writeback)
- insn1 &= ~(1 << 5);
- new_regmask = (1 << num_in_list) - 1;
- displaced_debug_printf ("LDM r%d%s, {..., pc}: original reg list "
- "%.4x, modified list %.4x",
- rn, writeback ? "!" : "",
- (int) dsc->u.block.regmask, new_regmask);
- dsc->modinsn[0] = insn1;
- dsc->modinsn[1] = (new_regmask & 0xffff);
- dsc->numinsns = 2;
- dsc->cleanup = &cleanup_block_load_pc;
- }
- }
- else
- {
- dsc->modinsn[0] = insn1;
- dsc->modinsn[1] = insn2;
- dsc->numinsns = 2;
- dsc->cleanup = &cleanup_block_store_pc;
- }
- return 0;
- }
- /* Wrapper over read_memory_unsigned_integer for use in arm_get_next_pcs.
- This is used to avoid a dependency on BFD's bfd_endian enum. */
- ULONGEST
- arm_get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr, int len,
- int byte_order)
- {
- return read_memory_unsigned_integer (memaddr, len,
- (enum bfd_endian) byte_order);
- }
- /* Wrapper over gdbarch_addr_bits_remove for use in arm_get_next_pcs. */
- CORE_ADDR
- arm_get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self,
- CORE_ADDR val)
- {
- return gdbarch_addr_bits_remove (self->regcache->arch (), val);
- }
- /* Wrapper over syscall_next_pc for use in get_next_pcs. */
- static CORE_ADDR
- arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self)
- {
- return 0;
- }
- /* Wrapper over arm_is_thumb for use in arm_get_next_pcs. */
- int
- arm_get_next_pcs_is_thumb (struct arm_get_next_pcs *self)
- {
- return arm_is_thumb (self->regcache);
- }
- /* single_step() is called just before we want to resume the inferior,
- if we want to single-step it but there is no hardware or kernel
- single-step support. We find the target of the coming instructions
- and breakpoint them. */
- std::vector<CORE_ADDR>
- arm_software_single_step (struct regcache *regcache)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- struct arm_get_next_pcs next_pcs_ctx;
- arm_get_next_pcs_ctor (&next_pcs_ctx,
- &arm_get_next_pcs_ops,
- gdbarch_byte_order (gdbarch),
- gdbarch_byte_order_for_code (gdbarch),
- 0,
- regcache);
- std::vector<CORE_ADDR> next_pcs = arm_get_next_pcs (&next_pcs_ctx);
- for (CORE_ADDR &pc_ref : next_pcs)
- pc_ref = gdbarch_addr_bits_remove (gdbarch, pc_ref);
- return next_pcs;
- }
- /* Cleanup/copy SVC (SWI) instructions. These two functions are overridden
- for Linux, where some SVC instructions must be treated specially. */
- static void
- cleanup_svc (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- CORE_ADDR resume_addr = dsc->insn_addr + dsc->insn_size;
- displaced_debug_printf ("cleanup for svc, resume at %.8lx",
- (unsigned long) resume_addr);
- displaced_write_reg (regs, dsc, ARM_PC_REGNUM, resume_addr, BRANCH_WRITE_PC);
- }
- /* Common copy routine for svc instruction. */
- static int
- install_svc (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- /* Preparation: none.
- Insn: unmodified svc.
- Cleanup: pc <- insn_addr + insn_size. */
- /* Pretend we wrote to the PC, so cleanup doesn't set PC to the next
- instruction. */
- dsc->wrote_to_pc = 1;
- /* Allow OS-specific code to override SVC handling. */
- if (dsc->u.svc.copy_svc_os)
- return dsc->u.svc.copy_svc_os (gdbarch, regs, dsc);
- else
- {
- dsc->cleanup = &cleanup_svc;
- return 0;
- }
- }
- static int
- arm_copy_svc (struct gdbarch *gdbarch, uint32_t insn,
- regcache *regs, arm_displaced_step_copy_insn_closure *dsc)
- {
- displaced_debug_printf ("copying svc insn %.8lx",
- (unsigned long) insn);
- dsc->modinsn[0] = insn;
- return install_svc (gdbarch, regs, dsc);
- }
- static int
- thumb_copy_svc (struct gdbarch *gdbarch, uint16_t insn,
- regcache *regs, arm_displaced_step_copy_insn_closure *dsc)
- {
- displaced_debug_printf ("copying svc insn %.4x", insn);
- dsc->modinsn[0] = insn;
- return install_svc (gdbarch, regs, dsc);
- }
- /* Copy undefined instructions. */
- static int
- arm_copy_undef (struct gdbarch *gdbarch, uint32_t insn,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- displaced_debug_printf ("copying undefined insn %.8lx",
- (unsigned long) insn);
- dsc->modinsn[0] = insn;
- return 0;
- }
- static int
- thumb_32bit_copy_undef (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- displaced_debug_printf ("copying undefined insn %.4x %.4x",
- (unsigned short) insn1, (unsigned short) insn2);
- dsc->modinsn[0] = insn1;
- dsc->modinsn[1] = insn2;
- dsc->numinsns = 2;
- return 0;
- }
- /* Copy unpredictable instructions. */
- static int
- arm_copy_unpred (struct gdbarch *gdbarch, uint32_t insn,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- displaced_debug_printf ("copying unpredictable insn %.8lx",
- (unsigned long) insn);
- dsc->modinsn[0] = insn;
- return 0;
- }
- /* The decode_* functions are instruction decoding helpers. They mostly follow
- the presentation in the ARM ARM. */
- static int
- arm_decode_misc_memhint_neon (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7);
- unsigned int rn = bits (insn, 16, 19);
- if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0x1) == 0x0)
- return arm_copy_unmodified (gdbarch, insn, "cps", dsc);
- else if (op1 == 0x10 && op2 == 0x0 && (rn & 0x1) == 0x1)
- return arm_copy_unmodified (gdbarch, insn, "setend", dsc);
- else if ((op1 & 0x60) == 0x20)
- return arm_copy_unmodified (gdbarch, insn, "neon dataproc", dsc);
- else if ((op1 & 0x71) == 0x40)
- return arm_copy_unmodified (gdbarch, insn, "neon elt/struct load/store",
- dsc);
- else if ((op1 & 0x77) == 0x41)
- return arm_copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
- else if ((op1 & 0x77) == 0x45)
- return arm_copy_preload (gdbarch, insn, regs, dsc); /* pli. */
- else if ((op1 & 0x77) == 0x51)
- {
- if (rn != 0xf)
- return arm_copy_preload (gdbarch, insn, regs, dsc); /* pld/pldw. */
- else
- return arm_copy_unpred (gdbarch, insn, dsc);
- }
- else if ((op1 & 0x77) == 0x55)
- return arm_copy_preload (gdbarch, insn, regs, dsc); /* pld/pldw. */
- else if (op1 == 0x57)
- switch (op2)
- {
- case 0x1: return arm_copy_unmodified (gdbarch, insn, "clrex", dsc);
- case 0x4: return arm_copy_unmodified (gdbarch, insn, "dsb", dsc);
- case 0x5: return arm_copy_unmodified (gdbarch, insn, "dmb", dsc);
- case 0x6: return arm_copy_unmodified (gdbarch, insn, "isb", dsc);
- default: return arm_copy_unpred (gdbarch, insn, dsc);
- }
- else if ((op1 & 0x63) == 0x43)
- return arm_copy_unpred (gdbarch, insn, dsc);
- else if ((op2 & 0x1) == 0x0)
- switch (op1 & ~0x80)
- {
- case 0x61:
- return arm_copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
- case 0x65:
- return arm_copy_preload_reg (gdbarch, insn, regs, dsc); /* pli reg. */
- case 0x71: case 0x75:
- /* pld/pldw reg. */
- return arm_copy_preload_reg (gdbarch, insn, regs, dsc);
- case 0x63: case 0x67: case 0x73: case 0x77:
- return arm_copy_unpred (gdbarch, insn, dsc);
- default:
- return arm_copy_undef (gdbarch, insn, dsc);
- }
- else
- return arm_copy_undef (gdbarch, insn, dsc); /* Probably unreachable. */
- }
- static int
- arm_decode_unconditional (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- if (bit (insn, 27) == 0)
- return arm_decode_misc_memhint_neon (gdbarch, insn, regs, dsc);
- /* Switch on bits: 0bxxxxx321xxx0xxxxxxxxxxxxxxxxxxxx. */
- else switch (((insn & 0x7000000) >> 23) | ((insn & 0x100000) >> 20))
- {
- case 0x0: case 0x2:
- return arm_copy_unmodified (gdbarch, insn, "srs", dsc);
- case 0x1: case 0x3:
- return arm_copy_unmodified (gdbarch, insn, "rfe", dsc);
- case 0x4: case 0x5: case 0x6: case 0x7:
- return arm_copy_b_bl_blx (gdbarch, insn, regs, dsc);
- case 0x8:
- switch ((insn & 0xe00000) >> 21)
- {
- case 0x1: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
- /* stc/stc2. */
- return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
- case 0x2:
- return arm_copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
- default:
- return arm_copy_undef (gdbarch, insn, dsc);
- }
- case 0x9:
- {
- int rn_f = (bits (insn, 16, 19) == 0xf);
- switch ((insn & 0xe00000) >> 21)
- {
- case 0x1: case 0x3:
- /* ldc/ldc2 imm (undefined for rn == pc). */
- return rn_f ? arm_copy_undef (gdbarch, insn, dsc)
- : arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
- case 0x2:
- return arm_copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
- case 0x4: case 0x5: case 0x6: case 0x7:
- /* ldc/ldc2 lit (undefined for rn != pc). */
- return rn_f ? arm_copy_copro_load_store (gdbarch, insn, regs, dsc)
- : arm_copy_undef (gdbarch, insn, dsc);
- default:
- return arm_copy_undef (gdbarch, insn, dsc);
- }
- }
- case 0xa:
- return arm_copy_unmodified (gdbarch, insn, "stc/stc2", dsc);
- case 0xb:
- if (bits (insn, 16, 19) == 0xf)
- /* ldc/ldc2 lit. */
- return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
- else
- return arm_copy_undef (gdbarch, insn, dsc);
- case 0xc:
- if (bit (insn, 4))
- return arm_copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
- else
- return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
- case 0xd:
- if (bit (insn, 4))
- return arm_copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
- else
- return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
- default:
- return arm_copy_undef (gdbarch, insn, dsc);
- }
- }
- /* Decode miscellaneous instructions in dp/misc encoding space. */
- static int
- arm_decode_miscellaneous (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int op2 = bits (insn, 4, 6);
- unsigned int op = bits (insn, 21, 22);
- switch (op2)
- {
- case 0x0:
- return arm_copy_unmodified (gdbarch, insn, "mrs/msr", dsc);
- case 0x1:
- if (op == 0x1) /* bx. */
- return arm_copy_bx_blx_reg (gdbarch, insn, regs, dsc);
- else if (op == 0x3)
- return arm_copy_unmodified (gdbarch, insn, "clz", dsc);
- else
- return arm_copy_undef (gdbarch, insn, dsc);
- case 0x2:
- if (op == 0x1)
- /* Not really supported. */
- return arm_copy_unmodified (gdbarch, insn, "bxj", dsc);
- else
- return arm_copy_undef (gdbarch, insn, dsc);
- case 0x3:
- if (op == 0x1)
- return arm_copy_bx_blx_reg (gdbarch, insn,
- regs, dsc); /* blx register. */
- else
- return arm_copy_undef (gdbarch, insn, dsc);
- case 0x5:
- return arm_copy_unmodified (gdbarch, insn, "saturating add/sub", dsc);
- case 0x7:
- if (op == 0x1)
- return arm_copy_unmodified (gdbarch, insn, "bkpt", dsc);
- else if (op == 0x3)
- /* Not really supported. */
- return arm_copy_unmodified (gdbarch, insn, "smc", dsc);
- /* Fall through. */
- default:
- return arm_copy_undef (gdbarch, insn, dsc);
- }
- }
- static int
- arm_decode_dp_misc (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- if (bit (insn, 25))
- switch (bits (insn, 20, 24))
- {
- case 0x10:
- return arm_copy_unmodified (gdbarch, insn, "movw", dsc);
- case 0x14:
- return arm_copy_unmodified (gdbarch, insn, "movt", dsc);
- case 0x12: case 0x16:
- return arm_copy_unmodified (gdbarch, insn, "msr imm", dsc);
- default:
- return arm_copy_alu_imm (gdbarch, insn, regs, dsc);
- }
- else
- {
- uint32_t op1 = bits (insn, 20, 24), op2 = bits (insn, 4, 7);
- if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0)
- return arm_copy_alu_reg (gdbarch, insn, regs, dsc);
- else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1)
- return arm_copy_alu_shifted_reg (gdbarch, insn, regs, dsc);
- else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0)
- return arm_decode_miscellaneous (gdbarch, insn, regs, dsc);
- else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8)
- return arm_copy_unmodified (gdbarch, insn, "halfword mul/mla", dsc);
- else if ((op1 & 0x10) == 0x00 && op2 == 0x9)
- return arm_copy_unmodified (gdbarch, insn, "mul/mla", dsc);
- else if ((op1 & 0x10) == 0x10 && op2 == 0x9)
- return arm_copy_unmodified (gdbarch, insn, "synch", dsc);
- else if (op2 == 0xb || (op2 & 0xd) == 0xd)
- /* 2nd arg means "unprivileged". */
- return arm_copy_extra_ld_st (gdbarch, insn, (op1 & 0x12) == 0x02, regs,
- dsc);
- }
- /* Should be unreachable. */
- return 1;
- }
- static int
- arm_decode_ld_st_word_ubyte (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- int a = bit (insn, 25), b = bit (insn, 4);
- uint32_t op1 = bits (insn, 20, 24);
- if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02)
- || (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b))
- return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 4, 0);
- else if ((!a && (op1 & 0x17) == 0x02)
- || (a && (op1 & 0x17) == 0x02 && !b))
- return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 4, 1);
- else if ((!a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03)
- || (a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03 && !b))
- return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 4, 0);
- else if ((!a && (op1 & 0x17) == 0x03)
- || (a && (op1 & 0x17) == 0x03 && !b))
- return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 4, 1);
- else if ((!a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06)
- || (a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06 && !b))
- return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 0);
- else if ((!a && (op1 & 0x17) == 0x06)
- || (a && (op1 & 0x17) == 0x06 && !b))
- return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 1);
- else if ((!a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07)
- || (a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07 && !b))
- return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 0);
- else if ((!a && (op1 & 0x17) == 0x07)
- || (a && (op1 & 0x17) == 0x07 && !b))
- return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 1);
- /* Should be unreachable. */
- return 1;
- }
- static int
- arm_decode_media (struct gdbarch *gdbarch, uint32_t insn,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- switch (bits (insn, 20, 24))
- {
- case 0x00: case 0x01: case 0x02: case 0x03:
- return arm_copy_unmodified (gdbarch, insn, "parallel add/sub signed", dsc);
- case 0x04: case 0x05: case 0x06: case 0x07:
- return arm_copy_unmodified (gdbarch, insn, "parallel add/sub unsigned", dsc);
- case 0x08: case 0x09: case 0x0a: case 0x0b:
- case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- return arm_copy_unmodified (gdbarch, insn,
- "decode/pack/unpack/saturate/reverse", dsc);
- case 0x18:
- if (bits (insn, 5, 7) == 0) /* op2. */
- {
- if (bits (insn, 12, 15) == 0xf)
- return arm_copy_unmodified (gdbarch, insn, "usad8", dsc);
- else
- return arm_copy_unmodified (gdbarch, insn, "usada8", dsc);
- }
- else
- return arm_copy_undef (gdbarch, insn, dsc);
- case 0x1a: case 0x1b:
- if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */
- return arm_copy_unmodified (gdbarch, insn, "sbfx", dsc);
- else
- return arm_copy_undef (gdbarch, insn, dsc);
- case 0x1c: case 0x1d:
- if (bits (insn, 5, 6) == 0x0) /* op2[1:0]. */
- {
- if (bits (insn, 0, 3) == 0xf)
- return arm_copy_unmodified (gdbarch, insn, "bfc", dsc);
- else
- return arm_copy_unmodified (gdbarch, insn, "bfi", dsc);
- }
- else
- return arm_copy_undef (gdbarch, insn, dsc);
- case 0x1e: case 0x1f:
- if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */
- return arm_copy_unmodified (gdbarch, insn, "ubfx", dsc);
- else
- return arm_copy_undef (gdbarch, insn, dsc);
- }
- /* Should be unreachable. */
- return 1;
- }
- static int
- arm_decode_b_bl_ldmstm (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- if (bit (insn, 25))
- return arm_copy_b_bl_blx (gdbarch, insn, regs, dsc);
- else
- return arm_copy_block_xfer (gdbarch, insn, regs, dsc);
- }
- static int
- arm_decode_ext_reg_ld_st (struct gdbarch *gdbarch, uint32_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int opcode = bits (insn, 20, 24);
- switch (opcode)
- {
- case 0x04: case 0x05: /* VFP/Neon mrrc/mcrr. */
- return arm_copy_unmodified (gdbarch, insn, "vfp/neon mrrc/mcrr", dsc);
- case 0x08: case 0x0a: case 0x0c: case 0x0e:
- case 0x12: case 0x16:
- return arm_copy_unmodified (gdbarch, insn, "vfp/neon vstm/vpush", dsc);
- case 0x09: case 0x0b: case 0x0d: case 0x0f:
- case 0x13: case 0x17:
- return arm_copy_unmodified (gdbarch, insn, "vfp/neon vldm/vpop", dsc);
- case 0x10: case 0x14: case 0x18: case 0x1c: /* vstr. */
- case 0x11: case 0x15: case 0x19: case 0x1d: /* vldr. */
- /* Note: no writeback for these instructions. Bit 25 will always be
- zero though (via caller), so the following works OK. */
- return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
- }
- /* Should be unreachable. */
- return 1;
- }
- /* Decode shifted register instructions. */
- static int
- thumb2_decode_dp_shift_reg (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- /* PC is only allowed to be used in instruction MOV. */
- unsigned int op = bits (insn1, 5, 8);
- unsigned int rn = bits (insn1, 0, 3);
- if (op == 0x2 && rn == 0xf) /* MOV */
- return thumb2_copy_alu_imm (gdbarch, insn1, insn2, regs, dsc);
- else
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "dp (shift reg)", dsc);
- }
- /* Decode extension register load/store. Exactly the same as
- arm_decode_ext_reg_ld_st. */
- static int
- thumb2_decode_ext_reg_ld_st (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int opcode = bits (insn1, 4, 8);
- switch (opcode)
- {
- case 0x04: case 0x05:
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "vfp/neon vmov", dsc);
- case 0x08: case 0x0c: /* 01x00 */
- case 0x0a: case 0x0e: /* 01x10 */
- case 0x12: case 0x16: /* 10x10 */
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "vfp/neon vstm/vpush", dsc);
- case 0x09: case 0x0d: /* 01x01 */
- case 0x0b: case 0x0f: /* 01x11 */
- case 0x13: case 0x17: /* 10x11 */
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "vfp/neon vldm/vpop", dsc);
- case 0x10: case 0x14: case 0x18: case 0x1c: /* vstr. */
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "vstr", dsc);
- case 0x11: case 0x15: case 0x19: case 0x1d: /* vldr. */
- return thumb2_copy_copro_load_store (gdbarch, insn1, insn2, regs, dsc);
- }
- /* Should be unreachable. */
- return 1;
- }
- static int
- arm_decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn,
- regcache *regs, arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int op1 = bits (insn, 20, 25);
- int op = bit (insn, 4);
- unsigned int coproc = bits (insn, 8, 11);
- if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa)
- return arm_decode_ext_reg_ld_st (gdbarch, insn, regs, dsc);
- else if ((op1 & 0x21) == 0x00 && (op1 & 0x3a) != 0x00
- && (coproc & 0xe) != 0xa)
- /* stc/stc2. */
- return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
- else if ((op1 & 0x21) == 0x01 && (op1 & 0x3a) != 0x00
- && (coproc & 0xe) != 0xa)
- /* ldc/ldc2 imm/lit. */
- return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
- else if ((op1 & 0x3e) == 0x00)
- return arm_copy_undef (gdbarch, insn, dsc);
- else if ((op1 & 0x3e) == 0x04 && (coproc & 0xe) == 0xa)
- return arm_copy_unmodified (gdbarch, insn, "neon 64bit xfer", dsc);
- else if (op1 == 0x04 && (coproc & 0xe) != 0xa)
- return arm_copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
- else if (op1 == 0x05 && (coproc & 0xe) != 0xa)
- return arm_copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
- else if ((op1 & 0x30) == 0x20 && !op)
- {
- if ((coproc & 0xe) == 0xa)
- return arm_copy_unmodified (gdbarch, insn, "vfp dataproc", dsc);
- else
- return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
- }
- else if ((op1 & 0x30) == 0x20 && op)
- return arm_copy_unmodified (gdbarch, insn, "neon 8/16/32 bit xfer", dsc);
- else if ((op1 & 0x31) == 0x20 && op && (coproc & 0xe) != 0xa)
- return arm_copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
- else if ((op1 & 0x31) == 0x21 && op && (coproc & 0xe) != 0xa)
- return arm_copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
- else if ((op1 & 0x30) == 0x30)
- return arm_copy_svc (gdbarch, insn, regs, dsc);
- else
- return arm_copy_undef (gdbarch, insn, dsc); /* Possibly unreachable. */
- }
- static int
- thumb2_decode_svc_copro (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int coproc = bits (insn2, 8, 11);
- unsigned int bit_5_8 = bits (insn1, 5, 8);
- unsigned int bit_9 = bit (insn1, 9);
- unsigned int bit_4 = bit (insn1, 4);
- if (bit_9 == 0)
- {
- if (bit_5_8 == 2)
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "neon 64bit xfer/mrrc/mrrc2/mcrr/mcrr2",
- dsc);
- else if (bit_5_8 == 0) /* UNDEFINED. */
- return thumb_32bit_copy_undef (gdbarch, insn1, insn2, dsc);
- else
- {
- /*coproc is 101x. SIMD/VFP, ext registers load/store. */
- if ((coproc & 0xe) == 0xa)
- return thumb2_decode_ext_reg_ld_st (gdbarch, insn1, insn2, regs,
- dsc);
- else /* coproc is not 101x. */
- {
- if (bit_4 == 0) /* STC/STC2. */
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "stc/stc2", dsc);
- else /* LDC/LDC2 {literal, immediate}. */
- return thumb2_copy_copro_load_store (gdbarch, insn1, insn2,
- regs, dsc);
- }
- }
- }
- else
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2, "coproc", dsc);
- return 0;
- }
- static void
- install_pc_relative (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc, int rd)
- {
- /* ADR Rd, #imm
- Rewrite as:
- Preparation: Rd <- PC
- Insn: ADD Rd, #imm
- Cleanup: Null.
- */
- /* Rd <- PC */
- int val = displaced_read_reg (regs, dsc, ARM_PC_REGNUM);
- displaced_write_reg (regs, dsc, rd, val, CANNOT_WRITE_PC);
- }
- static int
- thumb_copy_pc_relative_16bit (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc,
- int rd, unsigned int imm)
- {
- /* Encoding T2: ADDS Rd, #imm */
- dsc->modinsn[0] = (0x3000 | (rd << 8) | imm);
- install_pc_relative (gdbarch, regs, dsc, rd);
- return 0;
- }
- static int
- thumb_decode_pc_relative_16bit (struct gdbarch *gdbarch, uint16_t insn,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int rd = bits (insn, 8, 10);
- unsigned int imm8 = bits (insn, 0, 7);
- displaced_debug_printf ("copying thumb adr r%d, #%d insn %.4x",
- rd, imm8, insn);
- return thumb_copy_pc_relative_16bit (gdbarch, regs, dsc, rd, imm8);
- }
- static int
- thumb_copy_pc_relative_32bit (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int rd = bits (insn2, 8, 11);
- /* Since immediate has the same encoding in ADR ADD and SUB, so we simply
- extract raw immediate encoding rather than computing immediate. When
- generating ADD or SUB instruction, we can simply perform OR operation to
- set immediate into ADD. */
- unsigned int imm_3_8 = insn2 & 0x70ff;
- unsigned int imm_i = insn1 & 0x0400; /* Clear all bits except bit 10. */
- displaced_debug_printf ("copying thumb adr r%d, #%d:%d insn %.4x%.4x",
- rd, imm_i, imm_3_8, insn1, insn2);
- if (bit (insn1, 7)) /* Encoding T2 */
- {
- /* Encoding T3: SUB Rd, Rd, #imm */
- dsc->modinsn[0] = (0xf1a0 | rd | imm_i);
- dsc->modinsn[1] = ((rd << 8) | imm_3_8);
- }
- else /* Encoding T3 */
- {
- /* Encoding T3: ADD Rd, Rd, #imm */
- dsc->modinsn[0] = (0xf100 | rd | imm_i);
- dsc->modinsn[1] = ((rd << 8) | imm_3_8);
- }
- dsc->numinsns = 2;
- install_pc_relative (gdbarch, regs, dsc, rd);
- return 0;
- }
- static int
- thumb_copy_16bit_ldr_literal (struct gdbarch *gdbarch, uint16_t insn1,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned int rt = bits (insn1, 8, 10);
- unsigned int pc;
- int imm8 = (bits (insn1, 0, 7) << 2);
- /* LDR Rd, #imm8
- Rwrite as:
- Preparation: tmp0 <- R0, tmp2 <- R2, tmp3 <- R3, R2 <- PC, R3 <- #imm8;
- Insn: LDR R0, [R2, R3];
- Cleanup: R2 <- tmp2, R3 <- tmp3, Rd <- R0, R0 <- tmp0 */
- displaced_debug_printf ("copying thumb ldr r%d [pc #%d]", rt, imm8);
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
- dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
- dsc->tmp[3] = displaced_read_reg (regs, dsc, 3);
- pc = displaced_read_reg (regs, dsc, ARM_PC_REGNUM);
- /* The assembler calculates the required value of the offset from the
- Align(PC,4) value of this instruction to the label. */
- pc = pc & 0xfffffffc;
- displaced_write_reg (regs, dsc, 2, pc, CANNOT_WRITE_PC);
- displaced_write_reg (regs, dsc, 3, imm8, CANNOT_WRITE_PC);
- dsc->rd = rt;
- dsc->u.ldst.xfersize = 4;
- dsc->u.ldst.rn = 0;
- dsc->u.ldst.immed = 0;
- dsc->u.ldst.writeback = 0;
- dsc->u.ldst.restore_r4 = 0;
- dsc->modinsn[0] = 0x58d0; /* ldr r0, [r2, r3]*/
- dsc->cleanup = &cleanup_load;
- return 0;
- }
- /* Copy Thumb cbnz/cbz instruction. */
- static int
- thumb_copy_cbnz_cbz (struct gdbarch *gdbarch, uint16_t insn1,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- int non_zero = bit (insn1, 11);
- unsigned int imm5 = (bit (insn1, 9) << 6) | (bits (insn1, 3, 7) << 1);
- CORE_ADDR from = dsc->insn_addr;
- int rn = bits (insn1, 0, 2);
- int rn_val = displaced_read_reg (regs, dsc, rn);
- dsc->u.branch.cond = (rn_val && non_zero) || (!rn_val && !non_zero);
- /* CBNZ and CBZ do not affect the condition flags. If condition is true,
- set it INST_AL, so cleanup_branch will know branch is taken, otherwise,
- condition is false, let it be, cleanup_branch will do nothing. */
- if (dsc->u.branch.cond)
- {
- dsc->u.branch.cond = INST_AL;
- dsc->u.branch.dest = from + 4 + imm5;
- }
- else
- dsc->u.branch.dest = from + 2;
- dsc->u.branch.link = 0;
- dsc->u.branch.exchange = 0;
- displaced_debug_printf ("copying %s [r%d = 0x%x] insn %.4x to %.8lx",
- non_zero ? "cbnz" : "cbz",
- rn, rn_val, insn1, dsc->u.branch.dest);
- dsc->modinsn[0] = THUMB_NOP;
- dsc->cleanup = &cleanup_branch;
- return 0;
- }
- /* Copy Table Branch Byte/Halfword */
- static int
- thumb2_copy_table_branch (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- ULONGEST rn_val, rm_val;
- int is_tbh = bit (insn2, 4);
- CORE_ADDR halfwords = 0;
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- rn_val = displaced_read_reg (regs, dsc, bits (insn1, 0, 3));
- rm_val = displaced_read_reg (regs, dsc, bits (insn2, 0, 3));
- if (is_tbh)
- {
- gdb_byte buf[2];
- target_read_memory (rn_val + 2 * rm_val, buf, 2);
- halfwords = extract_unsigned_integer (buf, 2, byte_order);
- }
- else
- {
- gdb_byte buf[1];
- target_read_memory (rn_val + rm_val, buf, 1);
- halfwords = extract_unsigned_integer (buf, 1, byte_order);
- }
- displaced_debug_printf ("%s base 0x%x offset 0x%x offset 0x%x",
- is_tbh ? "tbh" : "tbb",
- (unsigned int) rn_val, (unsigned int) rm_val,
- (unsigned int) halfwords);
- dsc->u.branch.cond = INST_AL;
- dsc->u.branch.link = 0;
- dsc->u.branch.exchange = 0;
- dsc->u.branch.dest = dsc->insn_addr + 4 + 2 * halfwords;
- dsc->cleanup = &cleanup_branch;
- return 0;
- }
- static void
- cleanup_pop_pc_16bit_all (struct gdbarch *gdbarch, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- /* PC <- r7 */
- int val = displaced_read_reg (regs, dsc, 7);
- displaced_write_reg (regs, dsc, ARM_PC_REGNUM, val, BX_WRITE_PC);
- /* r7 <- r8 */
- val = displaced_read_reg (regs, dsc, 8);
- displaced_write_reg (regs, dsc, 7, val, CANNOT_WRITE_PC);
- /* r8 <- tmp[0] */
- displaced_write_reg (regs, dsc, 8, dsc->tmp[0], CANNOT_WRITE_PC);
- }
- static int
- thumb_copy_pop_pc_16bit (struct gdbarch *gdbarch, uint16_t insn1,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- dsc->u.block.regmask = insn1 & 0x00ff;
- /* Rewrite instruction: POP {rX, rY, ...,rZ, PC}
- to :
- (1) register list is full, that is, r0-r7 are used.
- Prepare: tmp[0] <- r8
- POP {r0, r1, ...., r6, r7}; remove PC from reglist
- MOV r8, r7; Move value of r7 to r8;
- POP {r7}; Store PC value into r7.
- Cleanup: PC <- r7, r7 <- r8, r8 <-tmp[0]
- (2) register list is not full, supposing there are N registers in
- register list (except PC, 0 <= N <= 7).
- Prepare: for each i, 0 - N, tmp[i] <- ri.
- POP {r0, r1, ...., rN};
- Cleanup: Set registers in original reglist from r0 - rN. Restore r0 - rN
- from tmp[] properly.
- */
- displaced_debug_printf ("copying thumb pop {%.8x, pc} insn %.4x",
- dsc->u.block.regmask, insn1);
- if (dsc->u.block.regmask == 0xff)
- {
- dsc->tmp[0] = displaced_read_reg (regs, dsc, 8);
- dsc->modinsn[0] = (insn1 & 0xfeff); /* POP {r0,r1,...,r6, r7} */
- dsc->modinsn[1] = 0x46b8; /* MOV r8, r7 */
- dsc->modinsn[2] = 0xbc80; /* POP {r7} */
- dsc->numinsns = 3;
- dsc->cleanup = &cleanup_pop_pc_16bit_all;
- }
- else
- {
- unsigned int num_in_list = count_one_bits (dsc->u.block.regmask);
- unsigned int i;
- unsigned int new_regmask;
- for (i = 0; i < num_in_list + 1; i++)
- dsc->tmp[i] = displaced_read_reg (regs, dsc, i);
- new_regmask = (1 << (num_in_list + 1)) - 1;
- displaced_debug_printf ("POP {..., pc}: original reg list %.4x, "
- "modified list %.4x",
- (int) dsc->u.block.regmask, new_regmask);
- dsc->u.block.regmask |= 0x8000;
- dsc->u.block.writeback = 0;
- dsc->u.block.cond = INST_AL;
- dsc->modinsn[0] = (insn1 & ~0x1ff) | (new_regmask & 0xff);
- dsc->cleanup = &cleanup_block_load_pc;
- }
- return 0;
- }
- static void
- thumb_process_displaced_16bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- unsigned short op_bit_12_15 = bits (insn1, 12, 15);
- unsigned short op_bit_10_11 = bits (insn1, 10, 11);
- int err = 0;
- /* 16-bit thumb instructions. */
- switch (op_bit_12_15)
- {
- /* Shift (imme), add, subtract, move and compare. */
- case 0: case 1: case 2: case 3:
- err = thumb_copy_unmodified_16bit (gdbarch, insn1,
- "shift/add/sub/mov/cmp",
- dsc);
- break;
- case 4:
- switch (op_bit_10_11)
- {
- case 0: /* Data-processing */
- err = thumb_copy_unmodified_16bit (gdbarch, insn1,
- "data-processing",
- dsc);
- break;
- case 1: /* Special data instructions and branch and exchange. */
- {
- unsigned short op = bits (insn1, 7, 9);
- if (op == 6 || op == 7) /* BX or BLX */
- err = thumb_copy_bx_blx_reg (gdbarch, insn1, regs, dsc);
- else if (bits (insn1, 6, 7) != 0) /* ADD/MOV/CMP high registers. */
- err = thumb_copy_alu_reg (gdbarch, insn1, regs, dsc);
- else
- err = thumb_copy_unmodified_16bit (gdbarch, insn1, "special data",
- dsc);
- }
- break;
- default: /* LDR (literal) */
- err = thumb_copy_16bit_ldr_literal (gdbarch, insn1, regs, dsc);
- }
- break;
- case 5: case 6: case 7: case 8: case 9: /* Load/Store single data item */
- err = thumb_copy_unmodified_16bit (gdbarch, insn1, "ldr/str", dsc);
- break;
- case 10:
- if (op_bit_10_11 < 2) /* Generate PC-relative address */
- err = thumb_decode_pc_relative_16bit (gdbarch, insn1, regs, dsc);
- else /* Generate SP-relative address */
- err = thumb_copy_unmodified_16bit (gdbarch, insn1, "sp-relative", dsc);
- break;
- case 11: /* Misc 16-bit instructions */
- {
- switch (bits (insn1, 8, 11))
- {
- case 1: case 3: case 9: case 11: /* CBNZ, CBZ */
- err = thumb_copy_cbnz_cbz (gdbarch, insn1, regs, dsc);
- break;
- case 12: case 13: /* POP */
- if (bit (insn1, 8)) /* PC is in register list. */
- err = thumb_copy_pop_pc_16bit (gdbarch, insn1, regs, dsc);
- else
- err = thumb_copy_unmodified_16bit (gdbarch, insn1, "pop", dsc);
- break;
- case 15: /* If-Then, and hints */
- if (bits (insn1, 0, 3))
- /* If-Then makes up to four following instructions conditional.
- IT instruction itself is not conditional, so handle it as a
- common unmodified instruction. */
- err = thumb_copy_unmodified_16bit (gdbarch, insn1, "If-Then",
- dsc);
- else
- err = thumb_copy_unmodified_16bit (gdbarch, insn1, "hints", dsc);
- break;
- default:
- err = thumb_copy_unmodified_16bit (gdbarch, insn1, "misc", dsc);
- }
- }
- break;
- case 12:
- if (op_bit_10_11 < 2) /* Store multiple registers */
- err = thumb_copy_unmodified_16bit (gdbarch, insn1, "stm", dsc);
- else /* Load multiple registers */
- err = thumb_copy_unmodified_16bit (gdbarch, insn1, "ldm", dsc);
- break;
- case 13: /* Conditional branch and supervisor call */
- if (bits (insn1, 9, 11) != 7) /* conditional branch */
- err = thumb_copy_b (gdbarch, insn1, dsc);
- else
- err = thumb_copy_svc (gdbarch, insn1, regs, dsc);
- break;
- case 14: /* Unconditional branch */
- err = thumb_copy_b (gdbarch, insn1, dsc);
- break;
- default:
- err = 1;
- }
- if (err)
- internal_error (__FILE__, __LINE__,
- _("thumb_process_displaced_16bit_insn: Instruction decode error"));
- }
- static int
- decode_thumb_32bit_ld_mem_hints (struct gdbarch *gdbarch,
- uint16_t insn1, uint16_t insn2,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- int rt = bits (insn2, 12, 15);
- int rn = bits (insn1, 0, 3);
- int op1 = bits (insn1, 7, 8);
- switch (bits (insn1, 5, 6))
- {
- case 0: /* Load byte and memory hints */
- if (rt == 0xf) /* PLD/PLI */
- {
- if (rn == 0xf)
- /* PLD literal or Encoding T3 of PLI(immediate, literal). */
- return thumb2_copy_preload (gdbarch, insn1, insn2, regs, dsc);
- else
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "pli/pld", dsc);
- }
- else
- {
- if (rn == 0xf) /* LDRB/LDRSB (literal) */
- return thumb2_copy_load_literal (gdbarch, insn1, insn2, regs, dsc,
- 1);
- else
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "ldrb{reg, immediate}/ldrbt",
- dsc);
- }
- break;
- case 1: /* Load halfword and memory hints. */
- if (rt == 0xf) /* PLD{W} and Unalloc memory hint. */
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "pld/unalloc memhint", dsc);
- else
- {
- if (rn == 0xf)
- return thumb2_copy_load_literal (gdbarch, insn1, insn2, regs, dsc,
- 2);
- else
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "ldrh/ldrht", dsc);
- }
- break;
- case 2: /* Load word */
- {
- int insn2_bit_8_11 = bits (insn2, 8, 11);
- if (rn == 0xf)
- return thumb2_copy_load_literal (gdbarch, insn1, insn2, regs, dsc, 4);
- else if (op1 == 0x1) /* Encoding T3 */
- return thumb2_copy_load_reg_imm (gdbarch, insn1, insn2, regs, dsc,
- 0, 1);
- else /* op1 == 0x0 */
- {
- if (insn2_bit_8_11 == 0xc || (insn2_bit_8_11 & 0x9) == 0x9)
- /* LDR (immediate) */
- return thumb2_copy_load_reg_imm (gdbarch, insn1, insn2, regs,
- dsc, bit (insn2, 8), 1);
- else if (insn2_bit_8_11 == 0xe) /* LDRT */
- return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "ldrt", dsc);
- else
- /* LDR (register) */
- return thumb2_copy_load_reg_imm (gdbarch, insn1, insn2, regs,
- dsc, 0, 0);
- }
- break;
- }
- default:
- return thumb_32bit_copy_undef (gdbarch, insn1, insn2, dsc);
- break;
- }
- return 0;
- }
- static void
- thumb_process_displaced_32bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
- uint16_t insn2, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- int err = 0;
- unsigned short op = bit (insn2, 15);
- unsigned int op1 = bits (insn1, 11, 12);
- switch (op1)
- {
- case 1:
- {
- switch (bits (insn1, 9, 10))
- {
- case 0:
- if (bit (insn1, 6))
- {
- /* Load/store {dual, exclusive}, table branch. */
- if (bits (insn1, 7, 8) == 1 && bits (insn1, 4, 5) == 1
- && bits (insn2, 5, 7) == 0)
- err = thumb2_copy_table_branch (gdbarch, insn1, insn2, regs,
- dsc);
- else
- /* PC is not allowed to use in load/store {dual, exclusive}
- instructions. */
- err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "load/store dual/ex", dsc);
- }
- else /* load/store multiple */
- {
- switch (bits (insn1, 7, 8))
- {
- case 0: case 3: /* SRS, RFE */
- err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "srs/rfe", dsc);
- break;
- case 1: case 2: /* LDM/STM/PUSH/POP */
- err = thumb2_copy_block_xfer (gdbarch, insn1, insn2, regs, dsc);
- break;
- }
- }
- break;
- case 1:
- /* Data-processing (shift register). */
- err = thumb2_decode_dp_shift_reg (gdbarch, insn1, insn2, regs,
- dsc);
- break;
- default: /* Coprocessor instructions. */
- err = thumb2_decode_svc_copro (gdbarch, insn1, insn2, regs, dsc);
- break;
- }
- break;
- }
- case 2: /* op1 = 2 */
- if (op) /* Branch and misc control. */
- {
- if (bit (insn2, 14) /* BLX/BL */
- || bit (insn2, 12) /* Unconditional branch */
- || (bits (insn1, 7, 9) != 0x7)) /* Conditional branch */
- err = thumb2_copy_b_bl_blx (gdbarch, insn1, insn2, regs, dsc);
- else
- err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "misc ctrl", dsc);
- }
- else
- {
- if (bit (insn1, 9)) /* Data processing (plain binary imm). */
- {
- int dp_op = bits (insn1, 4, 8);
- int rn = bits (insn1, 0, 3);
- if ((dp_op == 0 || dp_op == 0xa) && rn == 0xf)
- err = thumb_copy_pc_relative_32bit (gdbarch, insn1, insn2,
- regs, dsc);
- else
- err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "dp/pb", dsc);
- }
- else /* Data processing (modified immediate) */
- err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "dp/mi", dsc);
- }
- break;
- case 3: /* op1 = 3 */
- switch (bits (insn1, 9, 10))
- {
- case 0:
- if (bit (insn1, 4))
- err = decode_thumb_32bit_ld_mem_hints (gdbarch, insn1, insn2,
- regs, dsc);
- else /* NEON Load/Store and Store single data item */
- err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "neon elt/struct load/store",
- dsc);
- break;
- case 1: /* op1 = 3, bits (9, 10) == 1 */
- switch (bits (insn1, 7, 8))
- {
- case 0: case 1: /* Data processing (register) */
- err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "dp(reg)", dsc);
- break;
- case 2: /* Multiply and absolute difference */
- err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "mul/mua/diff", dsc);
- break;
- case 3: /* Long multiply and divide */
- err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
- "lmul/lmua", dsc);
- break;
- }
- break;
- default: /* Coprocessor instructions */
- err = thumb2_decode_svc_copro (gdbarch, insn1, insn2, regs, dsc);
- break;
- }
- break;
- default:
- err = 1;
- }
- if (err)
- internal_error (__FILE__, __LINE__,
- _("thumb_process_displaced_32bit_insn: Instruction decode error"));
- }
- static void
- thumb_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
- struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- uint16_t insn1
- = read_memory_unsigned_integer (from, 2, byte_order_for_code);
- displaced_debug_printf ("process thumb insn %.4x at %.8lx",
- insn1, (unsigned long) from);
- dsc->is_thumb = 1;
- dsc->insn_size = thumb_insn_size (insn1);
- if (thumb_insn_size (insn1) == 4)
- {
- uint16_t insn2
- = read_memory_unsigned_integer (from + 2, 2, byte_order_for_code);
- thumb_process_displaced_32bit_insn (gdbarch, insn1, insn2, regs, dsc);
- }
- else
- thumb_process_displaced_16bit_insn (gdbarch, insn1, regs, dsc);
- }
- void
- arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
- CORE_ADDR to, struct regcache *regs,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- int err = 0;
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- uint32_t insn;
- /* Most displaced instructions use a 1-instruction scratch space, so set this
- here and override below if/when necessary. */
- dsc->numinsns = 1;
- dsc->insn_addr = from;
- dsc->scratch_base = to;
- dsc->cleanup = NULL;
- dsc->wrote_to_pc = 0;
- if (!displaced_in_arm_mode (regs))
- return thumb_process_displaced_insn (gdbarch, from, regs, dsc);
- dsc->is_thumb = 0;
- dsc->insn_size = 4;
- insn = read_memory_unsigned_integer (from, 4, byte_order_for_code);
- displaced_debug_printf ("stepping insn %.8lx at %.8lx",
- (unsigned long) insn, (unsigned long) from);
- if ((insn & 0xf0000000) == 0xf0000000)
- err = arm_decode_unconditional (gdbarch, insn, regs, dsc);
- else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24))
- {
- case 0x0: case 0x1: case 0x2: case 0x3:
- err = arm_decode_dp_misc (gdbarch, insn, regs, dsc);
- break;
- case 0x4: case 0x5: case 0x6:
- err = arm_decode_ld_st_word_ubyte (gdbarch, insn, regs, dsc);
- break;
- case 0x7:
- err = arm_decode_media (gdbarch, insn, dsc);
- break;
- case 0x8: case 0x9: case 0xa: case 0xb:
- err = arm_decode_b_bl_ldmstm (gdbarch, insn, regs, dsc);
- break;
- case 0xc: case 0xd: case 0xe: case 0xf:
- err = arm_decode_svc_copro (gdbarch, insn, regs, dsc);
- break;
- }
- if (err)
- internal_error (__FILE__, __LINE__,
- _("arm_process_displaced_insn: Instruction decode error"));
- }
- /* Actually set up the scratch space for a displaced instruction. */
- void
- arm_displaced_init_closure (struct gdbarch *gdbarch, CORE_ADDR from,
- CORE_ADDR to,
- arm_displaced_step_copy_insn_closure *dsc)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- unsigned int i, len, offset;
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- int size = dsc->is_thumb? 2 : 4;
- const gdb_byte *bkp_insn;
- offset = 0;
- /* Poke modified instruction(s). */
- for (i = 0; i < dsc->numinsns; i++)
- {
- if (size == 4)
- displaced_debug_printf ("writing insn %.8lx at %.8lx",
- dsc->modinsn[i], (unsigned long) to + offset);
- else if (size == 2)
- displaced_debug_printf ("writing insn %.4x at %.8lx",
- (unsigned short) dsc->modinsn[i],
- (unsigned long) to + offset);
- write_memory_unsigned_integer (to + offset, size,
- byte_order_for_code,
- dsc->modinsn[i]);
- offset += size;
- }
- /* Choose the correct breakpoint instruction. */
- if (dsc->is_thumb)
- {
- bkp_insn = tdep->thumb_breakpoint;
- len = tdep->thumb_breakpoint_size;
- }
- else
- {
- bkp_insn = tdep->arm_breakpoint;
- len = tdep->arm_breakpoint_size;
- }
- /* Put breakpoint afterwards. */
- write_memory (to + offset, bkp_insn, len);
- displaced_debug_printf ("copy %s->%s", paddress (gdbarch, from),
- paddress (gdbarch, to));
- }
- /* Entry point for cleaning things up after a displaced instruction has been
- single-stepped. */
- void
- arm_displaced_step_fixup (struct gdbarch *gdbarch,
- struct displaced_step_copy_insn_closure *dsc_,
- CORE_ADDR from, CORE_ADDR to,
- struct regcache *regs)
- {
- arm_displaced_step_copy_insn_closure *dsc
- = (arm_displaced_step_copy_insn_closure *) dsc_;
- if (dsc->cleanup)
- dsc->cleanup (gdbarch, regs, dsc);
- if (!dsc->wrote_to_pc)
- regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM,
- dsc->insn_addr + dsc->insn_size);
- }
- #include "bfd-in2.h"
- #include "libcoff.h"
- static int
- gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
- {
- gdb_disassembler *di
- = static_cast<gdb_disassembler *>(info->application_data);
- struct gdbarch *gdbarch = di->arch ();
- if (arm_pc_is_thumb (gdbarch, memaddr))
- {
- static asymbol *asym;
- static combined_entry_type ce;
- static struct coff_symbol_struct csym;
- static struct bfd fake_bfd;
- static bfd_target fake_target;
- if (csym.native == NULL)
- {
- /* Create a fake symbol vector containing a Thumb symbol.
- This is solely so that the code in print_insn_little_arm()
- and print_insn_big_arm() in opcodes/arm-dis.c will detect
- the presence of a Thumb symbol and switch to decoding
- Thumb instructions. */
- fake_target.flavour = bfd_target_coff_flavour;
- fake_bfd.xvec = &fake_target;
- ce.u.syment.n_sclass = C_THUMBEXTFUNC;
- csym.native = &ce;
- csym.symbol.the_bfd = &fake_bfd;
- csym.symbol.name = "fake";
- asym = (asymbol *) & csym;
- }
- memaddr = UNMAKE_THUMB_ADDR (memaddr);
- info->symbols = &asym;
- }
- else
- info->symbols = NULL;
- /* GDB is able to get bfd_mach from the exe_bfd, info->mach is
- accurate, so mark USER_SPECIFIED_MACHINE_TYPE bit. Otherwise,
- opcodes/arm-dis.c:print_insn reset info->mach, and it will trigger
- the assert on the mismatch of info->mach and
- bfd_get_mach (current_program_space->exec_bfd ()) in
- default_print_insn. */
- if (current_program_space->exec_bfd () != NULL
- && (current_program_space->exec_bfd ()->arch_info
- == gdbarch_bfd_arch_info (gdbarch)))
- info->flags |= USER_SPECIFIED_MACHINE_TYPE;
- return default_print_insn (memaddr, info);
- }
- /* The following define instruction sequences that will cause ARM
- cpu's to take an undefined instruction trap. These are used to
- signal a breakpoint to GDB.
-
- The newer ARMv4T cpu's are capable of operating in ARM or Thumb
- modes. A different instruction is required for each mode. The ARM
- cpu's can also be big or little endian. Thus four different
- instructions are needed to support all cases.
-
- Note: ARMv4 defines several new instructions that will take the
- undefined instruction trap. ARM7TDMI is nominally ARMv4T, but does
- not in fact add the new instructions. The new undefined
- instructions in ARMv4 are all instructions that had no defined
- behaviour in earlier chips. There is no guarantee that they will
- raise an exception, but may be treated as NOP's. In practice, it
- may only safe to rely on instructions matching:
-
- 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
- 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- C C C C 0 1 1 x x x x x x x x x x x x x x x x x x x x 1 x x x x
-
- Even this may only true if the condition predicate is true. The
- following use a condition predicate of ALWAYS so it is always TRUE.
-
- There are other ways of forcing a breakpoint. GNU/Linux, RISC iX,
- and NetBSD all use a software interrupt rather than an undefined
- instruction to force a trap. This can be handled by by the
- abi-specific code during establishment of the gdbarch vector. */
- #define ARM_LE_BREAKPOINT {0xFE,0xDE,0xFF,0xE7}
- #define ARM_BE_BREAKPOINT {0xE7,0xFF,0xDE,0xFE}
- #define THUMB_LE_BREAKPOINT {0xbe,0xbe}
- #define THUMB_BE_BREAKPOINT {0xbe,0xbe}
- static const gdb_byte arm_default_arm_le_breakpoint[] = ARM_LE_BREAKPOINT;
- static const gdb_byte arm_default_arm_be_breakpoint[] = ARM_BE_BREAKPOINT;
- static const gdb_byte arm_default_thumb_le_breakpoint[] = THUMB_LE_BREAKPOINT;
- static const gdb_byte arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT;
- /* Implement the breakpoint_kind_from_pc gdbarch method. */
- static int
- arm_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- if (arm_pc_is_thumb (gdbarch, *pcptr))
- {
- *pcptr = UNMAKE_THUMB_ADDR (*pcptr);
- /* If we have a separate 32-bit breakpoint instruction for Thumb-2,
- check whether we are replacing a 32-bit instruction. */
- if (tdep->thumb2_breakpoint != NULL)
- {
- gdb_byte buf[2];
- if (target_read_memory (*pcptr, buf, 2) == 0)
- {
- unsigned short inst1;
- inst1 = extract_unsigned_integer (buf, 2, byte_order_for_code);
- if (thumb_insn_size (inst1) == 4)
- return ARM_BP_KIND_THUMB2;
- }
- }
- return ARM_BP_KIND_THUMB;
- }
- else
- return ARM_BP_KIND_ARM;
- }
- /* Implement the sw_breakpoint_from_kind gdbarch method. */
- static const gdb_byte *
- arm_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- switch (kind)
- {
- case ARM_BP_KIND_ARM:
- *size = tdep->arm_breakpoint_size;
- return tdep->arm_breakpoint;
- case ARM_BP_KIND_THUMB:
- *size = tdep->thumb_breakpoint_size;
- return tdep->thumb_breakpoint;
- case ARM_BP_KIND_THUMB2:
- *size = tdep->thumb2_breakpoint_size;
- return tdep->thumb2_breakpoint;
- default:
- gdb_assert_not_reached ("unexpected arm breakpoint kind");
- }
- }
- /* Implement the breakpoint_kind_from_current_state gdbarch method. */
- static int
- arm_breakpoint_kind_from_current_state (struct gdbarch *gdbarch,
- struct regcache *regcache,
- CORE_ADDR *pcptr)
- {
- gdb_byte buf[4];
- /* Check the memory pointed by PC is readable. */
- if (target_read_memory (regcache_read_pc (regcache), buf, 4) == 0)
- {
- struct arm_get_next_pcs next_pcs_ctx;
- arm_get_next_pcs_ctor (&next_pcs_ctx,
- &arm_get_next_pcs_ops,
- gdbarch_byte_order (gdbarch),
- gdbarch_byte_order_for_code (gdbarch),
- 0,
- regcache);
- std::vector<CORE_ADDR> next_pcs = arm_get_next_pcs (&next_pcs_ctx);
- /* If MEMADDR is the next instruction of current pc, do the
- software single step computation, and get the thumb mode by
- the destination address. */
- for (CORE_ADDR pc : next_pcs)
- {
- if (UNMAKE_THUMB_ADDR (pc) == *pcptr)
- {
- if (IS_THUMB_ADDR (pc))
- {
- *pcptr = MAKE_THUMB_ADDR (*pcptr);
- return arm_breakpoint_kind_from_pc (gdbarch, pcptr);
- }
- else
- return ARM_BP_KIND_ARM;
- }
- }
- }
- return arm_breakpoint_kind_from_pc (gdbarch, pcptr);
- }
- /* Extract from an array REGBUF containing the (raw) register state a
- function return value of type TYPE, and copy that, in virtual
- format, into VALBUF. */
- static void
- arm_extract_return_value (struct type *type, struct regcache *regs,
- gdb_byte *valbuf)
- {
- struct gdbarch *gdbarch = regs->arch ();
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (TYPE_CODE_FLT == type->code ())
- {
- switch (tdep->fp_model)
- {
- case ARM_FLOAT_FPA:
- {
- /* The value is in register F0 in internal format. We need to
- extract the raw value and then convert it to the desired
- internal type. */
- bfd_byte tmpbuf[ARM_FP_REGISTER_SIZE];
- regs->cooked_read (ARM_F0_REGNUM, tmpbuf);
- target_float_convert (tmpbuf, arm_ext_type (gdbarch),
- valbuf, type);
- }
- break;
- case ARM_FLOAT_SOFT_FPA:
- case ARM_FLOAT_SOFT_VFP:
- /* ARM_FLOAT_VFP can arise if this is a variadic function so
- not using the VFP ABI code. */
- case ARM_FLOAT_VFP:
- regs->cooked_read (ARM_A1_REGNUM, valbuf);
- if (TYPE_LENGTH (type) > 4)
- regs->cooked_read (ARM_A1_REGNUM + 1,
- valbuf + ARM_INT_REGISTER_SIZE);
- break;
- default:
- internal_error (__FILE__, __LINE__,
- _("arm_extract_return_value: "
- "Floating point model not supported"));
- break;
- }
- }
- else if (type->code () == TYPE_CODE_INT
- || type->code () == TYPE_CODE_CHAR
- || type->code () == TYPE_CODE_BOOL
- || type->code () == TYPE_CODE_PTR
- || TYPE_IS_REFERENCE (type)
- || type->code () == TYPE_CODE_ENUM
- || is_fixed_point_type (type))
- {
- /* If the type is a plain integer, then the access is
- straight-forward. Otherwise we have to play around a bit
- more. */
- int len = TYPE_LENGTH (type);
- int regno = ARM_A1_REGNUM;
- ULONGEST tmp;
- while (len > 0)
- {
- /* By using store_unsigned_integer we avoid having to do
- anything special for small big-endian values. */
- regcache_cooked_read_unsigned (regs, regno++, &tmp);
- store_unsigned_integer (valbuf,
- (len > ARM_INT_REGISTER_SIZE
- ? ARM_INT_REGISTER_SIZE : len),
- byte_order, tmp);
- len -= ARM_INT_REGISTER_SIZE;
- valbuf += ARM_INT_REGISTER_SIZE;
- }
- }
- else
- {
- /* For a structure or union the behaviour is as if the value had
- been stored to word-aligned memory and then loaded into
- registers with 32-bit load instruction(s). */
- int len = TYPE_LENGTH (type);
- int regno = ARM_A1_REGNUM;
- bfd_byte tmpbuf[ARM_INT_REGISTER_SIZE];
- while (len > 0)
- {
- regs->cooked_read (regno++, tmpbuf);
- memcpy (valbuf, tmpbuf,
- len > ARM_INT_REGISTER_SIZE ? ARM_INT_REGISTER_SIZE : len);
- len -= ARM_INT_REGISTER_SIZE;
- valbuf += ARM_INT_REGISTER_SIZE;
- }
- }
- }
- /* Will a function return an aggregate type in memory or in a
- register? Return 0 if an aggregate type can be returned in a
- register, 1 if it must be returned in memory. */
- static int
- arm_return_in_memory (struct gdbarch *gdbarch, struct type *type)
- {
- enum type_code code;
- type = check_typedef (type);
- /* Simple, non-aggregate types (ie not including vectors and
- complex) are always returned in a register (or registers). */
- code = type->code ();
- if (TYPE_CODE_STRUCT != code && TYPE_CODE_UNION != code
- && TYPE_CODE_ARRAY != code && TYPE_CODE_COMPLEX != code)
- return 0;
- if (TYPE_CODE_ARRAY == code && type->is_vector ())
- {
- /* Vector values should be returned using ARM registers if they
- are not over 16 bytes. */
- return (TYPE_LENGTH (type) > 16);
- }
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->arm_abi != ARM_ABI_APCS)
- {
- /* The AAPCS says all aggregates not larger than a word are returned
- in a register. */
- if (TYPE_LENGTH (type) <= ARM_INT_REGISTER_SIZE
- && language_pass_by_reference (type).trivially_copyable)
- return 0;
- return 1;
- }
- else
- {
- int nRc;
- /* All aggregate types that won't fit in a register must be returned
- in memory. */
- if (TYPE_LENGTH (type) > ARM_INT_REGISTER_SIZE
- || !language_pass_by_reference (type).trivially_copyable)
- return 1;
- /* In the ARM ABI, "integer" like aggregate types are returned in
- registers. For an aggregate type to be integer like, its size
- must be less than or equal to ARM_INT_REGISTER_SIZE and the
- offset of each addressable subfield must be zero. Note that bit
- fields are not addressable, and all addressable subfields of
- unions always start at offset zero.
- This function is based on the behaviour of GCC 2.95.1.
- See: gcc/arm.c: arm_return_in_memory() for details.
- Note: All versions of GCC before GCC 2.95.2 do not set up the
- parameters correctly for a function returning the following
- structure: struct { float f;}; This should be returned in memory,
- not a register. Richard Earnshaw sent me a patch, but I do not
- know of any way to detect if a function like the above has been
- compiled with the correct calling convention. */
- /* Assume all other aggregate types can be returned in a register.
- Run a check for structures, unions and arrays. */
- nRc = 0;
- if ((TYPE_CODE_STRUCT == code) || (TYPE_CODE_UNION == code))
- {
- int i;
- /* Need to check if this struct/union is "integer" like. For
- this to be true, its size must be less than or equal to
- ARM_INT_REGISTER_SIZE and the offset of each addressable
- subfield must be zero. Note that bit fields are not
- addressable, and unions always start at offset zero. If any
- of the subfields is a floating point type, the struct/union
- cannot be an integer type. */
- /* For each field in the object, check:
- 1) Is it FP? --> yes, nRc = 1;
- 2) Is it addressable (bitpos != 0) and
- not packed (bitsize == 0)?
- --> yes, nRc = 1
- */
- for (i = 0; i < type->num_fields (); i++)
- {
- enum type_code field_type_code;
- field_type_code
- = check_typedef (type->field (i).type ())->code ();
- /* Is it a floating point type field? */
- if (field_type_code == TYPE_CODE_FLT)
- {
- nRc = 1;
- break;
- }
- /* If bitpos != 0, then we have to care about it. */
- if (type->field (i).loc_bitpos () != 0)
- {
- /* Bitfields are not addressable. If the field bitsize is
- zero, then the field is not packed. Hence it cannot be
- a bitfield or any other packed type. */
- if (TYPE_FIELD_BITSIZE (type, i) == 0)
- {
- nRc = 1;
- break;
- }
- }
- }
- }
- return nRc;
- }
- }
- /* Write into appropriate registers a function return value of type
- TYPE, given in virtual format. */
- static void
- arm_store_return_value (struct type *type, struct regcache *regs,
- const gdb_byte *valbuf)
- {
- struct gdbarch *gdbarch = regs->arch ();
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- if (type->code () == TYPE_CODE_FLT)
- {
- gdb_byte buf[ARM_FP_REGISTER_SIZE];
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- switch (tdep->fp_model)
- {
- case ARM_FLOAT_FPA:
- target_float_convert (valbuf, type, buf, arm_ext_type (gdbarch));
- regs->cooked_write (ARM_F0_REGNUM, buf);
- break;
- case ARM_FLOAT_SOFT_FPA:
- case ARM_FLOAT_SOFT_VFP:
- /* ARM_FLOAT_VFP can arise if this is a variadic function so
- not using the VFP ABI code. */
- case ARM_FLOAT_VFP:
- regs->cooked_write (ARM_A1_REGNUM, valbuf);
- if (TYPE_LENGTH (type) > 4)
- regs->cooked_write (ARM_A1_REGNUM + 1,
- valbuf + ARM_INT_REGISTER_SIZE);
- break;
- default:
- internal_error (__FILE__, __LINE__,
- _("arm_store_return_value: Floating "
- "point model not supported"));
- break;
- }
- }
- else if (type->code () == TYPE_CODE_INT
- || type->code () == TYPE_CODE_CHAR
- || type->code () == TYPE_CODE_BOOL
- || type->code () == TYPE_CODE_PTR
- || TYPE_IS_REFERENCE (type)
- || type->code () == TYPE_CODE_ENUM)
- {
- if (TYPE_LENGTH (type) <= 4)
- {
- /* Values of one word or less are zero/sign-extended and
- returned in r0. */
- bfd_byte tmpbuf[ARM_INT_REGISTER_SIZE];
- LONGEST val = unpack_long (type, valbuf);
- store_signed_integer (tmpbuf, ARM_INT_REGISTER_SIZE, byte_order, val);
- regs->cooked_write (ARM_A1_REGNUM, tmpbuf);
- }
- else
- {
- /* Integral values greater than one word are stored in consecutive
- registers starting with r0. This will always be a multiple of
- the regiser size. */
- int len = TYPE_LENGTH (type);
- int regno = ARM_A1_REGNUM;
- while (len > 0)
- {
- regs->cooked_write (regno++, valbuf);
- len -= ARM_INT_REGISTER_SIZE;
- valbuf += ARM_INT_REGISTER_SIZE;
- }
- }
- }
- else
- {
- /* For a structure or union the behaviour is as if the value had
- been stored to word-aligned memory and then loaded into
- registers with 32-bit load instruction(s). */
- int len = TYPE_LENGTH (type);
- int regno = ARM_A1_REGNUM;
- bfd_byte tmpbuf[ARM_INT_REGISTER_SIZE];
- while (len > 0)
- {
- memcpy (tmpbuf, valbuf,
- len > ARM_INT_REGISTER_SIZE ? ARM_INT_REGISTER_SIZE : len);
- regs->cooked_write (regno++, tmpbuf);
- len -= ARM_INT_REGISTER_SIZE;
- valbuf += ARM_INT_REGISTER_SIZE;
- }
- }
- }
- /* Handle function return values. */
- static enum return_value_convention
- arm_return_value (struct gdbarch *gdbarch, struct value *function,
- struct type *valtype, struct regcache *regcache,
- gdb_byte *readbuf, const gdb_byte *writebuf)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- struct type *func_type = function ? value_type (function) : NULL;
- enum arm_vfp_cprc_base_type vfp_base_type;
- int vfp_base_count;
- if (arm_vfp_abi_for_function (gdbarch, func_type)
- && arm_vfp_call_candidate (valtype, &vfp_base_type, &vfp_base_count))
- {
- int reg_char = arm_vfp_cprc_reg_char (vfp_base_type);
- int unit_length = arm_vfp_cprc_unit_length (vfp_base_type);
- int i;
- for (i = 0; i < vfp_base_count; i++)
- {
- if (reg_char == 'q')
- {
- if (writebuf)
- arm_neon_quad_write (gdbarch, regcache, i,
- writebuf + i * unit_length);
- if (readbuf)
- arm_neon_quad_read (gdbarch, regcache, i,
- readbuf + i * unit_length);
- }
- else
- {
- char name_buf[4];
- int regnum;
- xsnprintf (name_buf, sizeof (name_buf), "%c%d", reg_char, i);
- regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
- strlen (name_buf));
- if (writebuf)
- regcache->cooked_write (regnum, writebuf + i * unit_length);
- if (readbuf)
- regcache->cooked_read (regnum, readbuf + i * unit_length);
- }
- }
- return RETURN_VALUE_REGISTER_CONVENTION;
- }
- if (valtype->code () == TYPE_CODE_STRUCT
- || valtype->code () == TYPE_CODE_UNION
- || valtype->code () == TYPE_CODE_ARRAY)
- {
- /* From the AAPCS document:
- Result return:
- A Composite Type larger than 4 bytes, or whose size cannot be
- determined statically by both caller and callee, is stored in memory
- at an address passed as an extra argument when the function was
- called (Parameter Passing, rule A.4). The memory to be used for the
- result may be modified at any point during the function call.
- Parameter Passing:
- A.4: If the subroutine is a function that returns a result in memory,
- then the address for the result is placed in r0 and the NCRN is set
- to r1. */
- if (tdep->struct_return == pcc_struct_return
- || arm_return_in_memory (gdbarch, valtype))
- {
- if (readbuf)
- {
- CORE_ADDR addr;
- regcache->cooked_read (ARM_A1_REGNUM, &addr);
- read_memory (addr, readbuf, TYPE_LENGTH (valtype));
- }
- return RETURN_VALUE_ABI_RETURNS_ADDRESS;
- }
- }
- else if (valtype->code () == TYPE_CODE_COMPLEX)
- {
- if (arm_return_in_memory (gdbarch, valtype))
- return RETURN_VALUE_STRUCT_CONVENTION;
- }
- if (writebuf)
- arm_store_return_value (valtype, regcache, writebuf);
- if (readbuf)
- arm_extract_return_value (valtype, regcache, readbuf);
- return RETURN_VALUE_REGISTER_CONVENTION;
- }
- static int
- arm_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
- {
- struct gdbarch *gdbarch = get_frame_arch (frame);
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- CORE_ADDR jb_addr;
- gdb_byte buf[ARM_INT_REGISTER_SIZE];
-
- jb_addr = get_frame_register_unsigned (frame, ARM_A1_REGNUM);
- if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
- ARM_INT_REGISTER_SIZE))
- return 0;
- *pc = extract_unsigned_integer (buf, ARM_INT_REGISTER_SIZE, byte_order);
- return 1;
- }
- /* A call to cmse secure entry function "foo" at "a" is modified by
- GNU ld as "b".
- a) bl xxxx <foo>
- <foo>
- xxxx:
- b) bl yyyy <__acle_se_foo>
- section .gnu.sgstubs:
- <foo>
- yyyy: sg // secure gateway
- b.w xxxx <__acle_se_foo> // original_branch_dest
- <__acle_se_foo>
- xxxx:
- When the control at "b", the pc contains "yyyy" (sg address) which is a
- trampoline and does not exist in source code. This function returns the
- target pc "xxxx". For more details please refer to section 5.4
- (Entry functions) and section 3.4.4 (C level development flow of secure code)
- of "armv8-m-security-extensions-requirements-on-development-tools-engineering-specification"
- document on www.developer.arm.com. */
- static CORE_ADDR
- arm_skip_cmse_entry (CORE_ADDR pc, const char *name, struct objfile *objfile)
- {
- int target_len = strlen (name) + strlen ("__acle_se_") + 1;
- char *target_name = (char *) alloca (target_len);
- xsnprintf (target_name, target_len, "%s%s", "__acle_se_", name);
- struct bound_minimal_symbol minsym
- = lookup_minimal_symbol (target_name, NULL, objfile);
- if (minsym.minsym != nullptr)
- return BMSYMBOL_VALUE_ADDRESS (minsym);
- return 0;
- }
- /* Return true when SEC points to ".gnu.sgstubs" section. */
- static bool
- arm_is_sgstubs_section (struct obj_section *sec)
- {
- return (sec != nullptr
- && sec->the_bfd_section != nullptr
- && sec->the_bfd_section->name != nullptr
- && streq (sec->the_bfd_section->name, ".gnu.sgstubs"));
- }
- /* Recognize GCC and GNU ld's trampolines. If we are in a trampoline,
- return the target PC. Otherwise return 0. */
- CORE_ADDR
- arm_skip_stub (struct frame_info *frame, CORE_ADDR pc)
- {
- const char *name;
- int namelen;
- CORE_ADDR start_addr;
- /* Find the starting address and name of the function containing the PC. */
- if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
- {
- /* Trampoline 'bx reg' doesn't belong to any functions. Do the
- check here. */
- start_addr = arm_skip_bx_reg (frame, pc);
- if (start_addr != 0)
- return start_addr;
- return 0;
- }
- /* If PC is in a Thumb call or return stub, return the address of the
- target PC, which is in a register. The thunk functions are called
- _call_via_xx, where x is the register name. The possible names
- are r0-r9, sl, fp, ip, sp, and lr. ARM RealView has similar
- functions, named __ARM_call_via_r[0-7]. */
- if (startswith (name, "_call_via_")
- || startswith (name, "__ARM_call_via_"))
- {
- /* Use the name suffix to determine which register contains the
- target PC. */
- static const char *table[15] =
- {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "sl", "fp", "ip", "sp", "lr"
- };
- int regno;
- int offset = strlen (name) - 2;
- for (regno = 0; regno <= 14; regno++)
- if (strcmp (&name[offset], table[regno]) == 0)
- return get_frame_register_unsigned (frame, regno);
- }
- /* GNU ld generates __foo_from_arm or __foo_from_thumb for
- non-interworking calls to foo. We could decode the stubs
- to find the target but it's easier to use the symbol table. */
- namelen = strlen (name);
- if (name[0] == '_' && name[1] == '_'
- && ((namelen > 2 + strlen ("_from_thumb")
- && startswith (name + namelen - strlen ("_from_thumb"), "_from_thumb"))
- || (namelen > 2 + strlen ("_from_arm")
- && startswith (name + namelen - strlen ("_from_arm"), "_from_arm"))))
- {
- char *target_name;
- int target_len = namelen - 2;
- struct bound_minimal_symbol minsym;
- struct objfile *objfile;
- struct obj_section *sec;
- if (name[namelen - 1] == 'b')
- target_len -= strlen ("_from_thumb");
- else
- target_len -= strlen ("_from_arm");
- target_name = (char *) alloca (target_len + 1);
- memcpy (target_name, name + 2, target_len);
- target_name[target_len] = '\0';
- sec = find_pc_section (pc);
- objfile = (sec == NULL) ? NULL : sec->objfile;
- minsym = lookup_minimal_symbol (target_name, NULL, objfile);
- if (minsym.minsym != NULL)
- return BMSYMBOL_VALUE_ADDRESS (minsym);
- else
- return 0;
- }
- struct obj_section *section = find_pc_section (pc);
- /* Check whether SECTION points to the ".gnu.sgstubs" section. */
- if (arm_is_sgstubs_section (section))
- return arm_skip_cmse_entry (pc, name, section->objfile);
- return 0; /* not a stub */
- }
- static void
- arm_update_current_architecture (void)
- {
- /* If the current architecture is not ARM, we have nothing to do. */
- if (gdbarch_bfd_arch_info (target_gdbarch ())->arch != bfd_arch_arm)
- return;
- /* Update the architecture. */
- gdbarch_info info;
- if (!gdbarch_update_p (info))
- internal_error (__FILE__, __LINE__, _("could not update architecture"));
- }
- static void
- set_fp_model_sfunc (const char *args, int from_tty,
- struct cmd_list_element *c)
- {
- int fp_model;
- for (fp_model = ARM_FLOAT_AUTO; fp_model != ARM_FLOAT_LAST; fp_model++)
- if (strcmp (current_fp_model, fp_model_strings[fp_model]) == 0)
- {
- arm_fp_model = (enum arm_float_model) fp_model;
- break;
- }
- if (fp_model == ARM_FLOAT_LAST)
- internal_error (__FILE__, __LINE__, _("Invalid fp model accepted: %s."),
- current_fp_model);
- arm_update_current_architecture ();
- }
- static void
- show_fp_model (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- arm_gdbarch_tdep *tdep
- = (arm_gdbarch_tdep *) gdbarch_tdep (target_gdbarch ());
- if (arm_fp_model == ARM_FLOAT_AUTO
- && gdbarch_bfd_arch_info (target_gdbarch ())->arch == bfd_arch_arm)
- gdb_printf (file, _("\
- The current ARM floating point model is \"auto\" (currently \"%s\").\n"),
- fp_model_strings[tdep->fp_model]);
- else
- gdb_printf (file, _("\
- The current ARM floating point model is \"%s\".\n"),
- fp_model_strings[arm_fp_model]);
- }
- static void
- arm_set_abi (const char *args, int from_tty,
- struct cmd_list_element *c)
- {
- int arm_abi;
- for (arm_abi = ARM_ABI_AUTO; arm_abi != ARM_ABI_LAST; arm_abi++)
- if (strcmp (arm_abi_string, arm_abi_strings[arm_abi]) == 0)
- {
- arm_abi_global = (enum arm_abi_kind) arm_abi;
- break;
- }
- if (arm_abi == ARM_ABI_LAST)
- internal_error (__FILE__, __LINE__, _("Invalid ABI accepted: %s."),
- arm_abi_string);
- arm_update_current_architecture ();
- }
- static void
- arm_show_abi (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- arm_gdbarch_tdep *tdep
- = (arm_gdbarch_tdep *) gdbarch_tdep (target_gdbarch ());
- if (arm_abi_global == ARM_ABI_AUTO
- && gdbarch_bfd_arch_info (target_gdbarch ())->arch == bfd_arch_arm)
- gdb_printf (file, _("\
- The current ARM ABI is \"auto\" (currently \"%s\").\n"),
- arm_abi_strings[tdep->arm_abi]);
- else
- gdb_printf (file, _("The current ARM ABI is \"%s\".\n"),
- arm_abi_string);
- }
- static void
- arm_show_fallback_mode (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file,
- _("The current execution mode assumed "
- "(when symbols are unavailable) is \"%s\".\n"),
- arm_fallback_mode_string);
- }
- static void
- arm_show_force_mode (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file,
- _("The current execution mode assumed "
- "(even when symbols are available) is \"%s\".\n"),
- arm_force_mode_string);
- }
- /* If the user changes the register disassembly style used for info
- register and other commands, we have to also switch the style used
- in opcodes for disassembly output. This function is run in the "set
- arm disassembly" command, and does that. */
- static void
- set_disassembly_style_sfunc (const char *args, int from_tty,
- struct cmd_list_element *c)
- {
- /* Convert the short style name into the long style name (eg, reg-names-*)
- before calling the generic set_disassembler_options() function. */
- std::string long_name = std::string ("reg-names-") + disassembly_style;
- set_disassembler_options (&long_name[0]);
- }
- static void
- show_disassembly_style_sfunc (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- struct gdbarch *gdbarch = get_current_arch ();
- char *options = get_disassembler_options (gdbarch);
- const char *style = "";
- int len = 0;
- const char *opt;
- FOR_EACH_DISASSEMBLER_OPTION (opt, options)
- if (startswith (opt, "reg-names-"))
- {
- style = &opt[strlen ("reg-names-")];
- len = strcspn (style, ",");
- }
- gdb_printf (file, "The disassembly style is \"%.*s\".\n", len, style);
- }
- /* Return the ARM register name corresponding to register I. */
- static const char *
- arm_register_name (struct gdbarch *gdbarch, int i)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (is_s_pseudo (gdbarch, i))
- {
- static const char *const s_pseudo_names[] = {
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
- "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
- "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
- };
- return s_pseudo_names[i - tdep->s_pseudo_base];
- }
- if (is_q_pseudo (gdbarch, i))
- {
- static const char *const q_pseudo_names[] = {
- "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
- };
- return q_pseudo_names[i - tdep->q_pseudo_base];
- }
- if (is_mve_pseudo (gdbarch, i))
- return "p0";
- /* RA_AUTH_CODE is used for unwinding only. Do not assign it a name. */
- if (is_pacbti_pseudo (gdbarch, i))
- return "";
- if (i >= ARRAY_SIZE (arm_register_names))
- /* These registers are only supported on targets which supply
- an XML description. */
- return "";
- /* Non-pseudo registers. */
- return arm_register_names[i];
- }
- /* Test whether the coff symbol specific value corresponds to a Thumb
- function. */
- static int
- coff_sym_is_thumb (int val)
- {
- return (val == C_THUMBEXT
- || val == C_THUMBSTAT
- || val == C_THUMBEXTFUNC
- || val == C_THUMBSTATFUNC
- || val == C_THUMBLABEL);
- }
- /* arm_coff_make_msymbol_special()
- arm_elf_make_msymbol_special()
-
- These functions test whether the COFF or ELF symbol corresponds to
- an address in thumb code, and set a "special" bit in a minimal
- symbol to indicate that it does. */
-
- static void
- arm_elf_make_msymbol_special(asymbol *sym, struct minimal_symbol *msym)
- {
- elf_symbol_type *elfsym = (elf_symbol_type *) sym;
- if (ARM_GET_SYM_BRANCH_TYPE (elfsym->internal_elf_sym.st_target_internal)
- == ST_BRANCH_TO_THUMB)
- MSYMBOL_SET_SPECIAL (msym);
- }
- static void
- arm_coff_make_msymbol_special(int val, struct minimal_symbol *msym)
- {
- if (coff_sym_is_thumb (val))
- MSYMBOL_SET_SPECIAL (msym);
- }
- static void
- arm_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile,
- asymbol *sym)
- {
- const char *name = bfd_asymbol_name (sym);
- struct arm_per_bfd *data;
- struct arm_mapping_symbol new_map_sym;
- gdb_assert (name[0] == '$');
- if (name[1] != 'a' && name[1] != 't' && name[1] != 'd')
- return;
- data = arm_bfd_data_key.get (objfile->obfd);
- if (data == NULL)
- data = arm_bfd_data_key.emplace (objfile->obfd,
- objfile->obfd->section_count);
- arm_mapping_symbol_vec &map
- = data->section_maps[bfd_asymbol_section (sym)->index];
- new_map_sym.value = sym->value;
- new_map_sym.type = name[1];
- /* Insert at the end, the vector will be sorted on first use. */
- map.push_back (new_map_sym);
- }
- static void
- arm_write_pc (struct regcache *regcache, CORE_ADDR pc)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- regcache_cooked_write_unsigned (regcache, ARM_PC_REGNUM, pc);
- /* If necessary, set the T bit. */
- if (arm_apcs_32)
- {
- ULONGEST val, t_bit;
- regcache_cooked_read_unsigned (regcache, ARM_PS_REGNUM, &val);
- t_bit = arm_psr_thumb_bit (gdbarch);
- if (arm_pc_is_thumb (gdbarch, pc))
- regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
- val | t_bit);
- else
- regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
- val & ~t_bit);
- }
- }
- /* Read the contents of a NEON quad register, by reading from two
- double registers. This is used to implement the quad pseudo
- registers, and for argument passing in case the quad registers are
- missing; vectors are passed in quad registers when using the VFP
- ABI, even if a NEON unit is not present. REGNUM is the index of
- the quad register, in [0, 15]. */
- static enum register_status
- arm_neon_quad_read (struct gdbarch *gdbarch, readable_regcache *regcache,
- int regnum, gdb_byte *buf)
- {
- char name_buf[4];
- gdb_byte reg_buf[8];
- int offset, double_regnum;
- enum register_status status;
- xsnprintf (name_buf, sizeof (name_buf), "d%d", regnum << 1);
- double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
- strlen (name_buf));
- /* d0 is always the least significant half of q0. */
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- offset = 8;
- else
- offset = 0;
- status = regcache->raw_read (double_regnum, reg_buf);
- if (status != REG_VALID)
- return status;
- memcpy (buf + offset, reg_buf, 8);
- offset = 8 - offset;
- status = regcache->raw_read (double_regnum + 1, reg_buf);
- if (status != REG_VALID)
- return status;
- memcpy (buf + offset, reg_buf, 8);
- return REG_VALID;
- }
- /* Read the contents of the MVE pseudo register REGNUM and store it
- in BUF. */
- static enum register_status
- arm_mve_pseudo_read (struct gdbarch *gdbarch, readable_regcache *regcache,
- int regnum, gdb_byte *buf)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* P0 is the first 16 bits of VPR. */
- return regcache->raw_read_part (tdep->mve_vpr_regnum, 0, 2, buf);
- }
- static enum register_status
- arm_pseudo_read (struct gdbarch *gdbarch, readable_regcache *regcache,
- int regnum, gdb_byte *buf)
- {
- const int num_regs = gdbarch_num_regs (gdbarch);
- char name_buf[4];
- gdb_byte reg_buf[8];
- int offset, double_regnum;
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- gdb_assert (regnum >= num_regs);
- if (is_q_pseudo (gdbarch, regnum))
- {
- /* Quad-precision register. */
- return arm_neon_quad_read (gdbarch, regcache,
- regnum - tdep->q_pseudo_base, buf);
- }
- else if (is_mve_pseudo (gdbarch, regnum))
- return arm_mve_pseudo_read (gdbarch, regcache, regnum, buf);
- else
- {
- enum register_status status;
- regnum -= tdep->s_pseudo_base;
- /* Single-precision register. */
- gdb_assert (regnum < 32);
- /* s0 is always the least significant half of d0. */
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- offset = (regnum & 1) ? 0 : 4;
- else
- offset = (regnum & 1) ? 4 : 0;
- xsnprintf (name_buf, sizeof (name_buf), "d%d", regnum >> 1);
- double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
- strlen (name_buf));
- status = regcache->raw_read (double_regnum, reg_buf);
- if (status == REG_VALID)
- memcpy (buf, reg_buf + offset, 4);
- return status;
- }
- }
- /* Store the contents of BUF to a NEON quad register, by writing to
- two double registers. This is used to implement the quad pseudo
- registers, and for argument passing in case the quad registers are
- missing; vectors are passed in quad registers when using the VFP
- ABI, even if a NEON unit is not present. REGNUM is the index
- of the quad register, in [0, 15]. */
- static void
- arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache,
- int regnum, const gdb_byte *buf)
- {
- char name_buf[4];
- int offset, double_regnum;
- xsnprintf (name_buf, sizeof (name_buf), "d%d", regnum << 1);
- double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
- strlen (name_buf));
- /* d0 is always the least significant half of q0. */
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- offset = 8;
- else
- offset = 0;
- regcache->raw_write (double_regnum, buf + offset);
- offset = 8 - offset;
- regcache->raw_write (double_regnum + 1, buf + offset);
- }
- /* Store the contents of BUF to the MVE pseudo register REGNUM. */
- static void
- arm_mve_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
- int regnum, const gdb_byte *buf)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* P0 is the first 16 bits of VPR. */
- regcache->raw_write_part (tdep->mve_vpr_regnum, 0, 2, buf);
- }
- static void
- arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
- int regnum, const gdb_byte *buf)
- {
- const int num_regs = gdbarch_num_regs (gdbarch);
- char name_buf[4];
- gdb_byte reg_buf[8];
- int offset, double_regnum;
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- gdb_assert (regnum >= num_regs);
- if (is_q_pseudo (gdbarch, regnum))
- {
- /* Quad-precision register. */
- arm_neon_quad_write (gdbarch, regcache,
- regnum - tdep->q_pseudo_base, buf);
- }
- else if (is_mve_pseudo (gdbarch, regnum))
- arm_mve_pseudo_write (gdbarch, regcache, regnum, buf);
- else
- {
- regnum -= tdep->s_pseudo_base;
- /* Single-precision register. */
- gdb_assert (regnum < 32);
- /* s0 is always the least significant half of d0. */
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- offset = (regnum & 1) ? 0 : 4;
- else
- offset = (regnum & 1) ? 4 : 0;
- xsnprintf (name_buf, sizeof (name_buf), "d%d", regnum >> 1);
- double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
- strlen (name_buf));
- regcache->raw_read (double_regnum, reg_buf);
- memcpy (reg_buf + offset, buf, 4);
- regcache->raw_write (double_regnum, reg_buf);
- }
- }
- static struct value *
- value_of_arm_user_reg (struct frame_info *frame, const void *baton)
- {
- const int *reg_p = (const int *) baton;
- return value_of_register (*reg_p, frame);
- }
- static enum gdb_osabi
- arm_elf_osabi_sniffer (bfd *abfd)
- {
- unsigned int elfosabi;
- enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
- elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
- if (elfosabi == ELFOSABI_ARM)
- /* GNU tools use this value. Check note sections in this case,
- as well. */
- {
- for (asection *sect : gdb_bfd_sections (abfd))
- generic_elf_osabi_sniff_abi_tag_sections (abfd, sect, &osabi);
- }
- /* Anything else will be handled by the generic ELF sniffer. */
- return osabi;
- }
- static int
- arm_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
- const struct reggroup *group)
- {
- /* FPS register's type is INT, but belongs to float_reggroup. Beside
- this, FPS register belongs to save_regroup, restore_reggroup, and
- all_reggroup, of course. */
- if (regnum == ARM_FPS_REGNUM)
- return (group == float_reggroup
- || group == save_reggroup
- || group == restore_reggroup
- || group == all_reggroup);
- else
- return default_register_reggroup_p (gdbarch, regnum, group);
- }
- /* For backward-compatibility we allow two 'g' packet lengths with
- the remote protocol depending on whether FPA registers are
- supplied. M-profile targets do not have FPA registers, but some
- stubs already exist in the wild which use a 'g' packet which
- supplies them albeit with dummy values. The packet format which
- includes FPA registers should be considered deprecated for
- M-profile targets. */
- static void
- arm_register_g_packet_guesses (struct gdbarch *gdbarch)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->is_m)
- {
- const target_desc *tdesc;
- /* If we know from the executable this is an M-profile target,
- cater for remote targets whose register set layout is the
- same as the FPA layout. */
- tdesc = arm_read_mprofile_description (ARM_M_TYPE_WITH_FPA);
- register_remote_g_packet_guess (gdbarch,
- ARM_CORE_REGS_SIZE + ARM_FP_REGS_SIZE,
- tdesc);
- /* The regular M-profile layout. */
- tdesc = arm_read_mprofile_description (ARM_M_TYPE_M_PROFILE);
- register_remote_g_packet_guess (gdbarch, ARM_CORE_REGS_SIZE,
- tdesc);
- /* M-profile plus M4F VFP. */
- tdesc = arm_read_mprofile_description (ARM_M_TYPE_VFP_D16);
- register_remote_g_packet_guess (gdbarch,
- ARM_CORE_REGS_SIZE + ARM_VFP2_REGS_SIZE,
- tdesc);
- /* M-profile plus MVE. */
- tdesc = arm_read_mprofile_description (ARM_M_TYPE_MVE);
- register_remote_g_packet_guess (gdbarch, ARM_CORE_REGS_SIZE
- + ARM_VFP2_REGS_SIZE
- + ARM_INT_REGISTER_SIZE, tdesc);
- }
- /* Otherwise we don't have a useful guess. */
- }
- /* Implement the code_of_frame_writable gdbarch method. */
- static int
- arm_code_of_frame_writable (struct gdbarch *gdbarch, struct frame_info *frame)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->is_m && get_frame_type (frame) == SIGTRAMP_FRAME)
- {
- /* M-profile exception frames return to some magic PCs, where
- isn't writable at all. */
- return 0;
- }
- else
- return 1;
- }
- /* Implement gdbarch_gnu_triplet_regexp. If the arch name is arm then allow it
- to be postfixed by a version (eg armv7hl). */
- static const char *
- arm_gnu_triplet_regexp (struct gdbarch *gdbarch)
- {
- if (strcmp (gdbarch_bfd_arch_info (gdbarch)->arch_name, "arm") == 0)
- return "arm(v[^- ]*)?";
- return gdbarch_bfd_arch_info (gdbarch)->arch_name;
- }
- /* Implement the "get_pc_address_flags" gdbarch method. */
- static std::string
- arm_get_pc_address_flags (frame_info *frame, CORE_ADDR pc)
- {
- if (get_frame_pc_masked (frame))
- return "PAC";
- return "";
- }
- /* Initialize the current architecture based on INFO. If possible,
- re-use an architecture from ARCHES, which is a list of
- architectures already created during this debugging session.
- Called e.g. at program startup, when reading a core file, and when
- reading a binary file. */
- static struct gdbarch *
- arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
- {
- struct gdbarch *gdbarch;
- struct gdbarch_list *best_arch;
- enum arm_abi_kind arm_abi = arm_abi_global;
- enum arm_float_model fp_model = arm_fp_model;
- tdesc_arch_data_up tdesc_data;
- int i;
- bool is_m = false;
- int vfp_register_count = 0;
- bool have_s_pseudos = false, have_q_pseudos = false;
- bool have_wmmx_registers = false;
- bool have_neon = false;
- bool have_fpa_registers = true;
- const struct target_desc *tdesc = info.target_desc;
- bool have_vfp = false;
- bool have_mve = false;
- bool have_pacbti = false;
- int mve_vpr_regnum = -1;
- int register_count = ARM_NUM_REGS;
- /* If we have an object to base this architecture on, try to determine
- its ABI. */
- if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL)
- {
- int ei_osabi, e_flags;
- switch (bfd_get_flavour (info.abfd))
- {
- case bfd_target_coff_flavour:
- /* Assume it's an old APCS-style ABI. */
- /* XXX WinCE? */
- arm_abi = ARM_ABI_APCS;
- break;
- case bfd_target_elf_flavour:
- ei_osabi = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
- e_flags = elf_elfheader (info.abfd)->e_flags;
- if (ei_osabi == ELFOSABI_ARM)
- {
- /* GNU tools used to use this value, but do not for EABI
- objects. There's nowhere to tag an EABI version
- anyway, so assume APCS. */
- arm_abi = ARM_ABI_APCS;
- }
- else if (ei_osabi == ELFOSABI_NONE || ei_osabi == ELFOSABI_GNU)
- {
- int eabi_ver = EF_ARM_EABI_VERSION (e_flags);
- switch (eabi_ver)
- {
- case EF_ARM_EABI_UNKNOWN:
- /* Assume GNU tools. */
- arm_abi = ARM_ABI_APCS;
- break;
- case EF_ARM_EABI_VER4:
- case EF_ARM_EABI_VER5:
- arm_abi = ARM_ABI_AAPCS;
- /* EABI binaries default to VFP float ordering.
- They may also contain build attributes that can
- be used to identify if the VFP argument-passing
- ABI is in use. */
- if (fp_model == ARM_FLOAT_AUTO)
- {
- #ifdef HAVE_ELF
- switch (bfd_elf_get_obj_attr_int (info.abfd,
- OBJ_ATTR_PROC,
- Tag_ABI_VFP_args))
- {
- case AEABI_VFP_args_base:
- /* "The user intended FP parameter/result
- passing to conform to AAPCS, base
- variant". */
- fp_model = ARM_FLOAT_SOFT_VFP;
- break;
- case AEABI_VFP_args_vfp:
- /* "The user intended FP parameter/result
- passing to conform to AAPCS, VFP
- variant". */
- fp_model = ARM_FLOAT_VFP;
- break;
- case AEABI_VFP_args_toolchain:
- /* "The user intended FP parameter/result
- passing to conform to tool chain-specific
- conventions" - we don't know any such
- conventions, so leave it as "auto". */
- break;
- case AEABI_VFP_args_compatible:
- /* "Code is compatible with both the base
- and VFP variants; the user did not permit
- non-variadic functions to pass FP
- parameters/results" - leave it as
- "auto". */
- break;
- default:
- /* Attribute value not mentioned in the
- November 2012 ABI, so leave it as
- "auto". */
- break;
- }
- #else
- fp_model = ARM_FLOAT_SOFT_VFP;
- #endif
- }
- break;
- default:
- /* Leave it as "auto". */
- warning (_("unknown ARM EABI version 0x%x"), eabi_ver);
- break;
- }
- #ifdef HAVE_ELF
- /* Detect M-profile programs. This only works if the
- executable file includes build attributes; GCC does
- copy them to the executable, but e.g. RealView does
- not. */
- int attr_arch
- = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC,
- Tag_CPU_arch);
- int attr_profile
- = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC,
- Tag_CPU_arch_profile);
- /* GCC specifies the profile for v6-M; RealView only
- specifies the profile for architectures starting with
- V7 (as opposed to architectures with a tag
- numerically greater than TAG_CPU_ARCH_V7). */
- if (!tdesc_has_registers (tdesc)
- && (attr_arch == TAG_CPU_ARCH_V6_M
- || attr_arch == TAG_CPU_ARCH_V6S_M
- || attr_arch == TAG_CPU_ARCH_V7E_M
- || attr_arch == TAG_CPU_ARCH_V8M_BASE
- || attr_arch == TAG_CPU_ARCH_V8M_MAIN
- || attr_arch == TAG_CPU_ARCH_V8_1M_MAIN
- || attr_profile == 'M'))
- is_m = true;
- /* Look for attributes that indicate support for ARMv8.1-m
- PACBTI. */
- if (!tdesc_has_registers (tdesc) && is_m)
- {
- int attr_pac_extension
- = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC,
- Tag_PAC_extension);
- int attr_bti_extension
- = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC,
- Tag_BTI_extension);
- int attr_pacret_use
- = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC,
- Tag_PACRET_use);
- int attr_bti_use
- = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC,
- Tag_BTI_use);
- if (attr_pac_extension != 0 || attr_bti_extension != 0
- || attr_pacret_use != 0 || attr_bti_use != 0)
- have_pacbti = true;
- }
- #endif
- }
- if (fp_model == ARM_FLOAT_AUTO)
- {
- switch (e_flags & (EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT))
- {
- case 0:
- /* Leave it as "auto". Strictly speaking this case
- means FPA, but almost nobody uses that now, and
- many toolchains fail to set the appropriate bits
- for the floating-point model they use. */
- break;
- case EF_ARM_SOFT_FLOAT:
- fp_model = ARM_FLOAT_SOFT_FPA;
- break;
- case EF_ARM_VFP_FLOAT:
- fp_model = ARM_FLOAT_VFP;
- break;
- case EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT:
- fp_model = ARM_FLOAT_SOFT_VFP;
- break;
- }
- }
- if (e_flags & EF_ARM_BE8)
- info.byte_order_for_code = BFD_ENDIAN_LITTLE;
- break;
- default:
- /* Leave it as "auto". */
- break;
- }
- }
- /* Check any target description for validity. */
- if (tdesc_has_registers (tdesc))
- {
- /* For most registers we require GDB's default names; but also allow
- the numeric names for sp / lr / pc, as a convenience. */
- static const char *const arm_sp_names[] = { "r13", "sp", NULL };
- static const char *const arm_lr_names[] = { "r14", "lr", NULL };
- static const char *const arm_pc_names[] = { "r15", "pc", NULL };
- const struct tdesc_feature *feature;
- int valid_p;
- feature = tdesc_find_feature (tdesc,
- "org.gnu.gdb.arm.core");
- if (feature == NULL)
- {
- feature = tdesc_find_feature (tdesc,
- "org.gnu.gdb.arm.m-profile");
- if (feature == NULL)
- return NULL;
- else
- is_m = true;
- }
- tdesc_data = tdesc_data_alloc ();
- valid_p = 1;
- for (i = 0; i < ARM_SP_REGNUM; i++)
- valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), i,
- arm_register_names[i]);
- valid_p &= tdesc_numbered_register_choices (feature, tdesc_data.get (),
- ARM_SP_REGNUM,
- arm_sp_names);
- valid_p &= tdesc_numbered_register_choices (feature, tdesc_data.get (),
- ARM_LR_REGNUM,
- arm_lr_names);
- valid_p &= tdesc_numbered_register_choices (feature, tdesc_data.get (),
- ARM_PC_REGNUM,
- arm_pc_names);
- if (is_m)
- valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
- ARM_PS_REGNUM, "xpsr");
- else
- valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
- ARM_PS_REGNUM, "cpsr");
- if (!valid_p)
- return NULL;
- feature = tdesc_find_feature (tdesc,
- "org.gnu.gdb.arm.fpa");
- if (feature != NULL)
- {
- valid_p = 1;
- for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++)
- valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), i,
- arm_register_names[i]);
- if (!valid_p)
- return NULL;
- }
- else
- have_fpa_registers = false;
- feature = tdesc_find_feature (tdesc,
- "org.gnu.gdb.xscale.iwmmxt");
- if (feature != NULL)
- {
- static const char *const iwmmxt_names[] = {
- "wR0", "wR1", "wR2", "wR3", "wR4", "wR5", "wR6", "wR7",
- "wR8", "wR9", "wR10", "wR11", "wR12", "wR13", "wR14", "wR15",
- "wCID", "wCon", "wCSSF", "wCASF", "", "", "", "",
- "wCGR0", "wCGR1", "wCGR2", "wCGR3", "", "", "", "",
- };
- valid_p = 1;
- for (i = ARM_WR0_REGNUM; i <= ARM_WR15_REGNUM; i++)
- valid_p
- &= tdesc_numbered_register (feature, tdesc_data.get (), i,
- iwmmxt_names[i - ARM_WR0_REGNUM]);
- /* Check for the control registers, but do not fail if they
- are missing. */
- for (i = ARM_WC0_REGNUM; i <= ARM_WCASF_REGNUM; i++)
- tdesc_numbered_register (feature, tdesc_data.get (), i,
- iwmmxt_names[i - ARM_WR0_REGNUM]);
- for (i = ARM_WCGR0_REGNUM; i <= ARM_WCGR3_REGNUM; i++)
- valid_p
- &= tdesc_numbered_register (feature, tdesc_data.get (), i,
- iwmmxt_names[i - ARM_WR0_REGNUM]);
- if (!valid_p)
- return NULL;
- have_wmmx_registers = true;
- }
- /* If we have a VFP unit, check whether the single precision registers
- are present. If not, then we will synthesize them as pseudo
- registers. */
- feature = tdesc_find_feature (tdesc,
- "org.gnu.gdb.arm.vfp");
- if (feature != NULL)
- {
- static const char *const vfp_double_names[] = {
- "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
- "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
- "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
- "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
- };
- /* Require the double precision registers. There must be either
- 16 or 32. */
- valid_p = 1;
- for (i = 0; i < 32; i++)
- {
- valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
- ARM_D0_REGNUM + i,
- vfp_double_names[i]);
- if (!valid_p)
- break;
- }
- if (!valid_p && i == 16)
- valid_p = 1;
- /* Also require FPSCR. */
- valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
- ARM_FPSCR_REGNUM, "fpscr");
- if (!valid_p)
- return NULL;
- have_vfp = true;
- if (tdesc_unnumbered_register (feature, "s0") == 0)
- have_s_pseudos = true;
- vfp_register_count = i;
- /* If we have VFP, also check for NEON. The architecture allows
- NEON without VFP (integer vector operations only), but GDB
- does not support that. */
- feature = tdesc_find_feature (tdesc,
- "org.gnu.gdb.arm.neon");
- if (feature != NULL)
- {
- /* NEON requires 32 double-precision registers. */
- if (i != 32)
- return NULL;
- /* If there are quad registers defined by the stub, use
- their type; otherwise (normally) provide them with
- the default type. */
- if (tdesc_unnumbered_register (feature, "q0") == 0)
- have_q_pseudos = true;
- }
- }
- /* Check for MVE after all the checks for GPR's, VFP and Neon.
- MVE (Helium) is an M-profile extension. */
- if (is_m)
- {
- /* Do we have the MVE feature? */
- feature = tdesc_find_feature (tdesc,"org.gnu.gdb.arm.m-profile-mve");
- if (feature != nullptr)
- {
- /* If we have MVE, we must always have the VPR register. */
- valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
- register_count, "vpr");
- if (!valid_p)
- {
- warning (_("MVE feature is missing required register vpr."));
- return nullptr;
- }
- have_mve = true;
- mve_vpr_regnum = register_count;
- register_count++;
- /* We can't have Q pseudo registers available here, as that
- would mean we have NEON features, and that is only available
- on A and R profiles. */
- gdb_assert (!have_q_pseudos);
- /* Given we have a M-profile target description, if MVE is
- enabled and there are VFP registers, we should have Q
- pseudo registers (Q0 ~ Q7). */
- if (have_vfp)
- have_q_pseudos = true;
- }
- /* Do we have the ARMv8.1-m PACBTI feature? */
- feature = tdesc_find_feature (tdesc,
- "org.gnu.gdb.arm.m-profile-pacbti");
- if (feature != nullptr)
- {
- /* By advertising this feature, the target acknowledges the
- presence of the ARMv8.1-m PACBTI extensions.
- We don't care for any particular registers in this group, so
- the target is free to include whatever it deems appropriate.
- The expectation is for this feature to include the PAC
- keys. */
- have_pacbti = true;
- }
- }
- }
- /* If there is already a candidate, use it. */
- for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
- best_arch != NULL;
- best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
- {
- arm_gdbarch_tdep *tdep
- = (arm_gdbarch_tdep *) gdbarch_tdep (best_arch->gdbarch);
- if (arm_abi != ARM_ABI_AUTO && arm_abi != tdep->arm_abi)
- continue;
- if (fp_model != ARM_FLOAT_AUTO && fp_model != tdep->fp_model)
- continue;
- /* There are various other properties in tdep that we do not
- need to check here: those derived from a target description,
- since gdbarches with a different target description are
- automatically disqualified. */
- /* Do check is_m, though, since it might come from the binary. */
- if (is_m != tdep->is_m)
- continue;
- /* Also check for ARMv8.1-m PACBTI support, since it might come from
- the binary. */
- if (have_pacbti != tdep->have_pacbti)
- continue;
- /* Found a match. */
- break;
- }
- if (best_arch != NULL)
- return best_arch->gdbarch;
- arm_gdbarch_tdep *tdep = new arm_gdbarch_tdep;
- gdbarch = gdbarch_alloc (&info, tdep);
- /* Record additional information about the architecture we are defining.
- These are gdbarch discriminators, like the OSABI. */
- tdep->arm_abi = arm_abi;
- tdep->fp_model = fp_model;
- tdep->is_m = is_m;
- tdep->have_fpa_registers = have_fpa_registers;
- tdep->have_wmmx_registers = have_wmmx_registers;
- gdb_assert (vfp_register_count == 0
- || vfp_register_count == 16
- || vfp_register_count == 32);
- tdep->vfp_register_count = vfp_register_count;
- tdep->have_s_pseudos = have_s_pseudos;
- tdep->have_q_pseudos = have_q_pseudos;
- tdep->have_neon = have_neon;
- /* Adjust the MVE feature settings. */
- if (have_mve)
- {
- tdep->have_mve = true;
- tdep->mve_vpr_regnum = mve_vpr_regnum;
- }
- /* Adjust the PACBTI feature settings. */
- tdep->have_pacbti = have_pacbti;
- arm_register_g_packet_guesses (gdbarch);
- /* Breakpoints. */
- switch (info.byte_order_for_code)
- {
- case BFD_ENDIAN_BIG:
- tdep->arm_breakpoint = arm_default_arm_be_breakpoint;
- tdep->arm_breakpoint_size = sizeof (arm_default_arm_be_breakpoint);
- tdep->thumb_breakpoint = arm_default_thumb_be_breakpoint;
- tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_be_breakpoint);
- break;
- case BFD_ENDIAN_LITTLE:
- tdep->arm_breakpoint = arm_default_arm_le_breakpoint;
- tdep->arm_breakpoint_size = sizeof (arm_default_arm_le_breakpoint);
- tdep->thumb_breakpoint = arm_default_thumb_le_breakpoint;
- tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_le_breakpoint);
- break;
- default:
- internal_error (__FILE__, __LINE__,
- _("arm_gdbarch_init: bad byte order for float format"));
- }
- /* On ARM targets char defaults to unsigned. */
- set_gdbarch_char_signed (gdbarch, 0);
- /* wchar_t is unsigned under the AAPCS. */
- if (tdep->arm_abi == ARM_ABI_AAPCS)
- set_gdbarch_wchar_signed (gdbarch, 0);
- else
- set_gdbarch_wchar_signed (gdbarch, 1);
- /* Compute type alignment. */
- set_gdbarch_type_align (gdbarch, arm_type_align);
- /* Note: for displaced stepping, this includes the breakpoint, and one word
- of additional scratch space. This setting isn't used for anything beside
- displaced stepping at present. */
- set_gdbarch_max_insn_length (gdbarch, 4 * ARM_DISPLACED_MODIFIED_INSNS);
- /* This should be low enough for everything. */
- tdep->lowest_pc = 0x20;
- tdep->jb_pc = -1; /* Longjump support not enabled by default. */
- /* The default, for both APCS and AAPCS, is to return small
- structures in registers. */
- tdep->struct_return = reg_struct_return;
- set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
- set_gdbarch_frame_align (gdbarch, arm_frame_align);
- if (is_m)
- set_gdbarch_code_of_frame_writable (gdbarch, arm_code_of_frame_writable);
- set_gdbarch_write_pc (gdbarch, arm_write_pc);
- frame_base_set_default (gdbarch, &arm_normal_base);
- /* Address manipulation. */
- set_gdbarch_addr_bits_remove (gdbarch, arm_addr_bits_remove);
- /* Advance PC across function entry code. */
- set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
- /* Detect whether PC is at a point where the stack has been destroyed. */
- set_gdbarch_stack_frame_destroyed_p (gdbarch, arm_stack_frame_destroyed_p);
- /* Skip trampolines. */
- set_gdbarch_skip_trampoline_code (gdbarch, arm_skip_stub);
- /* The stack grows downward. */
- set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
- /* Breakpoint manipulation. */
- set_gdbarch_breakpoint_kind_from_pc (gdbarch, arm_breakpoint_kind_from_pc);
- set_gdbarch_sw_breakpoint_from_kind (gdbarch, arm_sw_breakpoint_from_kind);
- set_gdbarch_breakpoint_kind_from_current_state (gdbarch,
- arm_breakpoint_kind_from_current_state);
- /* Information about registers, etc. */
- set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
- set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
- set_gdbarch_num_regs (gdbarch, register_count);
- set_gdbarch_register_type (gdbarch, arm_register_type);
- set_gdbarch_register_reggroup_p (gdbarch, arm_register_reggroup_p);
- /* This "info float" is FPA-specific. Use the generic version if we
- do not have FPA. */
- if (tdep->have_fpa_registers)
- set_gdbarch_print_float_info (gdbarch, arm_print_float_info);
- /* Internal <-> external register number maps. */
- set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum);
- set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
- set_gdbarch_register_name (gdbarch, arm_register_name);
- /* Returning results. */
- set_gdbarch_return_value (gdbarch, arm_return_value);
- /* Disassembly. */
- set_gdbarch_print_insn (gdbarch, gdb_print_insn_arm);
- /* Minsymbol frobbing. */
- set_gdbarch_elf_make_msymbol_special (gdbarch, arm_elf_make_msymbol_special);
- set_gdbarch_coff_make_msymbol_special (gdbarch,
- arm_coff_make_msymbol_special);
- set_gdbarch_record_special_symbol (gdbarch, arm_record_special_symbol);
- /* Thumb-2 IT block support. */
- set_gdbarch_adjust_breakpoint_address (gdbarch,
- arm_adjust_breakpoint_address);
- /* Virtual tables. */
- set_gdbarch_vbit_in_delta (gdbarch, 1);
- /* Hook in the ABI-specific overrides, if they have been registered. */
- gdbarch_init_osabi (info, gdbarch);
- dwarf2_frame_set_init_reg (gdbarch, arm_dwarf2_frame_init_reg);
- /* Add some default predicates. */
- if (is_m)
- frame_unwind_append_unwinder (gdbarch, &arm_m_exception_unwind);
- frame_unwind_append_unwinder (gdbarch, &arm_stub_unwind);
- dwarf2_append_unwinders (gdbarch);
- frame_unwind_append_unwinder (gdbarch, &arm_exidx_unwind);
- frame_unwind_append_unwinder (gdbarch, &arm_epilogue_frame_unwind);
- frame_unwind_append_unwinder (gdbarch, &arm_prologue_unwind);
- /* Now we have tuned the configuration, set a few final things,
- based on what the OS ABI has told us. */
- /* If the ABI is not otherwise marked, assume the old GNU APCS. EABI
- binaries are always marked. */
- if (tdep->arm_abi == ARM_ABI_AUTO)
- tdep->arm_abi = ARM_ABI_APCS;
- /* Watchpoints are not steppable. */
- set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
- /* We used to default to FPA for generic ARM, but almost nobody
- uses that now, and we now provide a way for the user to force
- the model. So default to the most useful variant. */
- if (tdep->fp_model == ARM_FLOAT_AUTO)
- tdep->fp_model = ARM_FLOAT_SOFT_FPA;
- if (tdep->jb_pc >= 0)
- set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
- /* Floating point sizes and format. */
- set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
- if (tdep->fp_model == ARM_FLOAT_SOFT_FPA || tdep->fp_model == ARM_FLOAT_FPA)
- {
- set_gdbarch_double_format
- (gdbarch, floatformats_ieee_double_littlebyte_bigword);
- set_gdbarch_long_double_format
- (gdbarch, floatformats_ieee_double_littlebyte_bigword);
- }
- else
- {
- set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
- set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
- }
- /* Hook used to decorate frames with signed return addresses, only available
- for ARMv8.1-m PACBTI. */
- if (is_m && have_pacbti)
- set_gdbarch_get_pc_address_flags (gdbarch, arm_get_pc_address_flags);
- if (tdesc_data != nullptr)
- {
- set_tdesc_pseudo_register_name (gdbarch, arm_register_name);
- tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data));
- register_count = gdbarch_num_regs (gdbarch);
- /* Override tdesc_register_type to adjust the types of VFP
- registers for NEON. */
- set_gdbarch_register_type (gdbarch, arm_register_type);
- }
- /* Initialize the pseudo register data. */
- int num_pseudos = 0;
- if (tdep->have_s_pseudos)
- {
- /* VFP single precision pseudo registers (S0~S31). */
- tdep->s_pseudo_base = register_count;
- tdep->s_pseudo_count = 32;
- num_pseudos += tdep->s_pseudo_count;
- if (tdep->have_q_pseudos)
- {
- /* NEON quad precision pseudo registers (Q0~Q15). */
- tdep->q_pseudo_base = register_count + num_pseudos;
- if (have_neon)
- tdep->q_pseudo_count = 16;
- else if (have_mve)
- tdep->q_pseudo_count = ARM_MVE_NUM_Q_REGS;
- num_pseudos += tdep->q_pseudo_count;
- }
- }
- /* Do we have any MVE pseudo registers? */
- if (have_mve)
- {
- tdep->mve_pseudo_base = register_count + num_pseudos;
- tdep->mve_pseudo_count = 1;
- num_pseudos += tdep->mve_pseudo_count;
- }
- /* Do we have any ARMv8.1-m PACBTI pseudo registers. */
- if (have_pacbti)
- {
- tdep->pacbti_pseudo_base = register_count + num_pseudos;
- tdep->pacbti_pseudo_count = 1;
- num_pseudos += tdep->pacbti_pseudo_count;
- }
- /* Set some pseudo register hooks, if we have pseudo registers. */
- if (tdep->have_s_pseudos || have_mve || have_pacbti)
- {
- set_gdbarch_num_pseudo_regs (gdbarch, num_pseudos);
- set_gdbarch_pseudo_register_read (gdbarch, arm_pseudo_read);
- set_gdbarch_pseudo_register_write (gdbarch, arm_pseudo_write);
- }
- /* Add standard register aliases. We add aliases even for those
- names which are used by the current architecture - it's simpler,
- and does no harm, since nothing ever lists user registers. */
- for (i = 0; i < ARRAY_SIZE (arm_register_aliases); i++)
- user_reg_add (gdbarch, arm_register_aliases[i].name,
- value_of_arm_user_reg, &arm_register_aliases[i].regnum);
- set_gdbarch_disassembler_options (gdbarch, &arm_disassembler_options);
- set_gdbarch_valid_disassembler_options (gdbarch, disassembler_options_arm ());
- set_gdbarch_gnu_triplet_regexp (gdbarch, arm_gnu_triplet_regexp);
- return gdbarch;
- }
- static void
- arm_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
- {
- arm_gdbarch_tdep *tdep = (arm_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep == NULL)
- return;
- gdb_printf (file, _("arm_dump_tdep: fp_model = %i\n"),
- (int) tdep->fp_model);
- gdb_printf (file, _("arm_dump_tdep: have_fpa_registers = %i\n"),
- (int) tdep->have_fpa_registers);
- gdb_printf (file, _("arm_dump_tdep: have_wmmx_registers = %i\n"),
- (int) tdep->have_wmmx_registers);
- gdb_printf (file, _("arm_dump_tdep: vfp_register_count = %i\n"),
- (int) tdep->vfp_register_count);
- gdb_printf (file, _("arm_dump_tdep: have_s_pseudos = %s\n"),
- tdep->have_s_pseudos? "true" : "false");
- gdb_printf (file, _("arm_dump_tdep: s_pseudo_base = %i\n"),
- (int) tdep->s_pseudo_base);
- gdb_printf (file, _("arm_dump_tdep: s_pseudo_count = %i\n"),
- (int) tdep->s_pseudo_count);
- gdb_printf (file, _("arm_dump_tdep: have_q_pseudos = %s\n"),
- tdep->have_q_pseudos? "true" : "false");
- gdb_printf (file, _("arm_dump_tdep: q_pseudo_base = %i\n"),
- (int) tdep->q_pseudo_base);
- gdb_printf (file, _("arm_dump_tdep: q_pseudo_count = %i\n"),
- (int) tdep->q_pseudo_count);
- gdb_printf (file, _("arm_dump_tdep: have_neon = %i\n"),
- (int) tdep->have_neon);
- gdb_printf (file, _("arm_dump_tdep: have_mve = %s\n"),
- tdep->have_mve? "yes" : "no");
- gdb_printf (file, _("arm_dump_tdep: mve_vpr_regnum = %i\n"),
- tdep->mve_vpr_regnum);
- gdb_printf (file, _("arm_dump_tdep: mve_pseudo_base = %i\n"),
- tdep->mve_pseudo_base);
- gdb_printf (file, _("arm_dump_tdep: mve_pseudo_count = %i\n"),
- tdep->mve_pseudo_count);
- gdb_printf (file, _("arm_dump_tdep: Lowest pc = 0x%lx\n"),
- (unsigned long) tdep->lowest_pc);
- gdb_printf (file, _("arm_dump_tdep: have_pacbti = %s\n"),
- tdep->have_pacbti? "yes" : "no");
- gdb_printf (file, _("arm_dump_tdep: pacbti_pseudo_base = %i\n"),
- tdep->pacbti_pseudo_base);
- gdb_printf (file, _("arm_dump_tdep: pacbti_pseudo_count = %i\n"),
- tdep->pacbti_pseudo_count);
- gdb_printf (file, _("arm_dump_tdep: is_m = %s\n"),
- tdep->is_m? "yes" : "no");
- }
- #if GDB_SELF_TEST
- namespace selftests
- {
- static void arm_record_test (void);
- static void arm_analyze_prologue_test ();
- }
- #endif
- void _initialize_arm_tdep ();
- void
- _initialize_arm_tdep ()
- {
- long length;
- int i, j;
- char regdesc[1024], *rdptr = regdesc;
- size_t rest = sizeof (regdesc);
- gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
- /* Add ourselves to objfile event chain. */
- gdb::observers::new_objfile.attach (arm_exidx_new_objfile, "arm-tdep");
- /* Register an ELF OS ABI sniffer for ARM binaries. */
- gdbarch_register_osabi_sniffer (bfd_arch_arm,
- bfd_target_elf_flavour,
- arm_elf_osabi_sniffer);
- /* Add root prefix command for all "set arm"/"show arm" commands. */
- add_setshow_prefix_cmd ("arm", no_class,
- _("Various ARM-specific commands."),
- _("Various ARM-specific commands."),
- &setarmcmdlist, &showarmcmdlist,
- &setlist, &showlist);
- arm_disassembler_options = xstrdup ("reg-names-std");
- const disasm_options_t *disasm_options
- = &disassembler_options_arm ()->options;
- int num_disassembly_styles = 0;
- for (i = 0; disasm_options->name[i] != NULL; i++)
- if (startswith (disasm_options->name[i], "reg-names-"))
- num_disassembly_styles++;
- /* Initialize the array that will be passed to add_setshow_enum_cmd(). */
- valid_disassembly_styles = XNEWVEC (const char *,
- num_disassembly_styles + 1);
- for (i = j = 0; disasm_options->name[i] != NULL; i++)
- if (startswith (disasm_options->name[i], "reg-names-"))
- {
- size_t offset = strlen ("reg-names-");
- const char *style = disasm_options->name[i];
- valid_disassembly_styles[j++] = &style[offset];
- if (strcmp (&style[offset], "std") == 0)
- disassembly_style = &style[offset];
- length = snprintf (rdptr, rest, "%s - %s\n", &style[offset],
- disasm_options->description[i]);
- rdptr += length;
- rest -= length;
- }
- /* Mark the end of valid options. */
- valid_disassembly_styles[num_disassembly_styles] = NULL;
- /* Create the help text. */
- std::string helptext = string_printf ("%s%s%s",
- _("The valid values are:\n"),
- regdesc,
- _("The default is \"std\"."));
- add_setshow_enum_cmd("disassembler", no_class,
- valid_disassembly_styles, &disassembly_style,
- _("Set the disassembly style."),
- _("Show the disassembly style."),
- helptext.c_str (),
- set_disassembly_style_sfunc,
- show_disassembly_style_sfunc,
- &setarmcmdlist, &showarmcmdlist);
- add_setshow_boolean_cmd ("apcs32", no_class, &arm_apcs_32,
- _("Set usage of ARM 32-bit mode."),
- _("Show usage of ARM 32-bit mode."),
- _("When off, a 26-bit PC will be used."),
- NULL,
- NULL, /* FIXME: i18n: Usage of ARM 32-bit
- mode is %s. */
- &setarmcmdlist, &showarmcmdlist);
- /* Add a command to allow the user to force the FPU model. */
- add_setshow_enum_cmd ("fpu", no_class, fp_model_strings, ¤t_fp_model,
- _("Set the floating point type."),
- _("Show the floating point type."),
- _("auto - Determine the FP typefrom the OS-ABI.\n\
- softfpa - Software FP, mixed-endian doubles on little-endian ARMs.\n\
- fpa - FPA co-processor (GCC compiled).\n\
- softvfp - Software FP with pure-endian doubles.\n\
- vfp - VFP co-processor."),
- set_fp_model_sfunc, show_fp_model,
- &setarmcmdlist, &showarmcmdlist);
- /* Add a command to allow the user to force the ABI. */
- add_setshow_enum_cmd ("abi", class_support, arm_abi_strings, &arm_abi_string,
- _("Set the ABI."),
- _("Show the ABI."),
- NULL, arm_set_abi, arm_show_abi,
- &setarmcmdlist, &showarmcmdlist);
- /* Add two commands to allow the user to force the assumed
- execution mode. */
- add_setshow_enum_cmd ("fallback-mode", class_support,
- arm_mode_strings, &arm_fallback_mode_string,
- _("Set the mode assumed when symbols are unavailable."),
- _("Show the mode assumed when symbols are unavailable."),
- NULL, NULL, arm_show_fallback_mode,
- &setarmcmdlist, &showarmcmdlist);
- add_setshow_enum_cmd ("force-mode", class_support,
- arm_mode_strings, &arm_force_mode_string,
- _("Set the mode assumed even when symbols are available."),
- _("Show the mode assumed even when symbols are available."),
- NULL, NULL, arm_show_force_mode,
- &setarmcmdlist, &showarmcmdlist);
- /* Debugging flag. */
- add_setshow_boolean_cmd ("arm", class_maintenance, &arm_debug,
- _("Set ARM debugging."),
- _("Show ARM debugging."),
- _("When on, arm-specific debugging is enabled."),
- NULL,
- NULL, /* FIXME: i18n: "ARM debugging is %s. */
- &setdebuglist, &showdebuglist);
- #if GDB_SELF_TEST
- selftests::register_test ("arm-record", selftests::arm_record_test);
- selftests::register_test ("arm_analyze_prologue", selftests::arm_analyze_prologue_test);
- #endif
- }
- /* ARM-reversible process record data structures. */
- #define ARM_INSN_SIZE_BYTES 4
- #define THUMB_INSN_SIZE_BYTES 2
- #define THUMB2_INSN_SIZE_BYTES 4
- /* Position of the bit within a 32-bit ARM instruction
- that defines whether the instruction is a load or store. */
- #define INSN_S_L_BIT_NUM 20
- #define REG_ALLOC(REGS, LENGTH, RECORD_BUF) \
- do \
- { \
- unsigned int reg_len = LENGTH; \
- if (reg_len) \
- { \
- REGS = XNEWVEC (uint32_t, reg_len); \
- memcpy(®S[0], &RECORD_BUF[0], sizeof(uint32_t)*LENGTH); \
- } \
- } \
- while (0)
- #define MEM_ALLOC(MEMS, LENGTH, RECORD_BUF) \
- do \
- { \
- unsigned int mem_len = LENGTH; \
- if (mem_len) \
- { \
- MEMS = XNEWVEC (struct arm_mem_r, mem_len); \
- memcpy(&MEMS->len, &RECORD_BUF[0], \
- sizeof(struct arm_mem_r) * LENGTH); \
- } \
- } \
- while (0)
- /* Checks whether insn is already recorded or yet to be decoded. (boolean expression). */
- #define INSN_RECORDED(ARM_RECORD) \
- (0 != (ARM_RECORD)->reg_rec_count || 0 != (ARM_RECORD)->mem_rec_count)
- /* ARM memory record structure. */
- struct arm_mem_r
- {
- uint32_t len; /* Record length. */
- uint32_t addr; /* Memory address. */
- };
- /* ARM instruction record contains opcode of current insn
- and execution state (before entry to decode_insn()),
- contains list of to-be-modified registers and
- memory blocks (on return from decode_insn()). */
- typedef struct insn_decode_record_t
- {
- struct gdbarch *gdbarch;
- struct regcache *regcache;
- CORE_ADDR this_addr; /* Address of the insn being decoded. */
- uint32_t arm_insn; /* Should accommodate thumb. */
- uint32_t cond; /* Condition code. */
- uint32_t opcode; /* Insn opcode. */
- uint32_t decode; /* Insn decode bits. */
- uint32_t mem_rec_count; /* No of mem records. */
- uint32_t reg_rec_count; /* No of reg records. */
- uint32_t *arm_regs; /* Registers to be saved for this record. */
- struct arm_mem_r *arm_mems; /* Memory to be saved for this record. */
- } insn_decode_record;
- /* Checks ARM SBZ and SBO mandatory fields. */
- static int
- sbo_sbz (uint32_t insn, uint32_t bit_num, uint32_t len, uint32_t sbo)
- {
- uint32_t ones = bits (insn, bit_num - 1, (bit_num -1) + (len - 1));
- if (!len)
- return 1;
- if (!sbo)
- ones = ~ones;
- while (ones)
- {
- if (!(ones & sbo))
- {
- return 0;
- }
- ones = ones >> 1;
- }
- return 1;
- }
- enum arm_record_result
- {
- ARM_RECORD_SUCCESS = 0,
- ARM_RECORD_FAILURE = 1
- };
- typedef enum
- {
- ARM_RECORD_STRH=1,
- ARM_RECORD_STRD
- } arm_record_strx_t;
- typedef enum
- {
- ARM_RECORD=1,
- THUMB_RECORD,
- THUMB2_RECORD
- } record_type_t;
- static int
- arm_record_strx (insn_decode_record *arm_insn_r, uint32_t *record_buf,
- uint32_t *record_buf_mem, arm_record_strx_t str_type)
- {
- struct regcache *reg_cache = arm_insn_r->regcache;
- ULONGEST u_regval[2]= {0};
- uint32_t reg_src1 = 0, reg_src2 = 0;
- uint32_t immed_high = 0, immed_low = 0,offset_8 = 0, tgt_mem_addr = 0;
- arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
- arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
- if (14 == arm_insn_r->opcode || 10 == arm_insn_r->opcode)
- {
- /* 1) Handle misc store, immediate offset. */
- immed_low = bits (arm_insn_r->arm_insn, 0, 3);
- immed_high = bits (arm_insn_r->arm_insn, 8, 11);
- reg_src1 = bits (arm_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_src1,
- &u_regval[0]);
- if (ARM_PC_REGNUM == reg_src1)
- {
- /* If R15 was used as Rn, hence current PC+8. */
- u_regval[0] = u_regval[0] + 8;
- }
- offset_8 = (immed_high << 4) | immed_low;
- /* Calculate target store address. */
- if (14 == arm_insn_r->opcode)
- {
- tgt_mem_addr = u_regval[0] + offset_8;
- }
- else
- {
- tgt_mem_addr = u_regval[0] - offset_8;
- }
- if (ARM_RECORD_STRH == str_type)
- {
- record_buf_mem[0] = 2;
- record_buf_mem[1] = tgt_mem_addr;
- arm_insn_r->mem_rec_count = 1;
- }
- else if (ARM_RECORD_STRD == str_type)
- {
- record_buf_mem[0] = 4;
- record_buf_mem[1] = tgt_mem_addr;
- record_buf_mem[2] = 4;
- record_buf_mem[3] = tgt_mem_addr + 4;
- arm_insn_r->mem_rec_count = 2;
- }
- }
- else if (12 == arm_insn_r->opcode || 8 == arm_insn_r->opcode)
- {
- /* 2) Store, register offset. */
- /* Get Rm. */
- reg_src1 = bits (arm_insn_r->arm_insn, 0, 3);
- /* Get Rn. */
- reg_src2 = bits (arm_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
- regcache_raw_read_unsigned (reg_cache, reg_src2, &u_regval[1]);
- if (15 == reg_src2)
- {
- /* If R15 was used as Rn, hence current PC+8. */
- u_regval[0] = u_regval[0] + 8;
- }
- /* Calculate target store address, Rn +/- Rm, register offset. */
- if (12 == arm_insn_r->opcode)
- {
- tgt_mem_addr = u_regval[0] + u_regval[1];
- }
- else
- {
- tgt_mem_addr = u_regval[1] - u_regval[0];
- }
- if (ARM_RECORD_STRH == str_type)
- {
- record_buf_mem[0] = 2;
- record_buf_mem[1] = tgt_mem_addr;
- arm_insn_r->mem_rec_count = 1;
- }
- else if (ARM_RECORD_STRD == str_type)
- {
- record_buf_mem[0] = 4;
- record_buf_mem[1] = tgt_mem_addr;
- record_buf_mem[2] = 4;
- record_buf_mem[3] = tgt_mem_addr + 4;
- arm_insn_r->mem_rec_count = 2;
- }
- }
- else if (11 == arm_insn_r->opcode || 15 == arm_insn_r->opcode
- || 2 == arm_insn_r->opcode || 6 == arm_insn_r->opcode)
- {
- /* 3) Store, immediate pre-indexed. */
- /* 5) Store, immediate post-indexed. */
- immed_low = bits (arm_insn_r->arm_insn, 0, 3);
- immed_high = bits (arm_insn_r->arm_insn, 8, 11);
- offset_8 = (immed_high << 4) | immed_low;
- reg_src1 = bits (arm_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
- /* Calculate target store address, Rn +/- Rm, register offset. */
- if (15 == arm_insn_r->opcode || 6 == arm_insn_r->opcode)
- {
- tgt_mem_addr = u_regval[0] + offset_8;
- }
- else
- {
- tgt_mem_addr = u_regval[0] - offset_8;
- }
- if (ARM_RECORD_STRH == str_type)
- {
- record_buf_mem[0] = 2;
- record_buf_mem[1] = tgt_mem_addr;
- arm_insn_r->mem_rec_count = 1;
- }
- else if (ARM_RECORD_STRD == str_type)
- {
- record_buf_mem[0] = 4;
- record_buf_mem[1] = tgt_mem_addr;
- record_buf_mem[2] = 4;
- record_buf_mem[3] = tgt_mem_addr + 4;
- arm_insn_r->mem_rec_count = 2;
- }
- /* Record Rn also as it changes. */
- *(record_buf) = bits (arm_insn_r->arm_insn, 16, 19);
- arm_insn_r->reg_rec_count = 1;
- }
- else if (9 == arm_insn_r->opcode || 13 == arm_insn_r->opcode
- || 0 == arm_insn_r->opcode || 4 == arm_insn_r->opcode)
- {
- /* 4) Store, register pre-indexed. */
- /* 6) Store, register post -indexed. */
- reg_src1 = bits (arm_insn_r->arm_insn, 0, 3);
- reg_src2 = bits (arm_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
- regcache_raw_read_unsigned (reg_cache, reg_src2, &u_regval[1]);
- /* Calculate target store address, Rn +/- Rm, register offset. */
- if (13 == arm_insn_r->opcode || 4 == arm_insn_r->opcode)
- {
- tgt_mem_addr = u_regval[0] + u_regval[1];
- }
- else
- {
- tgt_mem_addr = u_regval[1] - u_regval[0];
- }
- if (ARM_RECORD_STRH == str_type)
- {
- record_buf_mem[0] = 2;
- record_buf_mem[1] = tgt_mem_addr;
- arm_insn_r->mem_rec_count = 1;
- }
- else if (ARM_RECORD_STRD == str_type)
- {
- record_buf_mem[0] = 4;
- record_buf_mem[1] = tgt_mem_addr;
- record_buf_mem[2] = 4;
- record_buf_mem[3] = tgt_mem_addr + 4;
- arm_insn_r->mem_rec_count = 2;
- }
- /* Record Rn also as it changes. */
- *(record_buf) = bits (arm_insn_r->arm_insn, 16, 19);
- arm_insn_r->reg_rec_count = 1;
- }
- return 0;
- }
- /* Handling ARM extension space insns. */
- static int
- arm_record_extension_space (insn_decode_record *arm_insn_r)
- {
- int ret = 0; /* Return value: -1:record failure ; 0:success */
- uint32_t opcode1 = 0, opcode2 = 0, insn_op1 = 0;
- uint32_t record_buf[8], record_buf_mem[8];
- uint32_t reg_src1 = 0;
- struct regcache *reg_cache = arm_insn_r->regcache;
- ULONGEST u_regval = 0;
- gdb_assert (!INSN_RECORDED(arm_insn_r));
- /* Handle unconditional insn extension space. */
- opcode1 = bits (arm_insn_r->arm_insn, 20, 27);
- opcode2 = bits (arm_insn_r->arm_insn, 4, 7);
- if (arm_insn_r->cond)
- {
- /* PLD has no affect on architectural state, it just affects
- the caches. */
- if (5 == ((opcode1 & 0xE0) >> 5))
- {
- /* BLX(1) */
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = ARM_LR_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- }
- /* STC2, LDC2, MCR2, MRC2, CDP2: <TBD>, co-processor insn. */
- }
- opcode1 = bits (arm_insn_r->arm_insn, 25, 27);
- if (3 == opcode1 && bit (arm_insn_r->arm_insn, 4))
- {
- ret = -1;
- /* Undefined instruction on ARM V5; need to handle if later
- versions define it. */
- }
- opcode1 = bits (arm_insn_r->arm_insn, 24, 27);
- opcode2 = bits (arm_insn_r->arm_insn, 4, 7);
- insn_op1 = bits (arm_insn_r->arm_insn, 20, 23);
- /* Handle arithmetic insn extension space. */
- if (!opcode1 && 9 == opcode2 && 1 != arm_insn_r->cond
- && !INSN_RECORDED(arm_insn_r))
- {
- /* Handle MLA(S) and MUL(S). */
- if (in_inclusive_range (insn_op1, 0U, 3U))
- {
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[1] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- }
- else if (in_inclusive_range (insn_op1, 4U, 15U))
- {
- /* Handle SMLAL(S), SMULL(S), UMLAL(S), UMULL(S). */
- record_buf[0] = bits (arm_insn_r->arm_insn, 16, 19);
- record_buf[1] = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[2] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 3;
- }
- }
- opcode1 = bits (arm_insn_r->arm_insn, 26, 27);
- opcode2 = bits (arm_insn_r->arm_insn, 23, 24);
- insn_op1 = bits (arm_insn_r->arm_insn, 21, 22);
- /* Handle control insn extension space. */
- if (!opcode1 && 2 == opcode2 && !bit (arm_insn_r->arm_insn, 20)
- && 1 != arm_insn_r->cond && !INSN_RECORDED(arm_insn_r))
- {
- if (!bit (arm_insn_r->arm_insn,25))
- {
- if (!bits (arm_insn_r->arm_insn, 4, 7))
- {
- if ((0 == insn_op1) || (2 == insn_op1))
- {
- /* MRS. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- }
- else if (1 == insn_op1)
- {
- /* CSPR is going to be changed. */
- record_buf[0] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- }
- else if (3 == insn_op1)
- {
- /* SPSR is going to be changed. */
- /* We need to get SPSR value, which is yet to be done. */
- return -1;
- }
- }
- else if (1 == bits (arm_insn_r->arm_insn, 4, 7))
- {
- if (1 == insn_op1)
- {
- /* BX. */
- record_buf[0] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- }
- else if (3 == insn_op1)
- {
- /* CLZ. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- }
- }
- else if (3 == bits (arm_insn_r->arm_insn, 4, 7))
- {
- /* BLX. */
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = ARM_LR_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- }
- else if (5 == bits (arm_insn_r->arm_insn, 4, 7))
- {
- /* QADD, QSUB, QDADD, QDSUB */
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 2;
- }
- else if (7 == bits (arm_insn_r->arm_insn, 4, 7))
- {
- /* BKPT. */
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = ARM_LR_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- /* Save SPSR also;how? */
- return -1;
- }
- else if(8 == bits (arm_insn_r->arm_insn, 4, 7)
- || 10 == bits (arm_insn_r->arm_insn, 4, 7)
- || 12 == bits (arm_insn_r->arm_insn, 4, 7)
- || 14 == bits (arm_insn_r->arm_insn, 4, 7)
- )
- {
- if (0 == insn_op1 || 1 == insn_op1)
- {
- /* SMLA<x><y>, SMLAW<y>, SMULW<y>. */
- /* We dont do optimization for SMULW<y> where we
- need only Rd. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[1] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- }
- else if (2 == insn_op1)
- {
- /* SMLAL<x><y>. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[1] = bits (arm_insn_r->arm_insn, 16, 19);
- arm_insn_r->reg_rec_count = 2;
- }
- else if (3 == insn_op1)
- {
- /* SMUL<x><y>. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- }
- }
- }
- else
- {
- /* MSR : immediate form. */
- if (1 == insn_op1)
- {
- /* CSPR is going to be changed. */
- record_buf[0] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- }
- else if (3 == insn_op1)
- {
- /* SPSR is going to be changed. */
- /* we need to get SPSR value, which is yet to be done */
- return -1;
- }
- }
- }
- opcode1 = bits (arm_insn_r->arm_insn, 25, 27);
- opcode2 = bits (arm_insn_r->arm_insn, 20, 24);
- insn_op1 = bits (arm_insn_r->arm_insn, 5, 6);
- /* Handle load/store insn extension space. */
- if (!opcode1 && bit (arm_insn_r->arm_insn, 7)
- && bit (arm_insn_r->arm_insn, 4) && 1 != arm_insn_r->cond
- && !INSN_RECORDED(arm_insn_r))
- {
- /* SWP/SWPB. */
- if (0 == insn_op1)
- {
- /* These insn, changes register and memory as well. */
- /* SWP or SWPB insn. */
- /* Get memory address given by Rn. */
- reg_src1 = bits (arm_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval);
- /* SWP insn ?, swaps word. */
- if (8 == arm_insn_r->opcode)
- {
- record_buf_mem[0] = 4;
- }
- else
- {
- /* SWPB insn, swaps only byte. */
- record_buf_mem[0] = 1;
- }
- record_buf_mem[1] = u_regval;
- arm_insn_r->mem_rec_count = 1;
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- }
- else if (1 == insn_op1 && !bit (arm_insn_r->arm_insn, 20))
- {
- /* STRH. */
- arm_record_strx(arm_insn_r, &record_buf[0], &record_buf_mem[0],
- ARM_RECORD_STRH);
- }
- else if (2 == insn_op1 && !bit (arm_insn_r->arm_insn, 20))
- {
- /* LDRD. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[1] = record_buf[0] + 1;
- arm_insn_r->reg_rec_count = 2;
- }
- else if (3 == insn_op1 && !bit (arm_insn_r->arm_insn, 20))
- {
- /* STRD. */
- arm_record_strx(arm_insn_r, &record_buf[0], &record_buf_mem[0],
- ARM_RECORD_STRD);
- }
- else if (bit (arm_insn_r->arm_insn, 20) && insn_op1 <= 3)
- {
- /* LDRH, LDRSB, LDRSH. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- }
- }
- opcode1 = bits (arm_insn_r->arm_insn, 23, 27);
- if (24 == opcode1 && bit (arm_insn_r->arm_insn, 21)
- && !INSN_RECORDED(arm_insn_r))
- {
- ret = -1;
- /* Handle coprocessor insn extension space. */
- }
- /* To be done for ARMv5 and later; as of now we return -1. */
- if (-1 == ret)
- return ret;
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (arm_insn_r->arm_mems, arm_insn_r->mem_rec_count, record_buf_mem);
- return ret;
- }
- /* Handling opcode 000 insns. */
- static int
- arm_record_data_proc_misc_ld_str (insn_decode_record *arm_insn_r)
- {
- struct regcache *reg_cache = arm_insn_r->regcache;
- uint32_t record_buf[8], record_buf_mem[8];
- ULONGEST u_regval[2] = {0};
- uint32_t reg_src1 = 0;
- uint32_t opcode1 = 0;
- arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
- arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
- opcode1 = bits (arm_insn_r->arm_insn, 20, 24);
- if (!((opcode1 & 0x19) == 0x10))
- {
- /* Data-processing (register) and Data-processing (register-shifted
- register */
- /* Out of 11 shifter operands mode, all the insn modifies destination
- register, which is specified by 13-16 decode. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[1] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- }
- else if ((arm_insn_r->decode < 8) && ((opcode1 & 0x19) == 0x10))
- {
- /* Miscellaneous instructions */
- if (3 == arm_insn_r->decode && 0x12 == opcode1
- && sbo_sbz (arm_insn_r->arm_insn, 9, 12, 1))
- {
- /* Handle BLX, branch and link/exchange. */
- if (9 == arm_insn_r->opcode)
- {
- /* Branch is chosen by setting T bit of CSPR, bitp[0] of Rm,
- and R14 stores the return address. */
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = ARM_LR_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- }
- }
- else if (7 == arm_insn_r->decode && 0x12 == opcode1)
- {
- /* Handle enhanced software breakpoint insn, BKPT. */
- /* CPSR is changed to be executed in ARM state, disabling normal
- interrupts, entering abort mode. */
- /* According to high vector configuration PC is set. */
- /* user hit breakpoint and type reverse, in
- that case, we need to go back with previous CPSR and
- Program Counter. */
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = ARM_LR_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- /* Save SPSR also; how? */
- return -1;
- }
- else if (1 == arm_insn_r->decode && 0x12 == opcode1
- && sbo_sbz (arm_insn_r->arm_insn, 9, 12, 1))
- {
- /* Handle BX, branch and link/exchange. */
- /* Branch is chosen by setting T bit of CSPR, bitp[0] of Rm. */
- record_buf[0] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- }
- else if (1 == arm_insn_r->decode && 0x16 == opcode1
- && sbo_sbz (arm_insn_r->arm_insn, 9, 4, 1)
- && sbo_sbz (arm_insn_r->arm_insn, 17, 4, 1))
- {
- /* Count leading zeros: CLZ. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- }
- else if (!bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM)
- && (8 == arm_insn_r->opcode || 10 == arm_insn_r->opcode)
- && sbo_sbz (arm_insn_r->arm_insn, 17, 4, 1)
- && sbo_sbz (arm_insn_r->arm_insn, 1, 12, 0))
- {
- /* Handle MRS insn. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- }
- }
- else if (9 == arm_insn_r->decode && opcode1 < 0x10)
- {
- /* Multiply and multiply-accumulate */
- /* Handle multiply instructions. */
- /* MLA, MUL, SMLAL, SMULL, UMLAL, UMULL. */
- if (0 == arm_insn_r->opcode || 1 == arm_insn_r->opcode)
- {
- /* Handle MLA and MUL. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 16, 19);
- record_buf[1] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- }
- else if (4 <= arm_insn_r->opcode && 7 >= arm_insn_r->opcode)
- {
- /* Handle SMLAL, SMULL, UMLAL, UMULL. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 16, 19);
- record_buf[1] = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[2] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 3;
- }
- }
- else if (9 == arm_insn_r->decode && opcode1 > 0x10)
- {
- /* Synchronization primitives */
- /* Handling SWP, SWPB. */
- /* These insn, changes register and memory as well. */
- /* SWP or SWPB insn. */
- reg_src1 = bits (arm_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
- /* SWP insn ?, swaps word. */
- if (8 == arm_insn_r->opcode)
- {
- record_buf_mem[0] = 4;
- }
- else
- {
- /* SWPB insn, swaps only byte. */
- record_buf_mem[0] = 1;
- }
- record_buf_mem[1] = u_regval[0];
- arm_insn_r->mem_rec_count = 1;
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- }
- else if (11 == arm_insn_r->decode || 13 == arm_insn_r->decode
- || 15 == arm_insn_r->decode)
- {
- if ((opcode1 & 0x12) == 2)
- {
- /* Extra load/store (unprivileged) */
- return -1;
- }
- else
- {
- /* Extra load/store */
- switch (bits (arm_insn_r->arm_insn, 5, 6))
- {
- case 1:
- if ((opcode1 & 0x05) == 0x0 || (opcode1 & 0x05) == 0x4)
- {
- /* STRH (register), STRH (immediate) */
- arm_record_strx (arm_insn_r, &record_buf[0],
- &record_buf_mem[0], ARM_RECORD_STRH);
- }
- else if ((opcode1 & 0x05) == 0x1)
- {
- /* LDRH (register) */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- if (bit (arm_insn_r->arm_insn, 21))
- {
- /* Write back to Rn. */
- record_buf[arm_insn_r->reg_rec_count++]
- = bits (arm_insn_r->arm_insn, 16, 19);
- }
- }
- else if ((opcode1 & 0x05) == 0x5)
- {
- /* LDRH (immediate), LDRH (literal) */
- int rn = bits (arm_insn_r->arm_insn, 16, 19);
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- if (rn != 15)
- {
- /*LDRH (immediate) */
- if (bit (arm_insn_r->arm_insn, 21))
- {
- /* Write back to Rn. */
- record_buf[arm_insn_r->reg_rec_count++] = rn;
- }
- }
- }
- else
- return -1;
- break;
- case 2:
- if ((opcode1 & 0x05) == 0x0)
- {
- /* LDRD (register) */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[1] = record_buf[0] + 1;
- arm_insn_r->reg_rec_count = 2;
- if (bit (arm_insn_r->arm_insn, 21))
- {
- /* Write back to Rn. */
- record_buf[arm_insn_r->reg_rec_count++]
- = bits (arm_insn_r->arm_insn, 16, 19);
- }
- }
- else if ((opcode1 & 0x05) == 0x1)
- {
- /* LDRSB (register) */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- if (bit (arm_insn_r->arm_insn, 21))
- {
- /* Write back to Rn. */
- record_buf[arm_insn_r->reg_rec_count++]
- = bits (arm_insn_r->arm_insn, 16, 19);
- }
- }
- else if ((opcode1 & 0x05) == 0x4 || (opcode1 & 0x05) == 0x5)
- {
- /* LDRD (immediate), LDRD (literal), LDRSB (immediate),
- LDRSB (literal) */
- int rn = bits (arm_insn_r->arm_insn, 16, 19);
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- if (rn != 15)
- {
- /*LDRD (immediate), LDRSB (immediate) */
- if (bit (arm_insn_r->arm_insn, 21))
- {
- /* Write back to Rn. */
- record_buf[arm_insn_r->reg_rec_count++] = rn;
- }
- }
- }
- else
- return -1;
- break;
- case 3:
- if ((opcode1 & 0x05) == 0x0)
- {
- /* STRD (register) */
- arm_record_strx (arm_insn_r, &record_buf[0],
- &record_buf_mem[0], ARM_RECORD_STRD);
- }
- else if ((opcode1 & 0x05) == 0x1)
- {
- /* LDRSH (register) */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- if (bit (arm_insn_r->arm_insn, 21))
- {
- /* Write back to Rn. */
- record_buf[arm_insn_r->reg_rec_count++]
- = bits (arm_insn_r->arm_insn, 16, 19);
- }
- }
- else if ((opcode1 & 0x05) == 0x4)
- {
- /* STRD (immediate) */
- arm_record_strx (arm_insn_r, &record_buf[0],
- &record_buf_mem[0], ARM_RECORD_STRD);
- }
- else if ((opcode1 & 0x05) == 0x5)
- {
- /* LDRSH (immediate), LDRSH (literal) */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- if (bit (arm_insn_r->arm_insn, 21))
- {
- /* Write back to Rn. */
- record_buf[arm_insn_r->reg_rec_count++]
- = bits (arm_insn_r->arm_insn, 16, 19);
- }
- }
- else
- return -1;
- break;
- default:
- return -1;
- }
- }
- }
- else
- {
- return -1;
- }
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (arm_insn_r->arm_mems, arm_insn_r->mem_rec_count, record_buf_mem);
- return 0;
- }
- /* Handling opcode 001 insns. */
- static int
- arm_record_data_proc_imm (insn_decode_record *arm_insn_r)
- {
- uint32_t record_buf[8], record_buf_mem[8];
- arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
- arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
- if ((9 == arm_insn_r->opcode || 11 == arm_insn_r->opcode)
- && 2 == bits (arm_insn_r->arm_insn, 20, 21)
- && sbo_sbz (arm_insn_r->arm_insn, 13, 4, 1)
- )
- {
- /* Handle MSR insn. */
- if (9 == arm_insn_r->opcode)
- {
- /* CSPR is going to be changed. */
- record_buf[0] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- }
- else
- {
- /* SPSR is going to be changed. */
- }
- }
- else if (arm_insn_r->opcode <= 15)
- {
- /* Normal data processing insns. */
- /* Out of 11 shifter operands mode, all the insn modifies destination
- register, which is specified by 13-16 decode. */
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[1] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- }
- else
- {
- return -1;
- }
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (arm_insn_r->arm_mems, arm_insn_r->mem_rec_count, record_buf_mem);
- return 0;
- }
- static int
- arm_record_media (insn_decode_record *arm_insn_r)
- {
- uint32_t record_buf[8];
- switch (bits (arm_insn_r->arm_insn, 22, 24))
- {
- case 0:
- /* Parallel addition and subtraction, signed */
- case 1:
- /* Parallel addition and subtraction, unsigned */
- case 2:
- case 3:
- /* Packing, unpacking, saturation and reversal */
- {
- int rd = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[arm_insn_r->reg_rec_count++] = rd;
- }
- break;
- case 4:
- case 5:
- /* Signed multiplies */
- {
- int rd = bits (arm_insn_r->arm_insn, 16, 19);
- unsigned int op1 = bits (arm_insn_r->arm_insn, 20, 22);
- record_buf[arm_insn_r->reg_rec_count++] = rd;
- if (op1 == 0x0)
- record_buf[arm_insn_r->reg_rec_count++] = ARM_PS_REGNUM;
- else if (op1 == 0x4)
- record_buf[arm_insn_r->reg_rec_count++]
- = bits (arm_insn_r->arm_insn, 12, 15);
- }
- break;
- case 6:
- {
- if (bit (arm_insn_r->arm_insn, 21)
- && bits (arm_insn_r->arm_insn, 5, 6) == 0x2)
- {
- /* SBFX */
- record_buf[arm_insn_r->reg_rec_count++]
- = bits (arm_insn_r->arm_insn, 12, 15);
- }
- else if (bits (arm_insn_r->arm_insn, 20, 21) == 0x0
- && bits (arm_insn_r->arm_insn, 5, 7) == 0x0)
- {
- /* USAD8 and USADA8 */
- record_buf[arm_insn_r->reg_rec_count++]
- = bits (arm_insn_r->arm_insn, 16, 19);
- }
- }
- break;
- case 7:
- {
- if (bits (arm_insn_r->arm_insn, 20, 21) == 0x3
- && bits (arm_insn_r->arm_insn, 5, 7) == 0x7)
- {
- /* Permanently UNDEFINED */
- return -1;
- }
- else
- {
- /* BFC, BFI and UBFX */
- record_buf[arm_insn_r->reg_rec_count++]
- = bits (arm_insn_r->arm_insn, 12, 15);
- }
- }
- break;
- default:
- return -1;
- }
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
- return 0;
- }
- /* Handle ARM mode instructions with opcode 010. */
- static int
- arm_record_ld_st_imm_offset (insn_decode_record *arm_insn_r)
- {
- struct regcache *reg_cache = arm_insn_r->regcache;
- uint32_t reg_base , reg_dest;
- uint32_t offset_12, tgt_mem_addr;
- uint32_t record_buf[8], record_buf_mem[8];
- unsigned char wback;
- ULONGEST u_regval;
- /* Calculate wback. */
- wback = (bit (arm_insn_r->arm_insn, 24) == 0)
- || (bit (arm_insn_r->arm_insn, 21) == 1);
- arm_insn_r->reg_rec_count = 0;
- reg_base = bits (arm_insn_r->arm_insn, 16, 19);
- if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
- {
- /* LDR (immediate), LDR (literal), LDRB (immediate), LDRB (literal), LDRBT
- and LDRT. */
- reg_dest = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[arm_insn_r->reg_rec_count++] = reg_dest;
- /* The LDR instruction is capable of doing branching. If MOV LR, PC
- preceeds a LDR instruction having R15 as reg_base, it
- emulates a branch and link instruction, and hence we need to save
- CPSR and PC as well. */
- if (ARM_PC_REGNUM == reg_dest)
- record_buf[arm_insn_r->reg_rec_count++] = ARM_PS_REGNUM;
- /* If wback is true, also save the base register, which is going to be
- written to. */
- if (wback)
- record_buf[arm_insn_r->reg_rec_count++] = reg_base;
- }
- else
- {
- /* STR (immediate), STRB (immediate), STRBT and STRT. */
- offset_12 = bits (arm_insn_r->arm_insn, 0, 11);
- regcache_raw_read_unsigned (reg_cache, reg_base, &u_regval);
- /* Handle bit U. */
- if (bit (arm_insn_r->arm_insn, 23))
- {
- /* U == 1: Add the offset. */
- tgt_mem_addr = (uint32_t) u_regval + offset_12;
- }
- else
- {
- /* U == 0: subtract the offset. */
- tgt_mem_addr = (uint32_t) u_regval - offset_12;
- }
- /* Bit 22 tells us whether the store instruction writes 1 byte or 4
- bytes. */
- if (bit (arm_insn_r->arm_insn, 22))
- {
- /* STRB and STRBT: 1 byte. */
- record_buf_mem[0] = 1;
- }
- else
- {
- /* STR and STRT: 4 bytes. */
- record_buf_mem[0] = 4;
- }
- /* Handle bit P. */
- if (bit (arm_insn_r->arm_insn, 24))
- record_buf_mem[1] = tgt_mem_addr;
- else
- record_buf_mem[1] = (uint32_t) u_regval;
- arm_insn_r->mem_rec_count = 1;
- /* If wback is true, also save the base register, which is going to be
- written to. */
- if (wback)
- record_buf[arm_insn_r->reg_rec_count++] = reg_base;
- }
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (arm_insn_r->arm_mems, arm_insn_r->mem_rec_count, record_buf_mem);
- return 0;
- }
- /* Handling opcode 011 insns. */
- static int
- arm_record_ld_st_reg_offset (insn_decode_record *arm_insn_r)
- {
- struct regcache *reg_cache = arm_insn_r->regcache;
- uint32_t shift_imm = 0;
- uint32_t reg_src1 = 0, reg_src2 = 0, reg_dest = 0;
- uint32_t offset_12 = 0, tgt_mem_addr = 0;
- uint32_t record_buf[8], record_buf_mem[8];
- LONGEST s_word;
- ULONGEST u_regval[2];
- if (bit (arm_insn_r->arm_insn, 4))
- return arm_record_media (arm_insn_r);
- arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
- arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
- /* Handle enhanced store insns and LDRD DSP insn,
- order begins according to addressing modes for store insns
- STRH insn. */
- /* LDR or STR? */
- if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
- {
- reg_dest = bits (arm_insn_r->arm_insn, 12, 15);
- /* LDR insn has a capability to do branching, if
- MOV LR, PC is preceded by LDR insn having Rn as R15
- in that case, it emulates branch and link insn, and hence we
- need to save CSPR and PC as well. */
- if (15 != reg_dest)
- {
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- }
- else
- {
- record_buf[0] = reg_dest;
- record_buf[1] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- }
- }
- else
- {
- if (! bits (arm_insn_r->arm_insn, 4, 11))
- {
- /* Store insn, register offset and register pre-indexed,
- register post-indexed. */
- /* Get Rm. */
- reg_src1 = bits (arm_insn_r->arm_insn, 0, 3);
- /* Get Rn. */
- reg_src2 = bits (arm_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_src1
- , &u_regval[0]);
- regcache_raw_read_unsigned (reg_cache, reg_src2
- , &u_regval[1]);
- if (15 == reg_src2)
- {
- /* If R15 was used as Rn, hence current PC+8. */
- /* Pre-indexed mode doesnt reach here ; illegal insn. */
- u_regval[0] = u_regval[0] + 8;
- }
- /* Calculate target store address, Rn +/- Rm, register offset. */
- /* U == 1. */
- if (bit (arm_insn_r->arm_insn, 23))
- {
- tgt_mem_addr = u_regval[0] + u_regval[1];
- }
- else
- {
- tgt_mem_addr = u_regval[1] - u_regval[0];
- }
- switch (arm_insn_r->opcode)
- {
- /* STR. */
- case 8:
- case 12:
- /* STR. */
- case 9:
- case 13:
- /* STRT. */
- case 1:
- case 5:
- /* STR. */
- case 0:
- case 4:
- record_buf_mem[0] = 4;
- break;
- /* STRB. */
- case 10:
- case 14:
- /* STRB. */
- case 11:
- case 15:
- /* STRBT. */
- case 3:
- case 7:
- /* STRB. */
- case 2:
- case 6:
- record_buf_mem[0] = 1;
- break;
- default:
- gdb_assert_not_reached ("no decoding pattern found");
- break;
- }
- record_buf_mem[1] = tgt_mem_addr;
- arm_insn_r->mem_rec_count = 1;
- if (9 == arm_insn_r->opcode || 11 == arm_insn_r->opcode
- || 13 == arm_insn_r->opcode || 15 == arm_insn_r->opcode
- || 0 == arm_insn_r->opcode || 2 == arm_insn_r->opcode
- || 4 == arm_insn_r->opcode || 6 == arm_insn_r->opcode
- || 1 == arm_insn_r->opcode || 3 == arm_insn_r->opcode
- || 5 == arm_insn_r->opcode || 7 == arm_insn_r->opcode
- )
- {
- /* Rn is going to be changed in pre-indexed mode and
- post-indexed mode as well. */
- record_buf[0] = reg_src2;
- arm_insn_r->reg_rec_count = 1;
- }
- }
- else
- {
- /* Store insn, scaled register offset; scaled pre-indexed. */
- offset_12 = bits (arm_insn_r->arm_insn, 5, 6);
- /* Get Rm. */
- reg_src1 = bits (arm_insn_r->arm_insn, 0, 3);
- /* Get Rn. */
- reg_src2 = bits (arm_insn_r->arm_insn, 16, 19);
- /* Get shift_imm. */
- shift_imm = bits (arm_insn_r->arm_insn, 7, 11);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
- regcache_raw_read_signed (reg_cache, reg_src1, &s_word);
- regcache_raw_read_unsigned (reg_cache, reg_src2, &u_regval[1]);
- /* Offset_12 used as shift. */
- switch (offset_12)
- {
- case 0:
- /* Offset_12 used as index. */
- offset_12 = u_regval[0] << shift_imm;
- break;
- case 1:
- offset_12 = (!shift_imm)?0:u_regval[0] >> shift_imm;
- break;
- case 2:
- if (!shift_imm)
- {
- if (bit (u_regval[0], 31))
- {
- offset_12 = 0xFFFFFFFF;
- }
- else
- {
- offset_12 = 0;
- }
- }
- else
- {
- /* This is arithmetic shift. */
- offset_12 = s_word >> shift_imm;
- }
- break;
- case 3:
- if (!shift_imm)
- {
- regcache_raw_read_unsigned (reg_cache, ARM_PS_REGNUM,
- &u_regval[1]);
- /* Get C flag value and shift it by 31. */
- offset_12 = (((bit (u_regval[1], 29)) << 31) \
- | (u_regval[0]) >> 1);
- }
- else
- {
- offset_12 = (u_regval[0] >> shift_imm) \
- | (u_regval[0] <<
- (sizeof(uint32_t) - shift_imm));
- }
- break;
- default:
- gdb_assert_not_reached ("no decoding pattern found");
- break;
- }
- regcache_raw_read_unsigned (reg_cache, reg_src2, &u_regval[1]);
- /* bit U set. */
- if (bit (arm_insn_r->arm_insn, 23))
- {
- tgt_mem_addr = u_regval[1] + offset_12;
- }
- else
- {
- tgt_mem_addr = u_regval[1] - offset_12;
- }
- switch (arm_insn_r->opcode)
- {
- /* STR. */
- case 8:
- case 12:
- /* STR. */
- case 9:
- case 13:
- /* STRT. */
- case 1:
- case 5:
- /* STR. */
- case 0:
- case 4:
- record_buf_mem[0] = 4;
- break;
- /* STRB. */
- case 10:
- case 14:
- /* STRB. */
- case 11:
- case 15:
- /* STRBT. */
- case 3:
- case 7:
- /* STRB. */
- case 2:
- case 6:
- record_buf_mem[0] = 1;
- break;
- default:
- gdb_assert_not_reached ("no decoding pattern found");
- break;
- }
- record_buf_mem[1] = tgt_mem_addr;
- arm_insn_r->mem_rec_count = 1;
- if (9 == arm_insn_r->opcode || 11 == arm_insn_r->opcode
- || 13 == arm_insn_r->opcode || 15 == arm_insn_r->opcode
- || 0 == arm_insn_r->opcode || 2 == arm_insn_r->opcode
- || 4 == arm_insn_r->opcode || 6 == arm_insn_r->opcode
- || 1 == arm_insn_r->opcode || 3 == arm_insn_r->opcode
- || 5 == arm_insn_r->opcode || 7 == arm_insn_r->opcode
- )
- {
- /* Rn is going to be changed in register scaled pre-indexed
- mode,and scaled post indexed mode. */
- record_buf[0] = reg_src2;
- arm_insn_r->reg_rec_count = 1;
- }
- }
- }
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (arm_insn_r->arm_mems, arm_insn_r->mem_rec_count, record_buf_mem);
- return 0;
- }
- /* Handle ARM mode instructions with opcode 100. */
- static int
- arm_record_ld_st_multiple (insn_decode_record *arm_insn_r)
- {
- struct regcache *reg_cache = arm_insn_r->regcache;
- uint32_t register_count = 0, register_bits;
- uint32_t reg_base, addr_mode;
- uint32_t record_buf[24], record_buf_mem[48];
- uint32_t wback;
- ULONGEST u_regval;
- /* Fetch the list of registers. */
- register_bits = bits (arm_insn_r->arm_insn, 0, 15);
- arm_insn_r->reg_rec_count = 0;
- /* Fetch the base register that contains the address we are loading data
- to. */
- reg_base = bits (arm_insn_r->arm_insn, 16, 19);
- /* Calculate wback. */
- wback = (bit (arm_insn_r->arm_insn, 21) == 1);
- if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
- {
- /* LDM/LDMIA/LDMFD, LDMDA/LDMFA, LDMDB and LDMIB. */
- /* Find out which registers are going to be loaded from memory. */
- while (register_bits)
- {
- if (register_bits & 0x00000001)
- record_buf[arm_insn_r->reg_rec_count++] = register_count;
- register_bits = register_bits >> 1;
- register_count++;
- }
-
- /* If wback is true, also save the base register, which is going to be
- written to. */
- if (wback)
- record_buf[arm_insn_r->reg_rec_count++] = reg_base;
- /* Save the CPSR register. */
- record_buf[arm_insn_r->reg_rec_count++] = ARM_PS_REGNUM;
- }
- else
- {
- /* STM (STMIA, STMEA), STMDA (STMED), STMDB (STMFD) and STMIB (STMFA). */
- addr_mode = bits (arm_insn_r->arm_insn, 23, 24);
- regcache_raw_read_unsigned (reg_cache, reg_base, &u_regval);
- /* Find out how many registers are going to be stored to memory. */
- while (register_bits)
- {
- if (register_bits & 0x00000001)
- register_count++;
- register_bits = register_bits >> 1;
- }
- switch (addr_mode)
- {
- /* STMDA (STMED): Decrement after. */
- case 0:
- record_buf_mem[1] = (uint32_t) u_regval
- - register_count * ARM_INT_REGISTER_SIZE + 4;
- break;
- /* STM (STMIA, STMEA): Increment after. */
- case 1:
- record_buf_mem[1] = (uint32_t) u_regval;
- break;
- /* STMDB (STMFD): Decrement before. */
- case 2:
- record_buf_mem[1] = (uint32_t) u_regval
- - register_count * ARM_INT_REGISTER_SIZE;
- break;
- /* STMIB (STMFA): Increment before. */
- case 3:
- record_buf_mem[1] = (uint32_t) u_regval + ARM_INT_REGISTER_SIZE;
- break;
- default:
- gdb_assert_not_reached ("no decoding pattern found");
- break;
- }
- record_buf_mem[0] = register_count * ARM_INT_REGISTER_SIZE;
- arm_insn_r->mem_rec_count = 1;
- /* If wback is true, also save the base register, which is going to be
- written to. */
- if (wback)
- record_buf[arm_insn_r->reg_rec_count++] = reg_base;
- }
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (arm_insn_r->arm_mems, arm_insn_r->mem_rec_count, record_buf_mem);
- return 0;
- }
- /* Handling opcode 101 insns. */
- static int
- arm_record_b_bl (insn_decode_record *arm_insn_r)
- {
- uint32_t record_buf[8];
- /* Handle B, BL, BLX(1) insns. */
- /* B simply branches so we do nothing here. */
- /* Note: BLX(1) doesnt fall here but instead it falls into
- extension space. */
- if (bit (arm_insn_r->arm_insn, 24))
- {
- record_buf[0] = ARM_LR_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- }
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
- return 0;
- }
- static int
- arm_record_unsupported_insn (insn_decode_record *arm_insn_r)
- {
- gdb_printf (gdb_stderr,
- _("Process record does not support instruction "
- "0x%0x at address %s.\n"),arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch, arm_insn_r->this_addr));
- return -1;
- }
- /* Record handler for vector data transfer instructions. */
- static int
- arm_record_vdata_transfer_insn (insn_decode_record *arm_insn_r)
- {
- uint32_t bits_a, bit_c, bit_l, reg_t, reg_v;
- uint32_t record_buf[4];
- reg_t = bits (arm_insn_r->arm_insn, 12, 15);
- reg_v = bits (arm_insn_r->arm_insn, 21, 23);
- bits_a = bits (arm_insn_r->arm_insn, 21, 23);
- bit_l = bit (arm_insn_r->arm_insn, 20);
- bit_c = bit (arm_insn_r->arm_insn, 8);
- /* Handle VMOV instruction. */
- if (bit_l && bit_c)
- {
- record_buf[0] = reg_t;
- arm_insn_r->reg_rec_count = 1;
- }
- else if (bit_l && !bit_c)
- {
- /* Handle VMOV instruction. */
- if (bits_a == 0x00)
- {
- record_buf[0] = reg_t;
- arm_insn_r->reg_rec_count = 1;
- }
- /* Handle VMRS instruction. */
- else if (bits_a == 0x07)
- {
- if (reg_t == 15)
- reg_t = ARM_PS_REGNUM;
- record_buf[0] = reg_t;
- arm_insn_r->reg_rec_count = 1;
- }
- }
- else if (!bit_l && !bit_c)
- {
- /* Handle VMOV instruction. */
- if (bits_a == 0x00)
- {
- record_buf[0] = ARM_D0_REGNUM + reg_v;
- arm_insn_r->reg_rec_count = 1;
- }
- /* Handle VMSR instruction. */
- else if (bits_a == 0x07)
- {
- record_buf[0] = ARM_FPSCR_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- }
- }
- else if (!bit_l && bit_c)
- {
- /* Handle VMOV instruction. */
- if (!(bits_a & 0x04))
- {
- record_buf[0] = (reg_v | (bit (arm_insn_r->arm_insn, 7) << 4))
- + ARM_D0_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- }
- /* Handle VDUP instruction. */
- else
- {
- if (bit (arm_insn_r->arm_insn, 21))
- {
- reg_v = reg_v | (bit (arm_insn_r->arm_insn, 7) << 4);
- record_buf[0] = reg_v + ARM_D0_REGNUM;
- record_buf[1] = reg_v + ARM_D0_REGNUM + 1;
- arm_insn_r->reg_rec_count = 2;
- }
- else
- {
- reg_v = reg_v | (bit (arm_insn_r->arm_insn, 7) << 4);
- record_buf[0] = reg_v + ARM_D0_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- }
- }
- }
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
- return 0;
- }
- /* Record handler for extension register load/store instructions. */
- static int
- arm_record_exreg_ld_st_insn (insn_decode_record *arm_insn_r)
- {
- uint32_t opcode, single_reg;
- uint8_t op_vldm_vstm;
- uint32_t record_buf[8], record_buf_mem[128];
- ULONGEST u_regval = 0;
- struct regcache *reg_cache = arm_insn_r->regcache;
- opcode = bits (arm_insn_r->arm_insn, 20, 24);
- single_reg = !bit (arm_insn_r->arm_insn, 8);
- op_vldm_vstm = opcode & 0x1b;
- /* Handle VMOV instructions. */
- if ((opcode & 0x1e) == 0x04)
- {
- if (bit (arm_insn_r->arm_insn, 20)) /* to_arm_registers bit 20? */
- {
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[1] = bits (arm_insn_r->arm_insn, 16, 19);
- arm_insn_r->reg_rec_count = 2;
- }
- else
- {
- uint8_t reg_m = bits (arm_insn_r->arm_insn, 0, 3);
- uint8_t bit_m = bit (arm_insn_r->arm_insn, 5);
- if (single_reg)
- {
- /* The first S register number m is REG_M:M (M is bit 5),
- the corresponding D register number is REG_M:M / 2, which
- is REG_M. */
- record_buf[arm_insn_r->reg_rec_count++] = ARM_D0_REGNUM + reg_m;
- /* The second S register number is REG_M:M + 1, the
- corresponding D register number is (REG_M:M + 1) / 2.
- IOW, if bit M is 1, the first and second S registers
- are mapped to different D registers, otherwise, they are
- in the same D register. */
- if (bit_m)
- {
- record_buf[arm_insn_r->reg_rec_count++]
- = ARM_D0_REGNUM + reg_m + 1;
- }
- }
- else
- {
- record_buf[0] = ((bit_m << 4) + reg_m + ARM_D0_REGNUM);
- arm_insn_r->reg_rec_count = 1;
- }
- }
- }
- /* Handle VSTM and VPUSH instructions. */
- else if (op_vldm_vstm == 0x08 || op_vldm_vstm == 0x0a
- || op_vldm_vstm == 0x12)
- {
- uint32_t start_address, reg_rn, imm_off32, imm_off8, memory_count;
- uint32_t memory_index = 0;
- reg_rn = bits (arm_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
- imm_off8 = bits (arm_insn_r->arm_insn, 0, 7);
- imm_off32 = imm_off8 << 2;
- memory_count = imm_off8;
- if (bit (arm_insn_r->arm_insn, 23))
- start_address = u_regval;
- else
- start_address = u_regval - imm_off32;
- if (bit (arm_insn_r->arm_insn, 21))
- {
- record_buf[0] = reg_rn;
- arm_insn_r->reg_rec_count = 1;
- }
- while (memory_count > 0)
- {
- if (single_reg)
- {
- record_buf_mem[memory_index] = 4;
- record_buf_mem[memory_index + 1] = start_address;
- start_address = start_address + 4;
- memory_index = memory_index + 2;
- }
- else
- {
- record_buf_mem[memory_index] = 4;
- record_buf_mem[memory_index + 1] = start_address;
- record_buf_mem[memory_index + 2] = 4;
- record_buf_mem[memory_index + 3] = start_address + 4;
- start_address = start_address + 8;
- memory_index = memory_index + 4;
- }
- memory_count--;
- }
- arm_insn_r->mem_rec_count = (memory_index >> 1);
- }
- /* Handle VLDM instructions. */
- else if (op_vldm_vstm == 0x09 || op_vldm_vstm == 0x0b
- || op_vldm_vstm == 0x13)
- {
- uint32_t reg_count, reg_vd;
- uint32_t reg_index = 0;
- uint32_t bit_d = bit (arm_insn_r->arm_insn, 22);
- reg_vd = bits (arm_insn_r->arm_insn, 12, 15);
- reg_count = bits (arm_insn_r->arm_insn, 0, 7);
- /* REG_VD is the first D register number. If the instruction
- loads memory to S registers (SINGLE_REG is TRUE), the register
- number is (REG_VD << 1 | bit D), so the corresponding D
- register number is (REG_VD << 1 | bit D) / 2 = REG_VD. */
- if (!single_reg)
- reg_vd = reg_vd | (bit_d << 4);
- if (bit (arm_insn_r->arm_insn, 21) /* write back */)
- record_buf[reg_index++] = bits (arm_insn_r->arm_insn, 16, 19);
- /* If the instruction loads memory to D register, REG_COUNT should
- be divided by 2, according to the ARM Architecture Reference
- Manual. If the instruction loads memory to S register, divide by
- 2 as well because two S registers are mapped to D register. */
- reg_count = reg_count / 2;
- if (single_reg && bit_d)
- {
- /* Increase the register count if S register list starts from
- an odd number (bit d is one). */
- reg_count++;
- }
- while (reg_count > 0)
- {
- record_buf[reg_index++] = ARM_D0_REGNUM + reg_vd + reg_count - 1;
- reg_count--;
- }
- arm_insn_r->reg_rec_count = reg_index;
- }
- /* VSTR Vector store register. */
- else if ((opcode & 0x13) == 0x10)
- {
- uint32_t start_address, reg_rn, imm_off32, imm_off8;
- uint32_t memory_index = 0;
- reg_rn = bits (arm_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
- imm_off8 = bits (arm_insn_r->arm_insn, 0, 7);
- imm_off32 = imm_off8 << 2;
- if (bit (arm_insn_r->arm_insn, 23))
- start_address = u_regval + imm_off32;
- else
- start_address = u_regval - imm_off32;
- if (single_reg)
- {
- record_buf_mem[memory_index] = 4;
- record_buf_mem[memory_index + 1] = start_address;
- arm_insn_r->mem_rec_count = 1;
- }
- else
- {
- record_buf_mem[memory_index] = 4;
- record_buf_mem[memory_index + 1] = start_address;
- record_buf_mem[memory_index + 2] = 4;
- record_buf_mem[memory_index + 3] = start_address + 4;
- arm_insn_r->mem_rec_count = 2;
- }
- }
- /* VLDR Vector load register. */
- else if ((opcode & 0x13) == 0x11)
- {
- uint32_t reg_vd = bits (arm_insn_r->arm_insn, 12, 15);
- if (!single_reg)
- {
- reg_vd = reg_vd | (bit (arm_insn_r->arm_insn, 22) << 4);
- record_buf[0] = ARM_D0_REGNUM + reg_vd;
- }
- else
- {
- reg_vd = (reg_vd << 1) | bit (arm_insn_r->arm_insn, 22);
- /* Record register D rather than pseudo register S. */
- record_buf[0] = ARM_D0_REGNUM + reg_vd / 2;
- }
- arm_insn_r->reg_rec_count = 1;
- }
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (arm_insn_r->arm_mems, arm_insn_r->mem_rec_count, record_buf_mem);
- return 0;
- }
- /* Record handler for arm/thumb mode VFP data processing instructions. */
- static int
- arm_record_vfp_data_proc_insn (insn_decode_record *arm_insn_r)
- {
- uint32_t opc1, opc2, opc3, dp_op_sz, bit_d, reg_vd;
- uint32_t record_buf[4];
- enum insn_types {INSN_T0, INSN_T1, INSN_T2, INSN_T3, INSN_INV};
- enum insn_types curr_insn_type = INSN_INV;
- reg_vd = bits (arm_insn_r->arm_insn, 12, 15);
- opc1 = bits (arm_insn_r->arm_insn, 20, 23);
- opc2 = bits (arm_insn_r->arm_insn, 16, 19);
- opc3 = bits (arm_insn_r->arm_insn, 6, 7);
- dp_op_sz = bit (arm_insn_r->arm_insn, 8);
- bit_d = bit (arm_insn_r->arm_insn, 22);
- /* Mask off the "D" bit. */
- opc1 = opc1 & ~0x04;
- /* Handle VMLA, VMLS. */
- if (opc1 == 0x00)
- {
- if (bit (arm_insn_r->arm_insn, 10))
- {
- if (bit (arm_insn_r->arm_insn, 6))
- curr_insn_type = INSN_T0;
- else
- curr_insn_type = INSN_T1;
- }
- else
- {
- if (dp_op_sz)
- curr_insn_type = INSN_T1;
- else
- curr_insn_type = INSN_T2;
- }
- }
- /* Handle VNMLA, VNMLS, VNMUL. */
- else if (opc1 == 0x01)
- {
- if (dp_op_sz)
- curr_insn_type = INSN_T1;
- else
- curr_insn_type = INSN_T2;
- }
- /* Handle VMUL. */
- else if (opc1 == 0x02 && !(opc3 & 0x01))
- {
- if (bit (arm_insn_r->arm_insn, 10))
- {
- if (bit (arm_insn_r->arm_insn, 6))
- curr_insn_type = INSN_T0;
- else
- curr_insn_type = INSN_T1;
- }
- else
- {
- if (dp_op_sz)
- curr_insn_type = INSN_T1;
- else
- curr_insn_type = INSN_T2;
- }
- }
- /* Handle VADD, VSUB. */
- else if (opc1 == 0x03)
- {
- if (!bit (arm_insn_r->arm_insn, 9))
- {
- if (bit (arm_insn_r->arm_insn, 6))
- curr_insn_type = INSN_T0;
- else
- curr_insn_type = INSN_T1;
- }
- else
- {
- if (dp_op_sz)
- curr_insn_type = INSN_T1;
- else
- curr_insn_type = INSN_T2;
- }
- }
- /* Handle VDIV. */
- else if (opc1 == 0x08)
- {
- if (dp_op_sz)
- curr_insn_type = INSN_T1;
- else
- curr_insn_type = INSN_T2;
- }
- /* Handle all other vfp data processing instructions. */
- else if (opc1 == 0x0b)
- {
- /* Handle VMOV. */
- if (!(opc3 & 0x01) || (opc2 == 0x00 && opc3 == 0x01))
- {
- if (bit (arm_insn_r->arm_insn, 4))
- {
- if (bit (arm_insn_r->arm_insn, 6))
- curr_insn_type = INSN_T0;
- else
- curr_insn_type = INSN_T1;
- }
- else
- {
- if (dp_op_sz)
- curr_insn_type = INSN_T1;
- else
- curr_insn_type = INSN_T2;
- }
- }
- /* Handle VNEG and VABS. */
- else if ((opc2 == 0x01 && opc3 == 0x01)
- || (opc2 == 0x00 && opc3 == 0x03))
- {
- if (!bit (arm_insn_r->arm_insn, 11))
- {
- if (bit (arm_insn_r->arm_insn, 6))
- curr_insn_type = INSN_T0;
- else
- curr_insn_type = INSN_T1;
- }
- else
- {
- if (dp_op_sz)
- curr_insn_type = INSN_T1;
- else
- curr_insn_type = INSN_T2;
- }
- }
- /* Handle VSQRT. */
- else if (opc2 == 0x01 && opc3 == 0x03)
- {
- if (dp_op_sz)
- curr_insn_type = INSN_T1;
- else
- curr_insn_type = INSN_T2;
- }
- /* Handle VCVT. */
- else if (opc2 == 0x07 && opc3 == 0x03)
- {
- if (!dp_op_sz)
- curr_insn_type = INSN_T1;
- else
- curr_insn_type = INSN_T2;
- }
- else if (opc3 & 0x01)
- {
- /* Handle VCVT. */
- if ((opc2 == 0x08) || (opc2 & 0x0e) == 0x0c)
- {
- if (!bit (arm_insn_r->arm_insn, 18))
- curr_insn_type = INSN_T2;
- else
- {
- if (dp_op_sz)
- curr_insn_type = INSN_T1;
- else
- curr_insn_type = INSN_T2;
- }
- }
- /* Handle VCVT. */
- else if ((opc2 & 0x0e) == 0x0a || (opc2 & 0x0e) == 0x0e)
- {
- if (dp_op_sz)
- curr_insn_type = INSN_T1;
- else
- curr_insn_type = INSN_T2;
- }
- /* Handle VCVTB, VCVTT. */
- else if ((opc2 & 0x0e) == 0x02)
- curr_insn_type = INSN_T2;
- /* Handle VCMP, VCMPE. */
- else if ((opc2 & 0x0e) == 0x04)
- curr_insn_type = INSN_T3;
- }
- }
- switch (curr_insn_type)
- {
- case INSN_T0:
- reg_vd = reg_vd | (bit_d << 4);
- record_buf[0] = reg_vd + ARM_D0_REGNUM;
- record_buf[1] = reg_vd + ARM_D0_REGNUM + 1;
- arm_insn_r->reg_rec_count = 2;
- break;
- case INSN_T1:
- reg_vd = reg_vd | (bit_d << 4);
- record_buf[0] = reg_vd + ARM_D0_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- break;
- case INSN_T2:
- reg_vd = (reg_vd << 1) | bit_d;
- record_buf[0] = reg_vd + ARM_D0_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- break;
- case INSN_T3:
- record_buf[0] = ARM_FPSCR_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- break;
- default:
- gdb_assert_not_reached ("no decoding pattern found");
- break;
- }
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
- return 0;
- }
- /* Handling opcode 110 insns. */
- static int
- arm_record_asimd_vfp_coproc (insn_decode_record *arm_insn_r)
- {
- uint32_t op1, op1_ebit, coproc;
- coproc = bits (arm_insn_r->arm_insn, 8, 11);
- op1 = bits (arm_insn_r->arm_insn, 20, 25);
- op1_ebit = bit (arm_insn_r->arm_insn, 20);
- if ((coproc & 0x0e) == 0x0a)
- {
- /* Handle extension register ld/st instructions. */
- if (!(op1 & 0x20))
- return arm_record_exreg_ld_st_insn (arm_insn_r);
- /* 64-bit transfers between arm core and extension registers. */
- if ((op1 & 0x3e) == 0x04)
- return arm_record_exreg_ld_st_insn (arm_insn_r);
- }
- else
- {
- /* Handle coprocessor ld/st instructions. */
- if (!(op1 & 0x3a))
- {
- /* Store. */
- if (!op1_ebit)
- return arm_record_unsupported_insn (arm_insn_r);
- else
- /* Load. */
- return arm_record_unsupported_insn (arm_insn_r);
- }
- /* Move to coprocessor from two arm core registers. */
- if (op1 == 0x4)
- return arm_record_unsupported_insn (arm_insn_r);
- /* Move to two arm core registers from coprocessor. */
- if (op1 == 0x5)
- {
- uint32_t reg_t[2];
- reg_t[0] = bits (arm_insn_r->arm_insn, 12, 15);
- reg_t[1] = bits (arm_insn_r->arm_insn, 16, 19);
- arm_insn_r->reg_rec_count = 2;
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, reg_t);
- return 0;
- }
- }
- return arm_record_unsupported_insn (arm_insn_r);
- }
- /* Handling opcode 111 insns. */
- static int
- arm_record_coproc_data_proc (insn_decode_record *arm_insn_r)
- {
- uint32_t op, op1_ebit, coproc, bits_24_25;
- arm_gdbarch_tdep *tdep
- = (arm_gdbarch_tdep *) gdbarch_tdep (arm_insn_r->gdbarch);
- struct regcache *reg_cache = arm_insn_r->regcache;
- arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 24, 27);
- coproc = bits (arm_insn_r->arm_insn, 8, 11);
- op1_ebit = bit (arm_insn_r->arm_insn, 20);
- op = bit (arm_insn_r->arm_insn, 4);
- bits_24_25 = bits (arm_insn_r->arm_insn, 24, 25);
- /* Handle arm SWI/SVC system call instructions. */
- if (bits_24_25 == 0x3)
- {
- if (tdep->arm_syscall_record != NULL)
- {
- ULONGEST svc_operand, svc_number;
- svc_operand = (0x00ffffff & arm_insn_r->arm_insn);
- if (svc_operand) /* OABI. */
- svc_number = svc_operand - 0x900000;
- else /* EABI. */
- regcache_raw_read_unsigned (reg_cache, 7, &svc_number);
- return tdep->arm_syscall_record (reg_cache, svc_number);
- }
- else
- {
- gdb_printf (gdb_stderr, _("no syscall record support\n"));
- return -1;
- }
- }
- else if (bits_24_25 == 0x02)
- {
- if (op)
- {
- if ((coproc & 0x0e) == 0x0a)
- {
- /* 8, 16, and 32-bit transfer */
- return arm_record_vdata_transfer_insn (arm_insn_r);
- }
- else
- {
- if (op1_ebit)
- {
- /* MRC, MRC2 */
- uint32_t record_buf[1];
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- if (record_buf[0] == 15)
- record_buf[0] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count,
- record_buf);
- return 0;
- }
- else
- {
- /* MCR, MCR2 */
- return -1;
- }
- }
- }
- else
- {
- if ((coproc & 0x0e) == 0x0a)
- {
- /* VFP data-processing instructions. */
- return arm_record_vfp_data_proc_insn (arm_insn_r);
- }
- else
- {
- /* CDP, CDP2 */
- return -1;
- }
- }
- }
- else
- {
- unsigned int op1 = bits (arm_insn_r->arm_insn, 20, 25);
- if (op1 == 5)
- {
- if ((coproc & 0x0e) != 0x0a)
- {
- /* MRRC, MRRC2 */
- return -1;
- }
- }
- else if (op1 == 4 || op1 == 5)
- {
- if ((coproc & 0x0e) == 0x0a)
- {
- /* 64-bit transfers between ARM core and extension */
- return -1;
- }
- else if (op1 == 4)
- {
- /* MCRR, MCRR2 */
- return -1;
- }
- }
- else if (op1 == 0 || op1 == 1)
- {
- /* UNDEFINED */
- return -1;
- }
- else
- {
- if ((coproc & 0x0e) == 0x0a)
- {
- /* Extension register load/store */
- }
- else
- {
- /* STC, STC2, LDC, LDC2 */
- }
- return -1;
- }
- }
- return -1;
- }
- /* Handling opcode 000 insns. */
- static int
- thumb_record_shift_add_sub (insn_decode_record *thumb_insn_r)
- {
- uint32_t record_buf[8];
- uint32_t reg_src1 = 0;
- reg_src1 = bits (thumb_insn_r->arm_insn, 0, 2);
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = reg_src1;
- thumb_insn_r->reg_rec_count = 2;
- REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
- return 0;
- }
- /* Handling opcode 001 insns. */
- static int
- thumb_record_add_sub_cmp_mov (insn_decode_record *thumb_insn_r)
- {
- uint32_t record_buf[8];
- uint32_t reg_src1 = 0;
- reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = reg_src1;
- thumb_insn_r->reg_rec_count = 2;
- REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
- return 0;
- }
- /* Handling opcode 010 insns. */
- static int
- thumb_record_ld_st_reg_offset (insn_decode_record *thumb_insn_r)
- {
- struct regcache *reg_cache = thumb_insn_r->regcache;
- uint32_t record_buf[8], record_buf_mem[8];
- uint32_t reg_src1 = 0, reg_src2 = 0;
- uint32_t opcode1 = 0, opcode2 = 0, opcode3 = 0;
- ULONGEST u_regval[2] = {0};
- opcode1 = bits (thumb_insn_r->arm_insn, 10, 12);
- if (bit (thumb_insn_r->arm_insn, 12))
- {
- /* Handle load/store register offset. */
- uint32_t opB = bits (thumb_insn_r->arm_insn, 9, 11);
- if (in_inclusive_range (opB, 4U, 7U))
- {
- /* LDR(2), LDRB(2) , LDRH(2), LDRSB, LDRSH. */
- reg_src1 = bits (thumb_insn_r->arm_insn,0, 2);
- record_buf[0] = reg_src1;
- thumb_insn_r->reg_rec_count = 1;
- }
- else if (in_inclusive_range (opB, 0U, 2U))
- {
- /* STR(2), STRB(2), STRH(2) . */
- reg_src1 = bits (thumb_insn_r->arm_insn, 3, 5);
- reg_src2 = bits (thumb_insn_r->arm_insn, 6, 8);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
- regcache_raw_read_unsigned (reg_cache, reg_src2, &u_regval[1]);
- if (0 == opB)
- record_buf_mem[0] = 4; /* STR (2). */
- else if (2 == opB)
- record_buf_mem[0] = 1; /* STRB (2). */
- else if (1 == opB)
- record_buf_mem[0] = 2; /* STRH (2). */
- record_buf_mem[1] = u_regval[0] + u_regval[1];
- thumb_insn_r->mem_rec_count = 1;
- }
- }
- else if (bit (thumb_insn_r->arm_insn, 11))
- {
- /* Handle load from literal pool. */
- /* LDR(3). */
- reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
- record_buf[0] = reg_src1;
- thumb_insn_r->reg_rec_count = 1;
- }
- else if (opcode1)
- {
- /* Special data instructions and branch and exchange */
- opcode2 = bits (thumb_insn_r->arm_insn, 8, 9);
- opcode3 = bits (thumb_insn_r->arm_insn, 0, 2);
- if ((3 == opcode2) && (!opcode3))
- {
- /* Branch with exchange. */
- record_buf[0] = ARM_PS_REGNUM;
- thumb_insn_r->reg_rec_count = 1;
- }
- else
- {
- /* Format 8; special data processing insns. */
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = (bit (thumb_insn_r->arm_insn, 7) << 3
- | bits (thumb_insn_r->arm_insn, 0, 2));
- thumb_insn_r->reg_rec_count = 2;
- }
- }
- else
- {
- /* Format 5; data processing insns. */
- reg_src1 = bits (thumb_insn_r->arm_insn, 0, 2);
- if (bit (thumb_insn_r->arm_insn, 7))
- {
- reg_src1 = reg_src1 + 8;
- }
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = reg_src1;
- thumb_insn_r->reg_rec_count = 2;
- }
- REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (thumb_insn_r->arm_mems, thumb_insn_r->mem_rec_count,
- record_buf_mem);
- return 0;
- }
- /* Handling opcode 001 insns. */
- static int
- thumb_record_ld_st_imm_offset (insn_decode_record *thumb_insn_r)
- {
- struct regcache *reg_cache = thumb_insn_r->regcache;
- uint32_t record_buf[8], record_buf_mem[8];
- uint32_t reg_src1 = 0;
- uint32_t opcode = 0, immed_5 = 0;
- ULONGEST u_regval = 0;
- opcode = bits (thumb_insn_r->arm_insn, 11, 12);
- if (opcode)
- {
- /* LDR(1). */
- reg_src1 = bits (thumb_insn_r->arm_insn, 0, 2);
- record_buf[0] = reg_src1;
- thumb_insn_r->reg_rec_count = 1;
- }
- else
- {
- /* STR(1). */
- reg_src1 = bits (thumb_insn_r->arm_insn, 3, 5);
- immed_5 = bits (thumb_insn_r->arm_insn, 6, 10);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval);
- record_buf_mem[0] = 4;
- record_buf_mem[1] = u_regval + (immed_5 * 4);
- thumb_insn_r->mem_rec_count = 1;
- }
- REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (thumb_insn_r->arm_mems, thumb_insn_r->mem_rec_count,
- record_buf_mem);
- return 0;
- }
- /* Handling opcode 100 insns. */
- static int
- thumb_record_ld_st_stack (insn_decode_record *thumb_insn_r)
- {
- struct regcache *reg_cache = thumb_insn_r->regcache;
- uint32_t record_buf[8], record_buf_mem[8];
- uint32_t reg_src1 = 0;
- uint32_t opcode = 0, immed_8 = 0, immed_5 = 0;
- ULONGEST u_regval = 0;
- opcode = bits (thumb_insn_r->arm_insn, 11, 12);
- if (3 == opcode)
- {
- /* LDR(4). */
- reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
- record_buf[0] = reg_src1;
- thumb_insn_r->reg_rec_count = 1;
- }
- else if (1 == opcode)
- {
- /* LDRH(1). */
- reg_src1 = bits (thumb_insn_r->arm_insn, 0, 2);
- record_buf[0] = reg_src1;
- thumb_insn_r->reg_rec_count = 1;
- }
- else if (2 == opcode)
- {
- /* STR(3). */
- immed_8 = bits (thumb_insn_r->arm_insn, 0, 7);
- regcache_raw_read_unsigned (reg_cache, ARM_SP_REGNUM, &u_regval);
- record_buf_mem[0] = 4;
- record_buf_mem[1] = u_regval + (immed_8 * 4);
- thumb_insn_r->mem_rec_count = 1;
- }
- else if (0 == opcode)
- {
- /* STRH(1). */
- immed_5 = bits (thumb_insn_r->arm_insn, 6, 10);
- reg_src1 = bits (thumb_insn_r->arm_insn, 3, 5);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval);
- record_buf_mem[0] = 2;
- record_buf_mem[1] = u_regval + (immed_5 * 2);
- thumb_insn_r->mem_rec_count = 1;
- }
- REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (thumb_insn_r->arm_mems, thumb_insn_r->mem_rec_count,
- record_buf_mem);
- return 0;
- }
- /* Handling opcode 101 insns. */
- static int
- thumb_record_misc (insn_decode_record *thumb_insn_r)
- {
- struct regcache *reg_cache = thumb_insn_r->regcache;
- uint32_t opcode = 0;
- uint32_t register_bits = 0, register_count = 0;
- uint32_t index = 0, start_address = 0;
- uint32_t record_buf[24], record_buf_mem[48];
- uint32_t reg_src1;
- ULONGEST u_regval = 0;
- opcode = bits (thumb_insn_r->arm_insn, 11, 12);
- if (opcode == 0 || opcode == 1)
- {
- /* ADR and ADD (SP plus immediate) */
- reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
- record_buf[0] = reg_src1;
- thumb_insn_r->reg_rec_count = 1;
- }
- else
- {
- /* Miscellaneous 16-bit instructions */
- uint32_t opcode2 = bits (thumb_insn_r->arm_insn, 8, 11);
- switch (opcode2)
- {
- case 6:
- /* SETEND and CPS */
- break;
- case 0:
- /* ADD/SUB (SP plus immediate) */
- reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
- record_buf[0] = ARM_SP_REGNUM;
- thumb_insn_r->reg_rec_count = 1;
- break;
- case 1: /* fall through */
- case 3: /* fall through */
- case 9: /* fall through */
- case 11:
- /* CBNZ, CBZ */
- break;
- case 2:
- /* SXTH, SXTB, UXTH, UXTB */
- record_buf[0] = bits (thumb_insn_r->arm_insn, 0, 2);
- thumb_insn_r->reg_rec_count = 1;
- break;
- case 4: /* fall through */
- case 5:
- /* PUSH. */
- register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
- regcache_raw_read_unsigned (reg_cache, ARM_SP_REGNUM, &u_regval);
- while (register_bits)
- {
- if (register_bits & 0x00000001)
- register_count++;
- register_bits = register_bits >> 1;
- }
- start_address = u_regval - \
- (4 * (bit (thumb_insn_r->arm_insn, 8) + register_count));
- thumb_insn_r->mem_rec_count = register_count;
- while (register_count)
- {
- record_buf_mem[(register_count * 2) - 1] = start_address;
- record_buf_mem[(register_count * 2) - 2] = 4;
- start_address = start_address + 4;
- register_count--;
- }
- record_buf[0] = ARM_SP_REGNUM;
- thumb_insn_r->reg_rec_count = 1;
- break;
- case 10:
- /* REV, REV16, REVSH */
- record_buf[0] = bits (thumb_insn_r->arm_insn, 0, 2);
- thumb_insn_r->reg_rec_count = 1;
- break;
- case 12: /* fall through */
- case 13:
- /* POP. */
- register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
- while (register_bits)
- {
- if (register_bits & 0x00000001)
- record_buf[index++] = register_count;
- register_bits = register_bits >> 1;
- register_count++;
- }
- record_buf[index++] = ARM_PS_REGNUM;
- record_buf[index++] = ARM_SP_REGNUM;
- thumb_insn_r->reg_rec_count = index;
- break;
- case 0xe:
- /* BKPT insn. */
- /* Handle enhanced software breakpoint insn, BKPT. */
- /* CPSR is changed to be executed in ARM state, disabling normal
- interrupts, entering abort mode. */
- /* According to high vector configuration PC is set. */
- /* User hits breakpoint and type reverse, in that case, we need to go back with
- previous CPSR and Program Counter. */
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = ARM_LR_REGNUM;
- thumb_insn_r->reg_rec_count = 2;
- /* We need to save SPSR value, which is not yet done. */
- gdb_printf (gdb_stderr,
- _("Process record does not support instruction "
- "0x%0x at address %s.\n"),
- thumb_insn_r->arm_insn,
- paddress (thumb_insn_r->gdbarch,
- thumb_insn_r->this_addr));
- return -1;
- case 0xf:
- /* If-Then, and hints */
- break;
- default:
- return -1;
- };
- }
- REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (thumb_insn_r->arm_mems, thumb_insn_r->mem_rec_count,
- record_buf_mem);
- return 0;
- }
- /* Handling opcode 110 insns. */
- static int
- thumb_record_ldm_stm_swi (insn_decode_record *thumb_insn_r)
- {
- arm_gdbarch_tdep *tdep
- = (arm_gdbarch_tdep *) gdbarch_tdep (thumb_insn_r->gdbarch);
- struct regcache *reg_cache = thumb_insn_r->regcache;
- uint32_t ret = 0; /* function return value: -1:record failure ; 0:success */
- uint32_t reg_src1 = 0;
- uint32_t opcode1 = 0, opcode2 = 0, register_bits = 0, register_count = 0;
- uint32_t index = 0, start_address = 0;
- uint32_t record_buf[24], record_buf_mem[48];
- ULONGEST u_regval = 0;
- opcode1 = bits (thumb_insn_r->arm_insn, 8, 12);
- opcode2 = bits (thumb_insn_r->arm_insn, 11, 12);
- if (1 == opcode2)
- {
- /* LDMIA. */
- register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
- /* Get Rn. */
- reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
- while (register_bits)
- {
- if (register_bits & 0x00000001)
- record_buf[index++] = register_count;
- register_bits = register_bits >> 1;
- register_count++;
- }
- record_buf[index++] = reg_src1;
- thumb_insn_r->reg_rec_count = index;
- }
- else if (0 == opcode2)
- {
- /* It handles both STMIA. */
- register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
- /* Get Rn. */
- reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval);
- while (register_bits)
- {
- if (register_bits & 0x00000001)
- register_count++;
- register_bits = register_bits >> 1;
- }
- start_address = u_regval;
- thumb_insn_r->mem_rec_count = register_count;
- while (register_count)
- {
- record_buf_mem[(register_count * 2) - 1] = start_address;
- record_buf_mem[(register_count * 2) - 2] = 4;
- start_address = start_address + 4;
- register_count--;
- }
- }
- else if (0x1F == opcode1)
- {
- /* Handle arm syscall insn. */
- if (tdep->arm_syscall_record != NULL)
- {
- regcache_raw_read_unsigned (reg_cache, 7, &u_regval);
- ret = tdep->arm_syscall_record (reg_cache, u_regval);
- }
- else
- {
- gdb_printf (gdb_stderr, _("no syscall record support\n"));
- return -1;
- }
- }
- /* B (1), conditional branch is automatically taken care in process_record,
- as PC is saved there. */
- REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
- MEM_ALLOC (thumb_insn_r->arm_mems, thumb_insn_r->mem_rec_count,
- record_buf_mem);
- return ret;
- }
- /* Handling opcode 111 insns. */
- static int
- thumb_record_branch (insn_decode_record *thumb_insn_r)
- {
- uint32_t record_buf[8];
- uint32_t bits_h = 0;
- bits_h = bits (thumb_insn_r->arm_insn, 11, 12);
- if (2 == bits_h || 3 == bits_h)
- {
- /* BL */
- record_buf[0] = ARM_LR_REGNUM;
- thumb_insn_r->reg_rec_count = 1;
- }
- else if (1 == bits_h)
- {
- /* BLX(1). */
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = ARM_LR_REGNUM;
- thumb_insn_r->reg_rec_count = 2;
- }
- /* B(2) is automatically taken care in process_record, as PC is
- saved there. */
- REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
- return 0;
- }
- /* Handler for thumb2 load/store multiple instructions. */
- static int
- thumb2_record_ld_st_multiple (insn_decode_record *thumb2_insn_r)
- {
- struct regcache *reg_cache = thumb2_insn_r->regcache;
- uint32_t reg_rn, op;
- uint32_t register_bits = 0, register_count = 0;
- uint32_t index = 0, start_address = 0;
- uint32_t record_buf[24], record_buf_mem[48];
- ULONGEST u_regval = 0;
- reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
- op = bits (thumb2_insn_r->arm_insn, 23, 24);
- if (0 == op || 3 == op)
- {
- if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
- {
- /* Handle RFE instruction. */
- record_buf[0] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = 1;
- }
- else
- {
- /* Handle SRS instruction after reading banked SP. */
- return arm_record_unsupported_insn (thumb2_insn_r);
- }
- }
- else if (1 == op || 2 == op)
- {
- if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
- {
- /* Handle LDM/LDMIA/LDMFD and LDMDB/LDMEA instructions. */
- register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
- while (register_bits)
- {
- if (register_bits & 0x00000001)
- record_buf[index++] = register_count;
- register_count++;
- register_bits = register_bits >> 1;
- }
- record_buf[index++] = reg_rn;
- record_buf[index++] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = index;
- }
- else
- {
- /* Handle STM/STMIA/STMEA and STMDB/STMFD. */
- register_bits = bits (thumb2_insn_r->arm_insn, 0, 15);
- regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
- while (register_bits)
- {
- if (register_bits & 0x00000001)
- register_count++;
- register_bits = register_bits >> 1;
- }
- if (1 == op)
- {
- /* Start address calculation for LDMDB/LDMEA. */
- start_address = u_regval;
- }
- else if (2 == op)
- {
- /* Start address calculation for LDMDB/LDMEA. */
- start_address = u_regval - register_count * 4;
- }
- thumb2_insn_r->mem_rec_count = register_count;
- while (register_count)
- {
- record_buf_mem[register_count * 2 - 1] = start_address;
- record_buf_mem[register_count * 2 - 2] = 4;
- start_address = start_address + 4;
- register_count--;
- }
- record_buf[0] = reg_rn;
- record_buf[1] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = 2;
- }
- }
- MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
- record_buf_mem);
- REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
- record_buf);
- return ARM_RECORD_SUCCESS;
- }
- /* Handler for thumb2 load/store (dual/exclusive) and table branch
- instructions. */
- static int
- thumb2_record_ld_st_dual_ex_tbb (insn_decode_record *thumb2_insn_r)
- {
- struct regcache *reg_cache = thumb2_insn_r->regcache;
- uint32_t reg_rd, reg_rn, offset_imm;
- uint32_t reg_dest1, reg_dest2;
- uint32_t address, offset_addr;
- uint32_t record_buf[8], record_buf_mem[8];
- uint32_t op1, op2, op3;
- ULONGEST u_regval[2];
- op1 = bits (thumb2_insn_r->arm_insn, 23, 24);
- op2 = bits (thumb2_insn_r->arm_insn, 20, 21);
- op3 = bits (thumb2_insn_r->arm_insn, 4, 7);
- if (bit (thumb2_insn_r->arm_insn, INSN_S_L_BIT_NUM))
- {
- if(!(1 == op1 && 1 == op2 && (0 == op3 || 1 == op3)))
- {
- reg_dest1 = bits (thumb2_insn_r->arm_insn, 12, 15);
- record_buf[0] = reg_dest1;
- record_buf[1] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = 2;
- }
- if (3 == op2 || (op1 & 2) || (1 == op1 && 1 == op2 && 7 == op3))
- {
- reg_dest2 = bits (thumb2_insn_r->arm_insn, 8, 11);
- record_buf[2] = reg_dest2;
- thumb2_insn_r->reg_rec_count = 3;
- }
- }
- else
- {
- reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
- if (0 == op1 && 0 == op2)
- {
- /* Handle STREX. */
- offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
- address = u_regval[0] + (offset_imm * 4);
- record_buf_mem[0] = 4;
- record_buf_mem[1] = address;
- thumb2_insn_r->mem_rec_count = 1;
- reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
- record_buf[0] = reg_rd;
- thumb2_insn_r->reg_rec_count = 1;
- }
- else if (1 == op1 && 0 == op2)
- {
- reg_rd = bits (thumb2_insn_r->arm_insn, 0, 3);
- record_buf[0] = reg_rd;
- thumb2_insn_r->reg_rec_count = 1;
- address = u_regval[0];
- record_buf_mem[1] = address;
- if (4 == op3)
- {
- /* Handle STREXB. */
- record_buf_mem[0] = 1;
- thumb2_insn_r->mem_rec_count = 1;
- }
- else if (5 == op3)
- {
- /* Handle STREXH. */
- record_buf_mem[0] = 2 ;
- thumb2_insn_r->mem_rec_count = 1;
- }
- else if (7 == op3)
- {
- /* Handle STREXD. */
- address = u_regval[0];
- record_buf_mem[0] = 4;
- record_buf_mem[2] = 4;
- record_buf_mem[3] = address + 4;
- thumb2_insn_r->mem_rec_count = 2;
- }
- }
- else
- {
- offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
- if (bit (thumb2_insn_r->arm_insn, 24))
- {
- if (bit (thumb2_insn_r->arm_insn, 23))
- offset_addr = u_regval[0] + (offset_imm * 4);
- else
- offset_addr = u_regval[0] - (offset_imm * 4);
- address = offset_addr;
- }
- else
- address = u_regval[0];
- record_buf_mem[0] = 4;
- record_buf_mem[1] = address;
- record_buf_mem[2] = 4;
- record_buf_mem[3] = address + 4;
- thumb2_insn_r->mem_rec_count = 2;
- record_buf[0] = reg_rn;
- thumb2_insn_r->reg_rec_count = 1;
- }
- }
- REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
- record_buf);
- MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
- record_buf_mem);
- return ARM_RECORD_SUCCESS;
- }
- /* Handler for thumb2 data processing (shift register and modified immediate)
- instructions. */
- static int
- thumb2_record_data_proc_sreg_mimm (insn_decode_record *thumb2_insn_r)
- {
- uint32_t reg_rd, op;
- uint32_t record_buf[8];
- op = bits (thumb2_insn_r->arm_insn, 21, 24);
- reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
- if ((0 == op || 4 == op || 8 == op || 13 == op) && 15 == reg_rd)
- {
- record_buf[0] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = 1;
- }
- else
- {
- record_buf[0] = reg_rd;
- record_buf[1] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = 2;
- }
- REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
- record_buf);
- return ARM_RECORD_SUCCESS;
- }
- /* Generic handler for thumb2 instructions which effect destination and PS
- registers. */
- static int
- thumb2_record_ps_dest_generic (insn_decode_record *thumb2_insn_r)
- {
- uint32_t reg_rd;
- uint32_t record_buf[8];
- reg_rd = bits (thumb2_insn_r->arm_insn, 8, 11);
- record_buf[0] = reg_rd;
- record_buf[1] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = 2;
- REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
- record_buf);
- return ARM_RECORD_SUCCESS;
- }
- /* Handler for thumb2 branch and miscellaneous control instructions. */
- static int
- thumb2_record_branch_misc_cntrl (insn_decode_record *thumb2_insn_r)
- {
- uint32_t op, op1, op2;
- uint32_t record_buf[8];
- op = bits (thumb2_insn_r->arm_insn, 20, 26);
- op1 = bits (thumb2_insn_r->arm_insn, 12, 14);
- op2 = bits (thumb2_insn_r->arm_insn, 8, 11);
- /* Handle MSR insn. */
- if (!(op1 & 0x2) && 0x38 == op)
- {
- if (!(op2 & 0x3))
- {
- /* CPSR is going to be changed. */
- record_buf[0] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = 1;
- }
- else
- {
- arm_record_unsupported_insn(thumb2_insn_r);
- return -1;
- }
- }
- else if (4 == (op1 & 0x5) || 5 == (op1 & 0x5))
- {
- /* BLX. */
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = ARM_LR_REGNUM;
- thumb2_insn_r->reg_rec_count = 2;
- }
- REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
- record_buf);
- return ARM_RECORD_SUCCESS;
- }
- /* Handler for thumb2 store single data item instructions. */
- static int
- thumb2_record_str_single_data (insn_decode_record *thumb2_insn_r)
- {
- struct regcache *reg_cache = thumb2_insn_r->regcache;
- uint32_t reg_rn, reg_rm, offset_imm, shift_imm;
- uint32_t address, offset_addr;
- uint32_t record_buf[8], record_buf_mem[8];
- uint32_t op1, op2;
- ULONGEST u_regval[2];
- op1 = bits (thumb2_insn_r->arm_insn, 21, 23);
- op2 = bits (thumb2_insn_r->arm_insn, 6, 11);
- reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval[0]);
- if (bit (thumb2_insn_r->arm_insn, 23))
- {
- /* T2 encoding. */
- offset_imm = bits (thumb2_insn_r->arm_insn, 0, 11);
- offset_addr = u_regval[0] + offset_imm;
- address = offset_addr;
- }
- else
- {
- /* T3 encoding. */
- if ((0 == op1 || 1 == op1 || 2 == op1) && !(op2 & 0x20))
- {
- /* Handle STRB (register). */
- reg_rm = bits (thumb2_insn_r->arm_insn, 0, 3);
- regcache_raw_read_unsigned (reg_cache, reg_rm, &u_regval[1]);
- shift_imm = bits (thumb2_insn_r->arm_insn, 4, 5);
- offset_addr = u_regval[1] << shift_imm;
- address = u_regval[0] + offset_addr;
- }
- else
- {
- offset_imm = bits (thumb2_insn_r->arm_insn, 0, 7);
- if (bit (thumb2_insn_r->arm_insn, 10))
- {
- if (bit (thumb2_insn_r->arm_insn, 9))
- offset_addr = u_regval[0] + offset_imm;
- else
- offset_addr = u_regval[0] - offset_imm;
- address = offset_addr;
- }
- else
- address = u_regval[0];
- }
- }
- switch (op1)
- {
- /* Store byte instructions. */
- case 4:
- case 0:
- record_buf_mem[0] = 1;
- break;
- /* Store half word instructions. */
- case 1:
- case 5:
- record_buf_mem[0] = 2;
- break;
- /* Store word instructions. */
- case 2:
- case 6:
- record_buf_mem[0] = 4;
- break;
- default:
- gdb_assert_not_reached ("no decoding pattern found");
- break;
- }
- record_buf_mem[1] = address;
- thumb2_insn_r->mem_rec_count = 1;
- record_buf[0] = reg_rn;
- thumb2_insn_r->reg_rec_count = 1;
- REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
- record_buf);
- MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
- record_buf_mem);
- return ARM_RECORD_SUCCESS;
- }
- /* Handler for thumb2 load memory hints instructions. */
- static int
- thumb2_record_ld_mem_hints (insn_decode_record *thumb2_insn_r)
- {
- uint32_t record_buf[8];
- uint32_t reg_rt, reg_rn;
- reg_rt = bits (thumb2_insn_r->arm_insn, 12, 15);
- reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
- if (ARM_PC_REGNUM != reg_rt)
- {
- record_buf[0] = reg_rt;
- record_buf[1] = reg_rn;
- record_buf[2] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = 3;
- REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
- record_buf);
- return ARM_RECORD_SUCCESS;
- }
- return ARM_RECORD_FAILURE;
- }
- /* Handler for thumb2 load word instructions. */
- static int
- thumb2_record_ld_word (insn_decode_record *thumb2_insn_r)
- {
- uint32_t record_buf[8];
- record_buf[0] = bits (thumb2_insn_r->arm_insn, 12, 15);
- record_buf[1] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = 2;
- REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
- record_buf);
- return ARM_RECORD_SUCCESS;
- }
- /* Handler for thumb2 long multiply, long multiply accumulate, and
- divide instructions. */
- static int
- thumb2_record_lmul_lmla_div (insn_decode_record *thumb2_insn_r)
- {
- uint32_t opcode1 = 0, opcode2 = 0;
- uint32_t record_buf[8];
- opcode1 = bits (thumb2_insn_r->arm_insn, 20, 22);
- opcode2 = bits (thumb2_insn_r->arm_insn, 4, 7);
- if (0 == opcode1 || 2 == opcode1 || (opcode1 >= 4 && opcode1 <= 6))
- {
- /* Handle SMULL, UMULL, SMULAL. */
- /* Handle SMLAL(S), SMULL(S), UMLAL(S), UMULL(S). */
- record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
- record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
- record_buf[2] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = 3;
- }
- else if (1 == opcode1 || 3 == opcode2)
- {
- /* Handle SDIV and UDIV. */
- record_buf[0] = bits (thumb2_insn_r->arm_insn, 16, 19);
- record_buf[1] = bits (thumb2_insn_r->arm_insn, 12, 15);
- record_buf[2] = ARM_PS_REGNUM;
- thumb2_insn_r->reg_rec_count = 3;
- }
- else
- return ARM_RECORD_FAILURE;
- REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
- record_buf);
- return ARM_RECORD_SUCCESS;
- }
- /* Record handler for thumb32 coprocessor instructions. */
- static int
- thumb2_record_coproc_insn (insn_decode_record *thumb2_insn_r)
- {
- if (bit (thumb2_insn_r->arm_insn, 25))
- return arm_record_coproc_data_proc (thumb2_insn_r);
- else
- return arm_record_asimd_vfp_coproc (thumb2_insn_r);
- }
- /* Record handler for advance SIMD structure load/store instructions. */
- static int
- thumb2_record_asimd_struct_ld_st (insn_decode_record *thumb2_insn_r)
- {
- struct regcache *reg_cache = thumb2_insn_r->regcache;
- uint32_t l_bit, a_bit, b_bits;
- uint32_t record_buf[128], record_buf_mem[128];
- uint32_t reg_rn, reg_vd, address, f_elem;
- uint32_t index_r = 0, index_e = 0, bf_regs = 0, index_m = 0, loop_t = 0;
- uint8_t f_ebytes;
- l_bit = bit (thumb2_insn_r->arm_insn, 21);
- a_bit = bit (thumb2_insn_r->arm_insn, 23);
- b_bits = bits (thumb2_insn_r->arm_insn, 8, 11);
- reg_rn = bits (thumb2_insn_r->arm_insn, 16, 19);
- reg_vd = bits (thumb2_insn_r->arm_insn, 12, 15);
- reg_vd = (bit (thumb2_insn_r->arm_insn, 22) << 4) | reg_vd;
- f_ebytes = (1 << bits (thumb2_insn_r->arm_insn, 6, 7));
- f_elem = 8 / f_ebytes;
- if (!l_bit)
- {
- ULONGEST u_regval = 0;
- regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
- address = u_regval;
- if (!a_bit)
- {
- /* Handle VST1. */
- if (b_bits == 0x02 || b_bits == 0x0a || (b_bits & 0x0e) == 0x06)
- {
- if (b_bits == 0x07)
- bf_regs = 1;
- else if (b_bits == 0x0a)
- bf_regs = 2;
- else if (b_bits == 0x06)
- bf_regs = 3;
- else if (b_bits == 0x02)
- bf_regs = 4;
- else
- bf_regs = 0;
- for (index_r = 0; index_r < bf_regs; index_r++)
- {
- for (index_e = 0; index_e < f_elem; index_e++)
- {
- record_buf_mem[index_m++] = f_ebytes;
- record_buf_mem[index_m++] = address;
- address = address + f_ebytes;
- thumb2_insn_r->mem_rec_count += 1;
- }
- }
- }
- /* Handle VST2. */
- else if (b_bits == 0x03 || (b_bits & 0x0e) == 0x08)
- {
- if (b_bits == 0x09 || b_bits == 0x08)
- bf_regs = 1;
- else if (b_bits == 0x03)
- bf_regs = 2;
- else
- bf_regs = 0;
- for (index_r = 0; index_r < bf_regs; index_r++)
- for (index_e = 0; index_e < f_elem; index_e++)
- {
- for (loop_t = 0; loop_t < 2; loop_t++)
- {
- record_buf_mem[index_m++] = f_ebytes;
- record_buf_mem[index_m++] = address + (loop_t * f_ebytes);
- thumb2_insn_r->mem_rec_count += 1;
- }
- address = address + (2 * f_ebytes);
- }
- }
- /* Handle VST3. */
- else if ((b_bits & 0x0e) == 0x04)
- {
- for (index_e = 0; index_e < f_elem; index_e++)
- {
- for (loop_t = 0; loop_t < 3; loop_t++)
- {
- record_buf_mem[index_m++] = f_ebytes;
- record_buf_mem[index_m++] = address + (loop_t * f_ebytes);
- thumb2_insn_r->mem_rec_count += 1;
- }
- address = address + (3 * f_ebytes);
- }
- }
- /* Handle VST4. */
- else if (!(b_bits & 0x0e))
- {
- for (index_e = 0; index_e < f_elem; index_e++)
- {
- for (loop_t = 0; loop_t < 4; loop_t++)
- {
- record_buf_mem[index_m++] = f_ebytes;
- record_buf_mem[index_m++] = address + (loop_t * f_ebytes);
- thumb2_insn_r->mem_rec_count += 1;
- }
- address = address + (4 * f_ebytes);
- }
- }
- }
- else
- {
- uint8_t bft_size = bits (thumb2_insn_r->arm_insn, 10, 11);
- if (bft_size == 0x00)
- f_ebytes = 1;
- else if (bft_size == 0x01)
- f_ebytes = 2;
- else if (bft_size == 0x02)
- f_ebytes = 4;
- else
- f_ebytes = 0;
- /* Handle VST1. */
- if (!(b_bits & 0x0b) || b_bits == 0x08)
- thumb2_insn_r->mem_rec_count = 1;
- /* Handle VST2. */
- else if ((b_bits & 0x0b) == 0x01 || b_bits == 0x09)
- thumb2_insn_r->mem_rec_count = 2;
- /* Handle VST3. */
- else if ((b_bits & 0x0b) == 0x02 || b_bits == 0x0a)
- thumb2_insn_r->mem_rec_count = 3;
- /* Handle VST4. */
- else if ((b_bits & 0x0b) == 0x03 || b_bits == 0x0b)
- thumb2_insn_r->mem_rec_count = 4;
- for (index_m = 0; index_m < thumb2_insn_r->mem_rec_count; index_m++)
- {
- record_buf_mem[index_m] = f_ebytes;
- record_buf_mem[index_m] = address + (index_m * f_ebytes);
- }
- }
- }
- else
- {
- if (!a_bit)
- {
- /* Handle VLD1. */
- if (b_bits == 0x02 || b_bits == 0x0a || (b_bits & 0x0e) == 0x06)
- thumb2_insn_r->reg_rec_count = 1;
- /* Handle VLD2. */
- else if (b_bits == 0x03 || (b_bits & 0x0e) == 0x08)
- thumb2_insn_r->reg_rec_count = 2;
- /* Handle VLD3. */
- else if ((b_bits & 0x0e) == 0x04)
- thumb2_insn_r->reg_rec_count = 3;
- /* Handle VLD4. */
- else if (!(b_bits & 0x0e))
- thumb2_insn_r->reg_rec_count = 4;
- }
- else
- {
- /* Handle VLD1. */
- if (!(b_bits & 0x0b) || b_bits == 0x08 || b_bits == 0x0c)
- thumb2_insn_r->reg_rec_count = 1;
- /* Handle VLD2. */
- else if ((b_bits & 0x0b) == 0x01 || b_bits == 0x09 || b_bits == 0x0d)
- thumb2_insn_r->reg_rec_count = 2;
- /* Handle VLD3. */
- else if ((b_bits & 0x0b) == 0x02 || b_bits == 0x0a || b_bits == 0x0e)
- thumb2_insn_r->reg_rec_count = 3;
- /* Handle VLD4. */
- else if ((b_bits & 0x0b) == 0x03 || b_bits == 0x0b || b_bits == 0x0f)
- thumb2_insn_r->reg_rec_count = 4;
- for (index_r = 0; index_r < thumb2_insn_r->reg_rec_count; index_r++)
- record_buf[index_r] = reg_vd + ARM_D0_REGNUM + index_r;
- }
- }
- if (bits (thumb2_insn_r->arm_insn, 0, 3) != 15)
- {
- record_buf[index_r] = reg_rn;
- thumb2_insn_r->reg_rec_count += 1;
- }
- REG_ALLOC (thumb2_insn_r->arm_regs, thumb2_insn_r->reg_rec_count,
- record_buf);
- MEM_ALLOC (thumb2_insn_r->arm_mems, thumb2_insn_r->mem_rec_count,
- record_buf_mem);
- return 0;
- }
- /* Decodes thumb2 instruction type and invokes its record handler. */
- static unsigned int
- thumb2_record_decode_insn_handler (insn_decode_record *thumb2_insn_r)
- {
- uint32_t op, op1, op2;
- op = bit (thumb2_insn_r->arm_insn, 15);
- op1 = bits (thumb2_insn_r->arm_insn, 27, 28);
- op2 = bits (thumb2_insn_r->arm_insn, 20, 26);
- if (op1 == 0x01)
- {
- if (!(op2 & 0x64 ))
- {
- /* Load/store multiple instruction. */
- return thumb2_record_ld_st_multiple (thumb2_insn_r);
- }
- else if ((op2 & 0x64) == 0x4)
- {
- /* Load/store (dual/exclusive) and table branch instruction. */
- return thumb2_record_ld_st_dual_ex_tbb (thumb2_insn_r);
- }
- else if ((op2 & 0x60) == 0x20)
- {
- /* Data-processing (shifted register). */
- return thumb2_record_data_proc_sreg_mimm (thumb2_insn_r);
- }
- else if (op2 & 0x40)
- {
- /* Co-processor instructions. */
- return thumb2_record_coproc_insn (thumb2_insn_r);
- }
- }
- else if (op1 == 0x02)
- {
- if (op)
- {
- /* Branches and miscellaneous control instructions. */
- return thumb2_record_branch_misc_cntrl (thumb2_insn_r);
- }
- else if (op2 & 0x20)
- {
- /* Data-processing (plain binary immediate) instruction. */
- return thumb2_record_ps_dest_generic (thumb2_insn_r);
- }
- else
- {
- /* Data-processing (modified immediate). */
- return thumb2_record_data_proc_sreg_mimm (thumb2_insn_r);
- }
- }
- else if (op1 == 0x03)
- {
- if (!(op2 & 0x71 ))
- {
- /* Store single data item. */
- return thumb2_record_str_single_data (thumb2_insn_r);
- }
- else if (!((op2 & 0x71) ^ 0x10))
- {
- /* Advanced SIMD or structure load/store instructions. */
- return thumb2_record_asimd_struct_ld_st (thumb2_insn_r);
- }
- else if (!((op2 & 0x67) ^ 0x01))
- {
- /* Load byte, memory hints instruction. */
- return thumb2_record_ld_mem_hints (thumb2_insn_r);
- }
- else if (!((op2 & 0x67) ^ 0x03))
- {
- /* Load halfword, memory hints instruction. */
- return thumb2_record_ld_mem_hints (thumb2_insn_r);
- }
- else if (!((op2 & 0x67) ^ 0x05))
- {
- /* Load word instruction. */
- return thumb2_record_ld_word (thumb2_insn_r);
- }
- else if (!((op2 & 0x70) ^ 0x20))
- {
- /* Data-processing (register) instruction. */
- return thumb2_record_ps_dest_generic (thumb2_insn_r);
- }
- else if (!((op2 & 0x78) ^ 0x30))
- {
- /* Multiply, multiply accumulate, abs diff instruction. */
- return thumb2_record_ps_dest_generic (thumb2_insn_r);
- }
- else if (!((op2 & 0x78) ^ 0x38))
- {
- /* Long multiply, long multiply accumulate, and divide. */
- return thumb2_record_lmul_lmla_div (thumb2_insn_r);
- }
- else if (op2 & 0x40)
- {
- /* Co-processor instructions. */
- return thumb2_record_coproc_insn (thumb2_insn_r);
- }
- }
- return -1;
- }
- namespace {
- /* Abstract memory reader. */
- class abstract_memory_reader
- {
- public:
- /* Read LEN bytes of target memory at address MEMADDR, placing the
- results in GDB's memory at BUF. Return true on success. */
- virtual bool read (CORE_ADDR memaddr, gdb_byte *buf, const size_t len) = 0;
- };
- /* Instruction reader from real target. */
- class instruction_reader : public abstract_memory_reader
- {
- public:
- bool read (CORE_ADDR memaddr, gdb_byte *buf, const size_t len) override
- {
- if (target_read_memory (memaddr, buf, len))
- return false;
- else
- return true;
- }
- };
- } // namespace
- /* Extracts arm/thumb/thumb2 insn depending on the size, and returns 0 on success
- and positive val on failure. */
- static int
- extract_arm_insn (abstract_memory_reader& reader,
- insn_decode_record *insn_record, uint32_t insn_size)
- {
- gdb_byte buf[insn_size];
- memset (&buf[0], 0, insn_size);
-
- if (!reader.read (insn_record->this_addr, buf, insn_size))
- return 1;
- insn_record->arm_insn = (uint32_t) extract_unsigned_integer (&buf[0],
- insn_size,
- gdbarch_byte_order_for_code (insn_record->gdbarch));
- return 0;
- }
- typedef int (*sti_arm_hdl_fp_t) (insn_decode_record*);
- /* Decode arm/thumb insn depending on condition cods and opcodes; and
- dispatch it. */
- static int
- decode_insn (abstract_memory_reader &reader, insn_decode_record *arm_record,
- record_type_t record_type, uint32_t insn_size)
- {
- /* (Starting from numerical 0); bits 25, 26, 27 decodes type of arm
- instruction. */
- static const sti_arm_hdl_fp_t arm_handle_insn[8] =
- {
- arm_record_data_proc_misc_ld_str, /* 000. */
- arm_record_data_proc_imm, /* 001. */
- arm_record_ld_st_imm_offset, /* 010. */
- arm_record_ld_st_reg_offset, /* 011. */
- arm_record_ld_st_multiple, /* 100. */
- arm_record_b_bl, /* 101. */
- arm_record_asimd_vfp_coproc, /* 110. */
- arm_record_coproc_data_proc /* 111. */
- };
- /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb
- instruction. */
- static const sti_arm_hdl_fp_t thumb_handle_insn[8] =
- { \
- thumb_record_shift_add_sub, /* 000. */
- thumb_record_add_sub_cmp_mov, /* 001. */
- thumb_record_ld_st_reg_offset, /* 010. */
- thumb_record_ld_st_imm_offset, /* 011. */
- thumb_record_ld_st_stack, /* 100. */
- thumb_record_misc, /* 101. */
- thumb_record_ldm_stm_swi, /* 110. */
- thumb_record_branch /* 111. */
- };
- uint32_t ret = 0; /* return value: negative:failure 0:success. */
- uint32_t insn_id = 0;
- if (extract_arm_insn (reader, arm_record, insn_size))
- {
- if (record_debug)
- {
- gdb_printf (gdb_stdlog,
- _("Process record: error reading memory at "
- "addr %s len = %d.\n"),
- paddress (arm_record->gdbarch,
- arm_record->this_addr), insn_size);
- }
- return -1;
- }
- else if (ARM_RECORD == record_type)
- {
- arm_record->cond = bits (arm_record->arm_insn, 28, 31);
- insn_id = bits (arm_record->arm_insn, 25, 27);
- if (arm_record->cond == 0xf)
- ret = arm_record_extension_space (arm_record);
- else
- {
- /* If this insn has fallen into extension space
- then we need not decode it anymore. */
- ret = arm_handle_insn[insn_id] (arm_record);
- }
- if (ret != ARM_RECORD_SUCCESS)
- {
- arm_record_unsupported_insn (arm_record);
- ret = -1;
- }
- }
- else if (THUMB_RECORD == record_type)
- {
- /* As thumb does not have condition codes, we set negative. */
- arm_record->cond = -1;
- insn_id = bits (arm_record->arm_insn, 13, 15);
- ret = thumb_handle_insn[insn_id] (arm_record);
- if (ret != ARM_RECORD_SUCCESS)
- {
- arm_record_unsupported_insn (arm_record);
- ret = -1;
- }
- }
- else if (THUMB2_RECORD == record_type)
- {
- /* As thumb does not have condition codes, we set negative. */
- arm_record->cond = -1;
- /* Swap first half of 32bit thumb instruction with second half. */
- arm_record->arm_insn
- = (arm_record->arm_insn >> 16) | (arm_record->arm_insn << 16);
- ret = thumb2_record_decode_insn_handler (arm_record);
- if (ret != ARM_RECORD_SUCCESS)
- {
- arm_record_unsupported_insn (arm_record);
- ret = -1;
- }
- }
- else
- {
- /* Throw assertion. */
- gdb_assert_not_reached ("not a valid instruction, could not decode");
- }
- return ret;
- }
- #if GDB_SELF_TEST
- namespace selftests {
- /* Provide both 16-bit and 32-bit thumb instructions. */
- class instruction_reader_thumb : public abstract_memory_reader
- {
- public:
- template<size_t SIZE>
- instruction_reader_thumb (enum bfd_endian endian,
- const uint16_t (&insns)[SIZE])
- : m_endian (endian), m_insns (insns), m_insns_size (SIZE)
- {}
- bool read (CORE_ADDR memaddr, gdb_byte *buf, const size_t len) override
- {
- SELF_CHECK (len == 4 || len == 2);
- SELF_CHECK (memaddr % 2 == 0);
- SELF_CHECK ((memaddr / 2) < m_insns_size);
- store_unsigned_integer (buf, 2, m_endian, m_insns[memaddr / 2]);
- if (len == 4)
- {
- store_unsigned_integer (&buf[2], 2, m_endian,
- m_insns[memaddr / 2 + 1]);
- }
- return true;
- }
- private:
- enum bfd_endian m_endian;
- const uint16_t *m_insns;
- size_t m_insns_size;
- };
- static void
- arm_record_test (void)
- {
- struct gdbarch_info info;
- info.bfd_arch_info = bfd_scan_arch ("arm");
- struct gdbarch *gdbarch = gdbarch_find_by_info (info);
- SELF_CHECK (gdbarch != NULL);
- /* 16-bit Thumb instructions. */
- {
- insn_decode_record arm_record;
- memset (&arm_record, 0, sizeof (insn_decode_record));
- arm_record.gdbarch = gdbarch;
- static const uint16_t insns[] = {
- /* db b2 uxtb r3, r3 */
- 0xb2db,
- /* cd 58 ldr r5, [r1, r3] */
- 0x58cd,
- };
- enum bfd_endian endian = gdbarch_byte_order_for_code (arm_record.gdbarch);
- instruction_reader_thumb reader (endian, insns);
- int ret = decode_insn (reader, &arm_record, THUMB_RECORD,
- THUMB_INSN_SIZE_BYTES);
- SELF_CHECK (ret == 0);
- SELF_CHECK (arm_record.mem_rec_count == 0);
- SELF_CHECK (arm_record.reg_rec_count == 1);
- SELF_CHECK (arm_record.arm_regs[0] == 3);
- arm_record.this_addr += 2;
- ret = decode_insn (reader, &arm_record, THUMB_RECORD,
- THUMB_INSN_SIZE_BYTES);
- SELF_CHECK (ret == 0);
- SELF_CHECK (arm_record.mem_rec_count == 0);
- SELF_CHECK (arm_record.reg_rec_count == 1);
- SELF_CHECK (arm_record.arm_regs[0] == 5);
- }
- /* 32-bit Thumb-2 instructions. */
- {
- insn_decode_record arm_record;
- memset (&arm_record, 0, sizeof (insn_decode_record));
- arm_record.gdbarch = gdbarch;
- static const uint16_t insns[] = {
- /* 1d ee 70 7f mrc 15, 0, r7, cr13, cr0, {3} */
- 0xee1d, 0x7f70,
- };
- enum bfd_endian endian = gdbarch_byte_order_for_code (arm_record.gdbarch);
- instruction_reader_thumb reader (endian, insns);
- int ret = decode_insn (reader, &arm_record, THUMB2_RECORD,
- THUMB2_INSN_SIZE_BYTES);
- SELF_CHECK (ret == 0);
- SELF_CHECK (arm_record.mem_rec_count == 0);
- SELF_CHECK (arm_record.reg_rec_count == 1);
- SELF_CHECK (arm_record.arm_regs[0] == 7);
- }
- }
- /* Instruction reader from manually cooked instruction sequences. */
- class test_arm_instruction_reader : public arm_instruction_reader
- {
- public:
- explicit test_arm_instruction_reader (gdb::array_view<const uint32_t> insns)
- : m_insns (insns)
- {}
- uint32_t read (CORE_ADDR memaddr, enum bfd_endian byte_order) const override
- {
- SELF_CHECK (memaddr % 4 == 0);
- SELF_CHECK (memaddr / 4 < m_insns.size ());
- return m_insns[memaddr / 4];
- }
- private:
- const gdb::array_view<const uint32_t> m_insns;
- };
- static void
- arm_analyze_prologue_test ()
- {
- for (bfd_endian endianness : {BFD_ENDIAN_LITTLE, BFD_ENDIAN_BIG})
- {
- struct gdbarch_info info;
- info.byte_order = endianness;
- info.byte_order_for_code = endianness;
- info.bfd_arch_info = bfd_scan_arch ("arm");
- struct gdbarch *gdbarch = gdbarch_find_by_info (info);
- SELF_CHECK (gdbarch != NULL);
- /* The "sub" instruction contains an immediate value rotate count of 0,
- which resulted in a 32-bit shift of a 32-bit value, caught by
- UBSan. */
- const uint32_t insns[] = {
- 0xe92d4ff0, /* push {r4, r5, r6, r7, r8, r9, sl, fp, lr} */
- 0xe1a05000, /* mov r5, r0 */
- 0xe5903020, /* ldr r3, [r0, #32] */
- 0xe24dd044, /* sub sp, sp, #68 ; 0x44 */
- };
- test_arm_instruction_reader mem_reader (insns);
- arm_prologue_cache cache;
- cache.saved_regs = trad_frame_alloc_saved_regs (gdbarch);
- arm_analyze_prologue (gdbarch, 0, sizeof (insns) - 1, &cache, mem_reader);
- }
- }
- } // namespace selftests
- #endif /* GDB_SELF_TEST */
- /* Cleans up local record registers and memory allocations. */
- static void
- deallocate_reg_mem (insn_decode_record *record)
- {
- xfree (record->arm_regs);
- xfree (record->arm_mems);
- }
- /* Parse the current instruction and record the values of the registers and
- memory that will be changed in current instruction to record_arch_list".
- Return -1 if something is wrong. */
- int
- arm_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
- CORE_ADDR insn_addr)
- {
- uint32_t no_of_rec = 0;
- uint32_t ret = 0; /* return value: -1:record failure ; 0:success */
- ULONGEST t_bit = 0, insn_id = 0;
- ULONGEST u_regval = 0;
- insn_decode_record arm_record;
- memset (&arm_record, 0, sizeof (insn_decode_record));
- arm_record.regcache = regcache;
- arm_record.this_addr = insn_addr;
- arm_record.gdbarch = gdbarch;
- if (record_debug > 1)
- {
- gdb_printf (gdb_stdlog, "Process record: arm_process_record "
- "addr = %s\n",
- paddress (gdbarch, arm_record.this_addr));
- }
- instruction_reader reader;
- if (extract_arm_insn (reader, &arm_record, 2))
- {
- if (record_debug)
- {
- gdb_printf (gdb_stdlog,
- _("Process record: error reading memory at "
- "addr %s len = %d.\n"),
- paddress (arm_record.gdbarch,
- arm_record.this_addr), 2);
- }
- return -1;
- }
- /* Check the insn, whether it is thumb or arm one. */
- t_bit = arm_psr_thumb_bit (arm_record.gdbarch);
- regcache_raw_read_unsigned (arm_record.regcache, ARM_PS_REGNUM, &u_regval);
- if (!(u_regval & t_bit))
- {
- /* We are decoding arm insn. */
- ret = decode_insn (reader, &arm_record, ARM_RECORD, ARM_INSN_SIZE_BYTES);
- }
- else
- {
- insn_id = bits (arm_record.arm_insn, 11, 15);
- /* is it thumb2 insn? */
- if ((0x1D == insn_id) || (0x1E == insn_id) || (0x1F == insn_id))
- {
- ret = decode_insn (reader, &arm_record, THUMB2_RECORD,
- THUMB2_INSN_SIZE_BYTES);
- }
- else
- {
- /* We are decoding thumb insn. */
- ret = decode_insn (reader, &arm_record, THUMB_RECORD,
- THUMB_INSN_SIZE_BYTES);
- }
- }
- if (0 == ret)
- {
- /* Record registers. */
- record_full_arch_list_add_reg (arm_record.regcache, ARM_PC_REGNUM);
- if (arm_record.arm_regs)
- {
- for (no_of_rec = 0; no_of_rec < arm_record.reg_rec_count; no_of_rec++)
- {
- if (record_full_arch_list_add_reg
- (arm_record.regcache , arm_record.arm_regs[no_of_rec]))
- ret = -1;
- }
- }
- /* Record memories. */
- if (arm_record.arm_mems)
- {
- for (no_of_rec = 0; no_of_rec < arm_record.mem_rec_count; no_of_rec++)
- {
- if (record_full_arch_list_add_mem
- ((CORE_ADDR)arm_record.arm_mems[no_of_rec].addr,
- arm_record.arm_mems[no_of_rec].len))
- ret = -1;
- }
- }
- if (record_full_arch_list_add_end ())
- ret = -1;
- }
- deallocate_reg_mem (&arm_record);
- return ret;
- }
- /* See arm-tdep.h. */
- const target_desc *
- arm_read_description (arm_fp_type fp_type)
- {
- struct target_desc *tdesc = tdesc_arm_list[fp_type];
- if (tdesc == nullptr)
- {
- tdesc = arm_create_target_description (fp_type);
- tdesc_arm_list[fp_type] = tdesc;
- }
- return tdesc;
- }
- /* See arm-tdep.h. */
- const target_desc *
- arm_read_mprofile_description (arm_m_profile_type m_type)
- {
- struct target_desc *tdesc = tdesc_arm_mprofile_list[m_type];
- if (tdesc == nullptr)
- {
- tdesc = arm_create_mprofile_target_description (m_type);
- tdesc_arm_mprofile_list[m_type] = tdesc;
- }
- return tdesc;
- }
|