12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718 |
- /* Common target dependent code for GDB on AArch64 systems.
- Copyright (C) 2009-2022 Free Software Foundation, Inc.
- Contributed by ARM Ltd.
- 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 "frame.h"
- #include "gdbcmd.h"
- #include "gdbcore.h"
- #include "dis-asm.h"
- #include "regcache.h"
- #include "reggroups.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 "target-descriptions.h"
- #include "user-regs.h"
- #include "ax-gdb.h"
- #include "gdbsupport/selftest.h"
- #include "aarch64-tdep.h"
- #include "aarch64-ravenscar-thread.h"
- #include "record.h"
- #include "record-full.h"
- #include "arch/aarch64-insn.h"
- #include "gdbarch.h"
- #include "opcode/aarch64.h"
- #include <algorithm>
- /* A Homogeneous Floating-Point or Short-Vector Aggregate may have at most
- four members. */
- #define HA_MAX_NUM_FLDS 4
- /* All possible aarch64 target descriptors. */
- static target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1][2/*pauth*/][2 /* mte */];
- /* The standard register names, and all the valid aliases for them. */
- static const struct
- {
- const char *const name;
- int regnum;
- } aarch64_register_aliases[] =
- {
- /* 64-bit register names. */
- {"fp", AARCH64_FP_REGNUM},
- {"lr", AARCH64_LR_REGNUM},
- {"sp", AARCH64_SP_REGNUM},
- /* 32-bit register names. */
- {"w0", AARCH64_X0_REGNUM + 0},
- {"w1", AARCH64_X0_REGNUM + 1},
- {"w2", AARCH64_X0_REGNUM + 2},
- {"w3", AARCH64_X0_REGNUM + 3},
- {"w4", AARCH64_X0_REGNUM + 4},
- {"w5", AARCH64_X0_REGNUM + 5},
- {"w6", AARCH64_X0_REGNUM + 6},
- {"w7", AARCH64_X0_REGNUM + 7},
- {"w8", AARCH64_X0_REGNUM + 8},
- {"w9", AARCH64_X0_REGNUM + 9},
- {"w10", AARCH64_X0_REGNUM + 10},
- {"w11", AARCH64_X0_REGNUM + 11},
- {"w12", AARCH64_X0_REGNUM + 12},
- {"w13", AARCH64_X0_REGNUM + 13},
- {"w14", AARCH64_X0_REGNUM + 14},
- {"w15", AARCH64_X0_REGNUM + 15},
- {"w16", AARCH64_X0_REGNUM + 16},
- {"w17", AARCH64_X0_REGNUM + 17},
- {"w18", AARCH64_X0_REGNUM + 18},
- {"w19", AARCH64_X0_REGNUM + 19},
- {"w20", AARCH64_X0_REGNUM + 20},
- {"w21", AARCH64_X0_REGNUM + 21},
- {"w22", AARCH64_X0_REGNUM + 22},
- {"w23", AARCH64_X0_REGNUM + 23},
- {"w24", AARCH64_X0_REGNUM + 24},
- {"w25", AARCH64_X0_REGNUM + 25},
- {"w26", AARCH64_X0_REGNUM + 26},
- {"w27", AARCH64_X0_REGNUM + 27},
- {"w28", AARCH64_X0_REGNUM + 28},
- {"w29", AARCH64_X0_REGNUM + 29},
- {"w30", AARCH64_X0_REGNUM + 30},
- /* specials */
- {"ip0", AARCH64_X0_REGNUM + 16},
- {"ip1", AARCH64_X0_REGNUM + 17}
- };
- /* The required core 'R' registers. */
- static const char *const aarch64_r_register_names[] =
- {
- /* These registers must appear in consecutive RAW register number
- order and they must begin with AARCH64_X0_REGNUM! */
- "x0", "x1", "x2", "x3",
- "x4", "x5", "x6", "x7",
- "x8", "x9", "x10", "x11",
- "x12", "x13", "x14", "x15",
- "x16", "x17", "x18", "x19",
- "x20", "x21", "x22", "x23",
- "x24", "x25", "x26", "x27",
- "x28", "x29", "x30", "sp",
- "pc", "cpsr"
- };
- /* The FP/SIMD 'V' registers. */
- static const char *const aarch64_v_register_names[] =
- {
- /* These registers must appear in consecutive RAW register number
- order and they must begin with AARCH64_V0_REGNUM! */
- "v0", "v1", "v2", "v3",
- "v4", "v5", "v6", "v7",
- "v8", "v9", "v10", "v11",
- "v12", "v13", "v14", "v15",
- "v16", "v17", "v18", "v19",
- "v20", "v21", "v22", "v23",
- "v24", "v25", "v26", "v27",
- "v28", "v29", "v30", "v31",
- "fpsr",
- "fpcr"
- };
- /* The SVE 'Z' and 'P' registers. */
- static const char *const aarch64_sve_register_names[] =
- {
- /* These registers must appear in consecutive RAW register number
- order and they must begin with AARCH64_SVE_Z0_REGNUM! */
- "z0", "z1", "z2", "z3",
- "z4", "z5", "z6", "z7",
- "z8", "z9", "z10", "z11",
- "z12", "z13", "z14", "z15",
- "z16", "z17", "z18", "z19",
- "z20", "z21", "z22", "z23",
- "z24", "z25", "z26", "z27",
- "z28", "z29", "z30", "z31",
- "fpsr", "fpcr",
- "p0", "p1", "p2", "p3",
- "p4", "p5", "p6", "p7",
- "p8", "p9", "p10", "p11",
- "p12", "p13", "p14", "p15",
- "ffr", "vg"
- };
- static const char *const aarch64_pauth_register_names[] =
- {
- /* Authentication mask for data pointer. */
- "pauth_dmask",
- /* Authentication mask for code pointer. */
- "pauth_cmask"
- };
- static const char *const aarch64_mte_register_names[] =
- {
- /* Tag Control Register. */
- "tag_ctl"
- };
- /* AArch64 prologue cache structure. */
- struct aarch64_prologue_cache
- {
- /* The program counter at the start of the function. It is used to
- identify this frame as a prologue frame. */
- CORE_ADDR func;
- /* The program counter at the time this frame was created; i.e. where
- this function was called from. It is used to identify this frame as a
- stub frame. */
- CORE_ADDR prev_pc;
- /* 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;
- /* Is the target available to read from? */
- int available_p;
- /* 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;
- /* Saved register offsets. */
- trad_frame_saved_reg *saved_regs;
- };
- static void
- show_aarch64_debug (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("AArch64 debugging is %s.\n"), value);
- }
- namespace {
- /* Abstract instruction reader. */
- class abstract_instruction_reader
- {
- public:
- /* Read in one instruction. */
- virtual ULONGEST read (CORE_ADDR memaddr, int len,
- enum bfd_endian byte_order) = 0;
- };
- /* Instruction reader from real target. */
- class instruction_reader : public abstract_instruction_reader
- {
- public:
- ULONGEST read (CORE_ADDR memaddr, int len, enum bfd_endian byte_order)
- override
- {
- return read_code_unsigned_integer (memaddr, len, byte_order);
- }
- };
- } // namespace
- /* If address signing is enabled, mask off the signature bits from the link
- register, which is passed by value in ADDR, using the register values in
- THIS_FRAME. */
- static CORE_ADDR
- aarch64_frame_unmask_lr (aarch64_gdbarch_tdep *tdep,
- struct frame_info *this_frame, CORE_ADDR addr)
- {
- if (tdep->has_pauth ()
- && frame_unwind_register_unsigned (this_frame,
- tdep->pauth_ra_state_regnum))
- {
- int cmask_num = AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base);
- CORE_ADDR cmask = frame_unwind_register_unsigned (this_frame, cmask_num);
- addr = addr & ~cmask;
- /* Record in the frame that the link register required unmasking. */
- set_frame_previous_pc_masked (this_frame);
- }
- return addr;
- }
- /* Implement the "get_pc_address_flags" gdbarch method. */
- static std::string
- aarch64_get_pc_address_flags (frame_info *frame, CORE_ADDR pc)
- {
- if (pc != 0 && get_frame_pc_masked (frame))
- return "PAC";
- return "";
- }
- /* Analyze a 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. */
- static CORE_ADDR
- aarch64_analyze_prologue (struct gdbarch *gdbarch,
- CORE_ADDR start, CORE_ADDR limit,
- struct aarch64_prologue_cache *cache,
- abstract_instruction_reader& reader)
- {
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- int i;
- /* Whether the stack has been set. This should be true when we notice a SP
- to FP move or if we are using the SP as the base register for storing
- data, in case the FP is ommitted. */
- bool seen_stack_set = false;
- /* Track X registers and D registers in prologue. */
- pv_t regs[AARCH64_X_REGISTER_COUNT + AARCH64_D_REGISTER_COUNT];
- for (i = 0; i < AARCH64_X_REGISTER_COUNT + AARCH64_D_REGISTER_COUNT; i++)
- regs[i] = pv_register (i, 0);
- pv_area stack (AARCH64_SP_REGNUM, gdbarch_addr_bit (gdbarch));
- for (; start < limit; start += 4)
- {
- uint32_t insn;
- aarch64_inst inst;
- insn = reader.read (start, 4, byte_order_for_code);
- if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0)
- break;
- if (inst.opcode->iclass == addsub_imm
- && (inst.opcode->op == OP_ADD
- || strcmp ("sub", inst.opcode->name) == 0))
- {
- unsigned rd = inst.operands[0].reg.regno;
- unsigned rn = inst.operands[1].reg.regno;
- gdb_assert (aarch64_num_of_operands (inst.opcode) == 3);
- gdb_assert (inst.operands[0].type == AARCH64_OPND_Rd_SP);
- gdb_assert (inst.operands[1].type == AARCH64_OPND_Rn_SP);
- gdb_assert (inst.operands[2].type == AARCH64_OPND_AIMM);
- if (inst.opcode->op == OP_ADD)
- {
- regs[rd] = pv_add_constant (regs[rn],
- inst.operands[2].imm.value);
- }
- else
- {
- regs[rd] = pv_add_constant (regs[rn],
- -inst.operands[2].imm.value);
- }
- /* Did we move SP to FP? */
- if (rn == AARCH64_SP_REGNUM && rd == AARCH64_FP_REGNUM)
- seen_stack_set = true;
- }
- else if (inst.opcode->iclass == pcreladdr
- && inst.operands[1].type == AARCH64_OPND_ADDR_ADRP)
- {
- gdb_assert (aarch64_num_of_operands (inst.opcode) == 2);
- gdb_assert (inst.operands[0].type == AARCH64_OPND_Rd);
- regs[inst.operands[0].reg.regno] = pv_unknown ();
- }
- else if (inst.opcode->iclass == branch_imm)
- {
- /* Stop analysis on branch. */
- break;
- }
- else if (inst.opcode->iclass == condbranch)
- {
- /* Stop analysis on branch. */
- break;
- }
- else if (inst.opcode->iclass == branch_reg)
- {
- /* Stop analysis on branch. */
- break;
- }
- else if (inst.opcode->iclass == compbranch)
- {
- /* Stop analysis on branch. */
- break;
- }
- else if (inst.opcode->op == OP_MOVZ)
- {
- gdb_assert (inst.operands[0].type == AARCH64_OPND_Rd);
- /* If this shows up before we set the stack, keep going. Otherwise
- stop the analysis. */
- if (seen_stack_set)
- break;
- regs[inst.operands[0].reg.regno] = pv_unknown ();
- }
- else if (inst.opcode->iclass == log_shift
- && strcmp (inst.opcode->name, "orr") == 0)
- {
- unsigned rd = inst.operands[0].reg.regno;
- unsigned rn = inst.operands[1].reg.regno;
- unsigned rm = inst.operands[2].reg.regno;
- gdb_assert (inst.operands[0].type == AARCH64_OPND_Rd);
- gdb_assert (inst.operands[1].type == AARCH64_OPND_Rn);
- gdb_assert (inst.operands[2].type == AARCH64_OPND_Rm_SFT);
- if (inst.operands[2].shifter.amount == 0
- && rn == AARCH64_SP_REGNUM)
- regs[rd] = regs[rm];
- else
- {
- aarch64_debug_printf ("prologue analysis gave up "
- "addr=%s opcode=0x%x (orr x register)",
- core_addr_to_string_nz (start), insn);
- break;
- }
- }
- else if (inst.opcode->op == OP_STUR)
- {
- unsigned rt = inst.operands[0].reg.regno;
- unsigned rn = inst.operands[1].addr.base_regno;
- int size = aarch64_get_qualifier_esize (inst.operands[0].qualifier);
- gdb_assert (aarch64_num_of_operands (inst.opcode) == 2);
- gdb_assert (inst.operands[0].type == AARCH64_OPND_Rt);
- gdb_assert (inst.operands[1].type == AARCH64_OPND_ADDR_SIMM9);
- gdb_assert (!inst.operands[1].addr.offset.is_reg);
- stack.store
- (pv_add_constant (regs[rn], inst.operands[1].addr.offset.imm),
- size, regs[rt]);
- /* Are we storing with SP as a base? */
- if (rn == AARCH64_SP_REGNUM)
- seen_stack_set = true;
- }
- else if ((inst.opcode->iclass == ldstpair_off
- || (inst.opcode->iclass == ldstpair_indexed
- && inst.operands[2].addr.preind))
- && strcmp ("stp", inst.opcode->name) == 0)
- {
- /* STP with addressing mode Pre-indexed and Base register. */
- unsigned rt1;
- unsigned rt2;
- unsigned rn = inst.operands[2].addr.base_regno;
- int32_t imm = inst.operands[2].addr.offset.imm;
- int size = aarch64_get_qualifier_esize (inst.operands[0].qualifier);
- gdb_assert (inst.operands[0].type == AARCH64_OPND_Rt
- || inst.operands[0].type == AARCH64_OPND_Ft);
- gdb_assert (inst.operands[1].type == AARCH64_OPND_Rt2
- || inst.operands[1].type == AARCH64_OPND_Ft2);
- gdb_assert (inst.operands[2].type == AARCH64_OPND_ADDR_SIMM7);
- gdb_assert (!inst.operands[2].addr.offset.is_reg);
- /* If recording this store would invalidate the store area
- (perhaps because rn is not known) then we should abandon
- further prologue analysis. */
- if (stack.store_would_trash (pv_add_constant (regs[rn], imm)))
- break;
- if (stack.store_would_trash (pv_add_constant (regs[rn], imm + 8)))
- break;
- rt1 = inst.operands[0].reg.regno;
- rt2 = inst.operands[1].reg.regno;
- if (inst.operands[0].type == AARCH64_OPND_Ft)
- {
- rt1 += AARCH64_X_REGISTER_COUNT;
- rt2 += AARCH64_X_REGISTER_COUNT;
- }
- stack.store (pv_add_constant (regs[rn], imm), size, regs[rt1]);
- stack.store (pv_add_constant (regs[rn], imm + size), size, regs[rt2]);
- if (inst.operands[2].addr.writeback)
- regs[rn] = pv_add_constant (regs[rn], imm);
- /* Ignore the instruction that allocates stack space and sets
- the SP. */
- if (rn == AARCH64_SP_REGNUM && !inst.operands[2].addr.writeback)
- seen_stack_set = true;
- }
- else if ((inst.opcode->iclass == ldst_imm9 /* Signed immediate. */
- || (inst.opcode->iclass == ldst_pos /* Unsigned immediate. */
- && (inst.opcode->op == OP_STR_POS
- || inst.opcode->op == OP_STRF_POS)))
- && inst.operands[1].addr.base_regno == AARCH64_SP_REGNUM
- && strcmp ("str", inst.opcode->name) == 0)
- {
- /* STR (immediate) */
- unsigned int rt = inst.operands[0].reg.regno;
- int32_t imm = inst.operands[1].addr.offset.imm;
- unsigned int rn = inst.operands[1].addr.base_regno;
- int size = aarch64_get_qualifier_esize (inst.operands[0].qualifier);
- gdb_assert (inst.operands[0].type == AARCH64_OPND_Rt
- || inst.operands[0].type == AARCH64_OPND_Ft);
- if (inst.operands[0].type == AARCH64_OPND_Ft)
- rt += AARCH64_X_REGISTER_COUNT;
- stack.store (pv_add_constant (regs[rn], imm), size, regs[rt]);
- if (inst.operands[1].addr.writeback)
- regs[rn] = pv_add_constant (regs[rn], imm);
- /* Are we storing with SP as a base? */
- if (rn == AARCH64_SP_REGNUM)
- seen_stack_set = true;
- }
- else if (inst.opcode->iclass == testbranch)
- {
- /* Stop analysis on branch. */
- break;
- }
- else if (inst.opcode->iclass == ic_system)
- {
- aarch64_gdbarch_tdep *tdep
- = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- int ra_state_val = 0;
- if (insn == 0xd503233f /* paciasp. */
- || insn == 0xd503237f /* pacibsp. */)
- {
- /* Return addresses are mangled. */
- ra_state_val = 1;
- }
- else if (insn == 0xd50323bf /* autiasp. */
- || insn == 0xd50323ff /* autibsp. */)
- {
- /* Return addresses are not mangled. */
- ra_state_val = 0;
- }
- else if (IS_BTI (insn))
- /* We don't need to do anything special for a BTI instruction. */
- continue;
- else
- {
- aarch64_debug_printf ("prologue analysis gave up addr=%s"
- " opcode=0x%x (iclass)",
- core_addr_to_string_nz (start), insn);
- break;
- }
- if (tdep->has_pauth () && cache != nullptr)
- {
- int regnum = tdep->pauth_ra_state_regnum;
- cache->saved_regs[regnum].set_value (ra_state_val);
- }
- }
- else
- {
- aarch64_debug_printf ("prologue analysis gave up addr=%s"
- " opcode=0x%x",
- core_addr_to_string_nz (start), insn);
- break;
- }
- }
- if (cache == NULL)
- return start;
- if (pv_is_register (regs[AARCH64_FP_REGNUM], AARCH64_SP_REGNUM))
- {
- /* Frame pointer is fp. Frame size is constant. */
- cache->framereg = AARCH64_FP_REGNUM;
- cache->framesize = -regs[AARCH64_FP_REGNUM].k;
- }
- else if (pv_is_register (regs[AARCH64_SP_REGNUM], AARCH64_SP_REGNUM))
- {
- /* Try the stack pointer. */
- cache->framesize = -regs[AARCH64_SP_REGNUM].k;
- cache->framereg = AARCH64_SP_REGNUM;
- }
- else
- {
- /* We're just out of luck. We don't know where the frame is. */
- cache->framereg = -1;
- cache->framesize = 0;
- }
- for (i = 0; i < AARCH64_X_REGISTER_COUNT; i++)
- {
- CORE_ADDR offset;
- if (stack.find_reg (gdbarch, i, &offset))
- cache->saved_regs[i].set_addr (offset);
- }
- for (i = 0; i < AARCH64_D_REGISTER_COUNT; i++)
- {
- int regnum = gdbarch_num_regs (gdbarch);
- CORE_ADDR offset;
- if (stack.find_reg (gdbarch, i + AARCH64_X_REGISTER_COUNT,
- &offset))
- cache->saved_regs[i + regnum + AARCH64_D0_REGNUM].set_addr (offset);
- }
- return start;
- }
- static CORE_ADDR
- aarch64_analyze_prologue (struct gdbarch *gdbarch,
- CORE_ADDR start, CORE_ADDR limit,
- struct aarch64_prologue_cache *cache)
- {
- instruction_reader reader;
- return aarch64_analyze_prologue (gdbarch, start, limit, cache,
- reader);
- }
- #if GDB_SELF_TEST
- namespace selftests {
- /* Instruction reader from manually cooked instruction sequences. */
- class instruction_reader_test : public abstract_instruction_reader
- {
- public:
- template<size_t SIZE>
- explicit instruction_reader_test (const uint32_t (&insns)[SIZE])
- : m_insns (insns), m_insns_size (SIZE)
- {}
- ULONGEST read (CORE_ADDR memaddr, int len, enum bfd_endian byte_order)
- override
- {
- SELF_CHECK (len == 4);
- SELF_CHECK (memaddr % 4 == 0);
- SELF_CHECK (memaddr / 4 < m_insns_size);
- return m_insns[memaddr / 4];
- }
- private:
- const uint32_t *m_insns;
- size_t m_insns_size;
- };
- static void
- aarch64_analyze_prologue_test (void)
- {
- struct gdbarch_info info;
- info.bfd_arch_info = bfd_scan_arch ("aarch64");
- struct gdbarch *gdbarch = gdbarch_find_by_info (info);
- SELF_CHECK (gdbarch != NULL);
- struct aarch64_prologue_cache cache;
- cache.saved_regs = trad_frame_alloc_saved_regs (gdbarch);
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- /* Test the simple prologue in which frame pointer is used. */
- {
- static const uint32_t insns[] = {
- 0xa9af7bfd, /* stp x29, x30, [sp,#-272]! */
- 0x910003fd, /* mov x29, sp */
- 0x97ffffe6, /* bl 0x400580 */
- };
- instruction_reader_test reader (insns);
- CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
- SELF_CHECK (end == 4 * 2);
- SELF_CHECK (cache.framereg == AARCH64_FP_REGNUM);
- SELF_CHECK (cache.framesize == 272);
- for (int i = 0; i < AARCH64_X_REGISTER_COUNT; i++)
- {
- if (i == AARCH64_FP_REGNUM)
- SELF_CHECK (cache.saved_regs[i].addr () == -272);
- else if (i == AARCH64_LR_REGNUM)
- SELF_CHECK (cache.saved_regs[i].addr () == -264);
- else
- SELF_CHECK (cache.saved_regs[i].is_realreg ()
- && cache.saved_regs[i].realreg () == i);
- }
- for (int i = 0; i < AARCH64_D_REGISTER_COUNT; i++)
- {
- int num_regs = gdbarch_num_regs (gdbarch);
- int regnum = i + num_regs + AARCH64_D0_REGNUM;
- SELF_CHECK (cache.saved_regs[regnum].is_realreg ()
- && cache.saved_regs[regnum].realreg () == regnum);
- }
- }
- /* Test a prologue in which STR is used and frame pointer is not
- used. */
- {
- static const uint32_t insns[] = {
- 0xf81d0ff3, /* str x19, [sp, #-48]! */
- 0xb9002fe0, /* str w0, [sp, #44] */
- 0xf90013e1, /* str x1, [sp, #32]*/
- 0xfd000fe0, /* str d0, [sp, #24] */
- 0xaa0203f3, /* mov x19, x2 */
- 0xf94013e0, /* ldr x0, [sp, #32] */
- };
- instruction_reader_test reader (insns);
- trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
- CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
- SELF_CHECK (end == 4 * 5);
- SELF_CHECK (cache.framereg == AARCH64_SP_REGNUM);
- SELF_CHECK (cache.framesize == 48);
- for (int i = 0; i < AARCH64_X_REGISTER_COUNT; i++)
- {
- if (i == 1)
- SELF_CHECK (cache.saved_regs[i].addr () == -16);
- else if (i == 19)
- SELF_CHECK (cache.saved_regs[i].addr () == -48);
- else
- SELF_CHECK (cache.saved_regs[i].is_realreg ()
- && cache.saved_regs[i].realreg () == i);
- }
- for (int i = 0; i < AARCH64_D_REGISTER_COUNT; i++)
- {
- int num_regs = gdbarch_num_regs (gdbarch);
- int regnum = i + num_regs + AARCH64_D0_REGNUM;
- if (i == 0)
- SELF_CHECK (cache.saved_regs[regnum].addr () == -24);
- else
- SELF_CHECK (cache.saved_regs[regnum].is_realreg ()
- && cache.saved_regs[regnum].realreg () == regnum);
- }
- }
- /* Test handling of movz before setting the frame pointer. */
- {
- static const uint32_t insns[] = {
- 0xa9bf7bfd, /* stp x29, x30, [sp, #-16]! */
- 0x52800020, /* mov w0, #0x1 */
- 0x910003fd, /* mov x29, sp */
- 0x528000a2, /* mov w2, #0x5 */
- 0x97fffff8, /* bl 6e4 */
- };
- instruction_reader_test reader (insns);
- trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
- CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
- /* We should stop at the 4th instruction. */
- SELF_CHECK (end == (4 - 1) * 4);
- SELF_CHECK (cache.framereg == AARCH64_FP_REGNUM);
- SELF_CHECK (cache.framesize == 16);
- }
- /* Test handling of movz/stp when using the stack pointer as frame
- pointer. */
- {
- static const uint32_t insns[] = {
- 0xa9bc7bfd, /* stp x29, x30, [sp, #-64]! */
- 0x52800020, /* mov w0, #0x1 */
- 0x290207e0, /* stp w0, w1, [sp, #16] */
- 0xa9018fe2, /* stp x2, x3, [sp, #24] */
- 0x528000a2, /* mov w2, #0x5 */
- 0x97fffff8, /* bl 6e4 */
- };
- instruction_reader_test reader (insns);
- trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
- CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
- /* We should stop at the 5th instruction. */
- SELF_CHECK (end == (5 - 1) * 4);
- SELF_CHECK (cache.framereg == AARCH64_SP_REGNUM);
- SELF_CHECK (cache.framesize == 64);
- }
- /* Test handling of movz/str when using the stack pointer as frame
- pointer */
- {
- static const uint32_t insns[] = {
- 0xa9bc7bfd, /* stp x29, x30, [sp, #-64]! */
- 0x52800020, /* mov w0, #0x1 */
- 0xb9002be4, /* str w4, [sp, #40] */
- 0xf9001be5, /* str x5, [sp, #48] */
- 0x528000a2, /* mov w2, #0x5 */
- 0x97fffff8, /* bl 6e4 */
- };
- instruction_reader_test reader (insns);
- trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
- CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
- /* We should stop at the 5th instruction. */
- SELF_CHECK (end == (5 - 1) * 4);
- SELF_CHECK (cache.framereg == AARCH64_SP_REGNUM);
- SELF_CHECK (cache.framesize == 64);
- }
- /* Test handling of movz/stur when using the stack pointer as frame
- pointer. */
- {
- static const uint32_t insns[] = {
- 0xa9bc7bfd, /* stp x29, x30, [sp, #-64]! */
- 0x52800020, /* mov w0, #0x1 */
- 0xb80343e6, /* stur w6, [sp, #52] */
- 0xf80383e7, /* stur x7, [sp, #56] */
- 0x528000a2, /* mov w2, #0x5 */
- 0x97fffff8, /* bl 6e4 */
- };
- instruction_reader_test reader (insns);
- trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
- CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
- /* We should stop at the 5th instruction. */
- SELF_CHECK (end == (5 - 1) * 4);
- SELF_CHECK (cache.framereg == AARCH64_SP_REGNUM);
- SELF_CHECK (cache.framesize == 64);
- }
- /* Test handling of movz when there is no frame pointer set or no stack
- pointer used. */
- {
- static const uint32_t insns[] = {
- 0xa9bf7bfd, /* stp x29, x30, [sp, #-16]! */
- 0x52800020, /* mov w0, #0x1 */
- 0x528000a2, /* mov w2, #0x5 */
- 0x97fffff8, /* bl 6e4 */
- };
- instruction_reader_test reader (insns);
- trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
- CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader);
- /* We should stop at the 4th instruction. */
- SELF_CHECK (end == (4 - 1) * 4);
- SELF_CHECK (cache.framereg == AARCH64_SP_REGNUM);
- SELF_CHECK (cache.framesize == 16);
- }
- /* Test a prologue in which there is a return address signing instruction. */
- if (tdep->has_pauth ())
- {
- static const uint32_t insns[] = {
- 0xd503233f, /* paciasp */
- 0xa9bd7bfd, /* stp x29, x30, [sp, #-48]! */
- 0x910003fd, /* mov x29, sp */
- 0xf801c3f3, /* str x19, [sp, #28] */
- 0xb9401fa0, /* ldr x19, [x29, #28] */
- };
- instruction_reader_test reader (insns);
- trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
- CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache,
- reader);
- SELF_CHECK (end == 4 * 4);
- SELF_CHECK (cache.framereg == AARCH64_FP_REGNUM);
- SELF_CHECK (cache.framesize == 48);
- for (int i = 0; i < AARCH64_X_REGISTER_COUNT; i++)
- {
- if (i == 19)
- SELF_CHECK (cache.saved_regs[i].addr () == -20);
- else if (i == AARCH64_FP_REGNUM)
- SELF_CHECK (cache.saved_regs[i].addr () == -48);
- else if (i == AARCH64_LR_REGNUM)
- SELF_CHECK (cache.saved_regs[i].addr () == -40);
- else
- SELF_CHECK (cache.saved_regs[i].is_realreg ()
- && cache.saved_regs[i].realreg () == i);
- }
- if (tdep->has_pauth ())
- {
- int regnum = tdep->pauth_ra_state_regnum;
- SELF_CHECK (cache.saved_regs[regnum].is_value ());
- }
- }
- /* Test a prologue with a BTI instruction. */
- {
- static const uint32_t insns[] = {
- 0xd503245f, /* bti */
- 0xa9bd7bfd, /* stp x29, x30, [sp, #-48]! */
- 0x910003fd, /* mov x29, sp */
- 0xf801c3f3, /* str x19, [sp, #28] */
- 0xb9401fa0, /* ldr x19, [x29, #28] */
- };
- instruction_reader_test reader (insns);
- trad_frame_reset_saved_regs (gdbarch, cache.saved_regs);
- CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache,
- reader);
- SELF_CHECK (end == 4 * 4);
- SELF_CHECK (cache.framereg == AARCH64_FP_REGNUM);
- SELF_CHECK (cache.framesize == 48);
- for (int i = 0; i < AARCH64_X_REGISTER_COUNT; i++)
- {
- if (i == 19)
- SELF_CHECK (cache.saved_regs[i].addr () == -20);
- else if (i == AARCH64_FP_REGNUM)
- SELF_CHECK (cache.saved_regs[i].addr () == -48);
- else if (i == AARCH64_LR_REGNUM)
- SELF_CHECK (cache.saved_regs[i].addr () == -40);
- else
- SELF_CHECK (cache.saved_regs[i].is_realreg ()
- && cache.saved_regs[i].realreg () == i);
- }
- }
- }
- } // namespace selftests
- #endif /* GDB_SELF_TEST */
- /* Implement the "skip_prologue" gdbarch method. */
- static CORE_ADDR
- aarch64_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);
- if (post_prologue_pc != 0)
- return std::max (pc, 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. */
- limit_pc = skip_prologue_using_sal (gdbarch, pc);
- if (limit_pc == 0)
- limit_pc = pc + 128; /* Magic. */
- /* Try disassembling prologue. */
- return aarch64_analyze_prologue (gdbarch, pc, limit_pc, NULL);
- }
- /* Scan the function prologue for THIS_FRAME and populate the prologue
- cache CACHE. */
- static void
- aarch64_scan_prologue (struct frame_info *this_frame,
- struct aarch64_prologue_cache *cache)
- {
- CORE_ADDR block_addr = get_frame_address_in_block (this_frame);
- CORE_ADDR prologue_start;
- CORE_ADDR prologue_end;
- CORE_ADDR prev_pc = get_frame_pc (this_frame);
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- cache->prev_pc = prev_pc;
- /* Assume we do not find a frame. */
- cache->framereg = -1;
- cache->framesize = 0;
- if (find_pc_partial_function (block_addr, NULL, &prologue_start,
- &prologue_end))
- {
- struct symtab_and_line sal = find_pc_line (prologue_start, 0);
- if (sal.line == 0)
- {
- /* No line info so use the current PC. */
- prologue_end = prev_pc;
- }
- else if (sal.end < prologue_end)
- {
- /* The next line begins after the function end. */
- prologue_end = sal.end;
- }
- prologue_end = std::min (prologue_end, prev_pc);
- aarch64_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
- }
- else
- {
- CORE_ADDR frame_loc;
- frame_loc = get_frame_register_unsigned (this_frame, AARCH64_FP_REGNUM);
- if (frame_loc == 0)
- return;
- cache->framereg = AARCH64_FP_REGNUM;
- cache->framesize = 16;
- cache->saved_regs[29].set_addr (0);
- cache->saved_regs[30].set_addr (8);
- }
- }
- /* Fill in *CACHE with information about the prologue of *THIS_FRAME. This
- function may throw an exception if the inferior's registers or memory is
- not available. */
- static void
- aarch64_make_prologue_cache_1 (struct frame_info *this_frame,
- struct aarch64_prologue_cache *cache)
- {
- CORE_ADDR unwound_fp;
- int reg;
- aarch64_scan_prologue (this_frame, cache);
- if (cache->framereg == -1)
- return;
- unwound_fp = get_frame_register_unsigned (this_frame, cache->framereg);
- if (unwound_fp == 0)
- return;
- cache->prev_sp = unwound_fp + cache->framesize;
- /* Calculate actual addresses of saved registers using offsets
- determined by aarch64_analyze_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);
- cache->func = get_frame_func (this_frame);
- cache->available_p = 1;
- }
- /* Allocate and fill in *THIS_CACHE with information about the prologue of
- *THIS_FRAME. Do not do this is if *THIS_CACHE was already allocated.
- Return a pointer to the current aarch64_prologue_cache in
- *THIS_CACHE. */
- static struct aarch64_prologue_cache *
- aarch64_make_prologue_cache (struct frame_info *this_frame, void **this_cache)
- {
- struct aarch64_prologue_cache *cache;
- if (*this_cache != NULL)
- return (struct aarch64_prologue_cache *) *this_cache;
- cache = FRAME_OBSTACK_ZALLOC (struct aarch64_prologue_cache);
- cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
- *this_cache = cache;
- try
- {
- aarch64_make_prologue_cache_1 (this_frame, cache);
- }
- catch (const gdb_exception_error &ex)
- {
- if (ex.error != NOT_AVAILABLE_ERROR)
- throw;
- }
- return cache;
- }
- /* Implement the "stop_reason" frame_unwind method. */
- static enum unwind_stop_reason
- aarch64_prologue_frame_unwind_stop_reason (struct frame_info *this_frame,
- void **this_cache)
- {
- struct aarch64_prologue_cache *cache
- = aarch64_make_prologue_cache (this_frame, this_cache);
- if (!cache->available_p)
- return UNWIND_UNAVAILABLE;
- /* Halt the backtrace at "_start". */
- gdbarch *arch = get_frame_arch (this_frame);
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (arch);
- if (cache->prev_pc <= tdep->lowest_pc)
- return UNWIND_OUTERMOST;
- /* 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
- aarch64_prologue_this_id (struct frame_info *this_frame,
- void **this_cache, struct frame_id *this_id)
- {
- struct aarch64_prologue_cache *cache
- = aarch64_make_prologue_cache (this_frame, this_cache);
- if (!cache->available_p)
- *this_id = frame_id_build_unavailable_stack (cache->func);
- else
- *this_id = frame_id_build (cache->prev_sp, cache->func);
- }
- /* Implement the "prev_register" frame_unwind method. */
- static struct value *
- aarch64_prologue_prev_register (struct frame_info *this_frame,
- void **this_cache, int prev_regnum)
- {
- struct aarch64_prologue_cache *cache
- = aarch64_make_prologue_cache (this_frame, this_cache);
- /* 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. */
- if (prev_regnum == AARCH64_PC_REGNUM)
- {
- CORE_ADDR lr;
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- aarch64_gdbarch_tdep *tdep
- = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- lr = frame_unwind_register_unsigned (this_frame, AARCH64_LR_REGNUM);
- if (tdep->has_pauth ()
- && cache->saved_regs[tdep->pauth_ra_state_regnum].is_value ())
- lr = aarch64_frame_unmask_lr (tdep, this_frame, lr);
- return frame_unwind_got_constant (this_frame, prev_regnum, 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. */
- /*
- +----------+ ^
- | saved lr | |
- +->| saved fp |--+
- | | |
- | | | <- Previous SP
- | +----------+
- | | saved lr |
- +--| saved fp |<- FP
- | |
- | |<- SP
- +----------+ */
- if (prev_regnum == AARCH64_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);
- }
- /* AArch64 prologue unwinder. */
- static frame_unwind aarch64_prologue_unwind =
- {
- "aarch64 prologue",
- NORMAL_FRAME,
- aarch64_prologue_frame_unwind_stop_reason,
- aarch64_prologue_this_id,
- aarch64_prologue_prev_register,
- NULL,
- default_frame_sniffer
- };
- /* Allocate and fill in *THIS_CACHE with information about the prologue of
- *THIS_FRAME. Do not do this is if *THIS_CACHE was already allocated.
- Return a pointer to the current aarch64_prologue_cache in
- *THIS_CACHE. */
- static struct aarch64_prologue_cache *
- aarch64_make_stub_cache (struct frame_info *this_frame, void **this_cache)
- {
- struct aarch64_prologue_cache *cache;
- if (*this_cache != NULL)
- return (struct aarch64_prologue_cache *) *this_cache;
- cache = FRAME_OBSTACK_ZALLOC (struct aarch64_prologue_cache);
- cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
- *this_cache = cache;
- try
- {
- cache->prev_sp = get_frame_register_unsigned (this_frame,
- AARCH64_SP_REGNUM);
- cache->prev_pc = get_frame_pc (this_frame);
- cache->available_p = 1;
- }
- catch (const gdb_exception_error &ex)
- {
- if (ex.error != NOT_AVAILABLE_ERROR)
- throw;
- }
- return cache;
- }
- /* Implement the "stop_reason" frame_unwind method. */
- static enum unwind_stop_reason
- aarch64_stub_frame_unwind_stop_reason (struct frame_info *this_frame,
- void **this_cache)
- {
- struct aarch64_prologue_cache *cache
- = aarch64_make_stub_cache (this_frame, this_cache);
- if (!cache->available_p)
- return UNWIND_UNAVAILABLE;
- return UNWIND_NO_REASON;
- }
- /* Our frame ID for a stub frame is the current SP and LR. */
- static void
- aarch64_stub_this_id (struct frame_info *this_frame,
- void **this_cache, struct frame_id *this_id)
- {
- struct aarch64_prologue_cache *cache
- = aarch64_make_stub_cache (this_frame, this_cache);
- if (cache->available_p)
- *this_id = frame_id_build (cache->prev_sp, cache->prev_pc);
- else
- *this_id = frame_id_build_unavailable_stack (cache->prev_pc);
- }
- /* Implement the "sniffer" frame_unwind method. */
- static int
- aarch64_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];
- addr_in_block = get_frame_address_in_block (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 (get_frame_pc (this_frame), dummy, 4) != 0)
- return 1;
- return 0;
- }
- /* AArch64 stub unwinder. */
- static frame_unwind aarch64_stub_unwind =
- {
- "aarch64 stub",
- NORMAL_FRAME,
- aarch64_stub_frame_unwind_stop_reason,
- aarch64_stub_this_id,
- aarch64_prologue_prev_register,
- NULL,
- aarch64_stub_unwind_sniffer
- };
- /* Return the frame base address of *THIS_FRAME. */
- static CORE_ADDR
- aarch64_normal_frame_base (struct frame_info *this_frame, void **this_cache)
- {
- struct aarch64_prologue_cache *cache
- = aarch64_make_prologue_cache (this_frame, this_cache);
- return cache->prev_sp - cache->framesize;
- }
- /* AArch64 default frame base information. */
- static frame_base aarch64_normal_base =
- {
- &aarch64_prologue_unwind,
- aarch64_normal_frame_base,
- aarch64_normal_frame_base,
- aarch64_normal_frame_base
- };
- /* Return the value of the REGNUM register in the previous frame of
- *THIS_FRAME. */
- static struct value *
- aarch64_dwarf2_prev_register (struct frame_info *this_frame,
- void **this_cache, int regnum)
- {
- gdbarch *arch = get_frame_arch (this_frame);
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (arch);
- CORE_ADDR lr;
- switch (regnum)
- {
- case AARCH64_PC_REGNUM:
- lr = frame_unwind_register_unsigned (this_frame, AARCH64_LR_REGNUM);
- lr = aarch64_frame_unmask_lr (tdep, this_frame, lr);
- return frame_unwind_got_constant (this_frame, regnum, lr);
- default:
- internal_error (__FILE__, __LINE__,
- _("Unexpected register %d"), regnum);
- }
- }
- static const unsigned char op_lit0 = DW_OP_lit0;
- static const unsigned char op_lit1 = DW_OP_lit1;
- /* Implement the "init_reg" dwarf2_frame_ops method. */
- static void
- aarch64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg,
- struct frame_info *this_frame)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- switch (regnum)
- {
- case AARCH64_PC_REGNUM:
- reg->how = DWARF2_FRAME_REG_FN;
- reg->loc.fn = aarch64_dwarf2_prev_register;
- return;
- case AARCH64_SP_REGNUM:
- reg->how = DWARF2_FRAME_REG_CFA;
- return;
- }
- /* Init pauth registers. */
- if (tdep->has_pauth ())
- {
- if (regnum == tdep->pauth_ra_state_regnum)
- {
- /* Initialize RA_STATE to zero. */
- reg->how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
- reg->loc.exp.start = &op_lit0;
- reg->loc.exp.len = 1;
- return;
- }
- else if (regnum == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
- || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base))
- {
- reg->how = DWARF2_FRAME_REG_SAME_VALUE;
- return;
- }
- }
- }
- /* Implement the execute_dwarf_cfa_vendor_op method. */
- static bool
- aarch64_execute_dwarf_cfa_vendor_op (struct gdbarch *gdbarch, gdb_byte op,
- struct dwarf2_frame_state *fs)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- struct dwarf2_frame_state_reg *ra_state;
- if (op == DW_CFA_AARCH64_negate_ra_state)
- {
- /* On systems without pauth, treat as a nop. */
- if (!tdep->has_pauth ())
- return true;
- /* Allocate RA_STATE column if it's not allocated yet. */
- fs->regs.alloc_regs (AARCH64_DWARF_PAUTH_RA_STATE + 1);
- /* Toggle the status of RA_STATE between 0 and 1. */
- ra_state = &(fs->regs.reg[AARCH64_DWARF_PAUTH_RA_STATE]);
- ra_state->how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
- if (ra_state->loc.exp.start == nullptr
- || ra_state->loc.exp.start == &op_lit0)
- ra_state->loc.exp.start = &op_lit1;
- else
- ra_state->loc.exp.start = &op_lit0;
- ra_state->loc.exp.len = 1;
- return true;
- }
- return false;
- }
- /* Used for matching BRK instructions for AArch64. */
- static constexpr uint32_t BRK_INSN_MASK = 0xffe0001f;
- static constexpr uint32_t BRK_INSN_BASE = 0xd4200000;
- /* Implementation of gdbarch_program_breakpoint_here_p for aarch64. */
- static bool
- aarch64_program_breakpoint_here_p (gdbarch *gdbarch, CORE_ADDR address)
- {
- const uint32_t insn_len = 4;
- gdb_byte target_mem[4];
- /* Enable the automatic memory restoration from breakpoints while
- we read the memory. Otherwise we may find temporary breakpoints, ones
- inserted by GDB, and flag them as permanent breakpoints. */
- scoped_restore restore_memory
- = make_scoped_restore_show_memory_breakpoints (0);
- if (target_read_memory (address, target_mem, insn_len) == 0)
- {
- uint32_t insn =
- (uint32_t) extract_unsigned_integer (target_mem, insn_len,
- gdbarch_byte_order_for_code (gdbarch));
- /* Check if INSN is a BRK instruction pattern. There are multiple choices
- of such instructions with different immediate values. Different OS'
- may use a different variation, but they have the same outcome. */
- return ((insn & BRK_INSN_MASK) == BRK_INSN_BASE);
- }
- return false;
- }
- /* 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_t
- {
- /* Value to pass on stack. It can be NULL if this item is for stack
- padding. */
- const gdb_byte *data;
- /* Size in bytes of value to pass on stack. */
- int len;
- };
- /* Implement the gdbarch type alignment method, overrides the generic
- alignment algorithm for anything that is aarch64 specific. */
- static ULONGEST
- aarch64_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 128-bit. */
- if (TYPE_LENGTH (t) > 16)
- return 16;
- else
- return TYPE_LENGTH (t);
- }
- /* Allow the common code to calculate the alignment. */
- return 0;
- }
- /* Worker function for aapcs_is_vfp_call_or_return_candidate.
- Return the number of register required, or -1 on failure.
- When encountering a base element, if FUNDAMENTAL_TYPE is not set then set it
- to the element, else fail if the type of this element does not match the
- existing value. */
- static int
- aapcs_is_vfp_call_or_return_candidate_1 (struct type *type,
- struct type **fundamental_type)
- {
- if (type == nullptr)
- return -1;
- switch (type->code ())
- {
- case TYPE_CODE_FLT:
- if (TYPE_LENGTH (type) > 16)
- return -1;
- if (*fundamental_type == nullptr)
- *fundamental_type = type;
- else if (TYPE_LENGTH (type) != TYPE_LENGTH (*fundamental_type)
- || type->code () != (*fundamental_type)->code ())
- return -1;
- return 1;
- case TYPE_CODE_COMPLEX:
- {
- struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
- if (TYPE_LENGTH (target_type) > 16)
- return -1;
- if (*fundamental_type == nullptr)
- *fundamental_type = target_type;
- else if (TYPE_LENGTH (target_type) != TYPE_LENGTH (*fundamental_type)
- || target_type->code () != (*fundamental_type)->code ())
- return -1;
- return 2;
- }
- case TYPE_CODE_ARRAY:
- {
- if (type->is_vector ())
- {
- if (TYPE_LENGTH (type) != 8 && TYPE_LENGTH (type) != 16)
- return -1;
- if (*fundamental_type == nullptr)
- *fundamental_type = type;
- else if (TYPE_LENGTH (type) != TYPE_LENGTH (*fundamental_type)
- || type->code () != (*fundamental_type)->code ())
- return -1;
- return 1;
- }
- else
- {
- struct type *target_type = TYPE_TARGET_TYPE (type);
- int count = aapcs_is_vfp_call_or_return_candidate_1
- (target_type, fundamental_type);
- if (count == -1)
- return count;
- count *= (TYPE_LENGTH (type) / TYPE_LENGTH (target_type));
- return count;
- }
- }
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- {
- int count = 0;
- for (int i = 0; i < type->num_fields (); i++)
- {
- /* Ignore any static fields. */
- if (field_is_static (&type->field (i)))
- continue;
- struct type *member = check_typedef (type->field (i).type ());
- int sub_count = aapcs_is_vfp_call_or_return_candidate_1
- (member, fundamental_type);
- if (sub_count == -1)
- return -1;
- count += sub_count;
- }
- /* Ensure there is no padding between the fields (allowing for empty
- zero length structs) */
- int ftype_length = (*fundamental_type == nullptr)
- ? 0 : TYPE_LENGTH (*fundamental_type);
- if (count * ftype_length != TYPE_LENGTH (type))
- return -1;
- return count;
- }
- default:
- break;
- }
- return -1;
- }
- /* Return true if an argument, whose type is described by TYPE, can be passed or
- returned in simd/fp registers, providing enough parameter passing registers
- are available. This is as described in the AAPCS64.
- Upon successful return, *COUNT returns the number of needed registers,
- *FUNDAMENTAL_TYPE contains the type of those registers.
- Candidate as per the AAPCS64 5.4.2.C is either a:
- - float.
- - short-vector.
- - HFA (Homogeneous Floating-point Aggregate, 4.3.5.1). A Composite type where
- all the members are floats and has at most 4 members.
- - HVA (Homogeneous Short-vector Aggregate, 4.3.5.2). A Composite type where
- all the members are short vectors and has at most 4 members.
- - Complex (7.1.1)
- Note that HFAs and HVAs can include nested structures and arrays. */
- static bool
- aapcs_is_vfp_call_or_return_candidate (struct type *type, int *count,
- struct type **fundamental_type)
- {
- if (type == nullptr)
- return false;
- *fundamental_type = nullptr;
- int ag_count = aapcs_is_vfp_call_or_return_candidate_1 (type,
- fundamental_type);
- if (ag_count > 0 && ag_count <= HA_MAX_NUM_FLDS)
- {
- *count = ag_count;
- return true;
- }
- else
- return false;
- }
- /* AArch64 function call information structure. */
- struct aarch64_call_info
- {
- /* the current argument number. */
- unsigned argnum = 0;
- /* The next general purpose register number, equivalent to NGRN as
- described in the AArch64 Procedure Call Standard. */
- unsigned ngrn = 0;
- /* The next SIMD and floating point register number, equivalent to
- NSRN as described in the AArch64 Procedure Call Standard. */
- unsigned nsrn = 0;
- /* The next stacked argument address, equivalent to NSAA as
- described in the AArch64 Procedure Call Standard. */
- unsigned nsaa = 0;
- /* Stack item vector. */
- std::vector<stack_item_t> si;
- };
- /* Pass a value in a sequence of consecutive X registers. The caller
- is responsible for ensuring sufficient registers are available. */
- static void
- pass_in_x (struct gdbarch *gdbarch, struct regcache *regcache,
- struct aarch64_call_info *info, struct type *type,
- struct value *arg)
- {
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- int len = TYPE_LENGTH (type);
- enum type_code typecode = type->code ();
- int regnum = AARCH64_X0_REGNUM + info->ngrn;
- const bfd_byte *buf = value_contents (arg).data ();
- info->argnum++;
- while (len > 0)
- {
- int partial_len = len < X_REGISTER_SIZE ? len : X_REGISTER_SIZE;
- CORE_ADDR regval = extract_unsigned_integer (buf, partial_len,
- byte_order);
- /* Adjust sub-word struct/union args when big-endian. */
- if (byte_order == BFD_ENDIAN_BIG
- && partial_len < X_REGISTER_SIZE
- && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
- regval <<= ((X_REGISTER_SIZE - partial_len) * TARGET_CHAR_BIT);
- aarch64_debug_printf ("arg %d in %s = 0x%s", info->argnum,
- gdbarch_register_name (gdbarch, regnum),
- phex (regval, X_REGISTER_SIZE));
- regcache_cooked_write_unsigned (regcache, regnum, regval);
- len -= partial_len;
- buf += partial_len;
- regnum++;
- }
- }
- /* Attempt to marshall a value in a V register. Return 1 if
- successful, or 0 if insufficient registers are available. This
- function, unlike the equivalent pass_in_x() function does not
- handle arguments spread across multiple registers. */
- static int
- pass_in_v (struct gdbarch *gdbarch,
- struct regcache *regcache,
- struct aarch64_call_info *info,
- int len, const bfd_byte *buf)
- {
- if (info->nsrn < 8)
- {
- int regnum = AARCH64_V0_REGNUM + info->nsrn;
- /* Enough space for a full vector register. */
- gdb_byte reg[register_size (gdbarch, regnum)];
- gdb_assert (len <= sizeof (reg));
- info->argnum++;
- info->nsrn++;
- memset (reg, 0, sizeof (reg));
- /* PCS C.1, the argument is allocated to the least significant
- bits of V register. */
- memcpy (reg, buf, len);
- regcache->cooked_write (regnum, reg);
- aarch64_debug_printf ("arg %d in %s", info->argnum,
- gdbarch_register_name (gdbarch, regnum));
- return 1;
- }
- info->nsrn = 8;
- return 0;
- }
- /* Marshall an argument onto the stack. */
- static void
- pass_on_stack (struct aarch64_call_info *info, struct type *type,
- struct value *arg)
- {
- const bfd_byte *buf = value_contents (arg).data ();
- int len = TYPE_LENGTH (type);
- int align;
- stack_item_t item;
- info->argnum++;
- align = type_align (type);
- /* PCS C.17 Stack should be aligned to the larger of 8 bytes or the
- Natural alignment of the argument's type. */
- align = align_up (align, 8);
- /* The AArch64 PCS requires at most doubleword alignment. */
- if (align > 16)
- align = 16;
- aarch64_debug_printf ("arg %d len=%d @ sp + %d\n", info->argnum, len,
- info->nsaa);
- item.len = len;
- item.data = buf;
- info->si.push_back (item);
- info->nsaa += len;
- if (info->nsaa & (align - 1))
- {
- /* Push stack alignment padding. */
- int pad = align - (info->nsaa & (align - 1));
- item.len = pad;
- item.data = NULL;
- info->si.push_back (item);
- info->nsaa += pad;
- }
- }
- /* Marshall an argument into a sequence of one or more consecutive X
- registers or, if insufficient X registers are available then onto
- the stack. */
- static void
- pass_in_x_or_stack (struct gdbarch *gdbarch, struct regcache *regcache,
- struct aarch64_call_info *info, struct type *type,
- struct value *arg)
- {
- int len = TYPE_LENGTH (type);
- int nregs = (len + X_REGISTER_SIZE - 1) / X_REGISTER_SIZE;
- /* PCS C.13 - Pass in registers if we have enough spare */
- if (info->ngrn + nregs <= 8)
- {
- pass_in_x (gdbarch, regcache, info, type, arg);
- info->ngrn += nregs;
- }
- else
- {
- info->ngrn = 8;
- pass_on_stack (info, type, arg);
- }
- }
- /* Pass a value, which is of type arg_type, in a V register. Assumes value is a
- aapcs_is_vfp_call_or_return_candidate and there are enough spare V
- registers. A return value of false is an error state as the value will have
- been partially passed to the stack. */
- static bool
- pass_in_v_vfp_candidate (struct gdbarch *gdbarch, struct regcache *regcache,
- struct aarch64_call_info *info, struct type *arg_type,
- struct value *arg)
- {
- switch (arg_type->code ())
- {
- case TYPE_CODE_FLT:
- return pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (arg_type),
- value_contents (arg).data ());
- break;
- case TYPE_CODE_COMPLEX:
- {
- const bfd_byte *buf = value_contents (arg).data ();
- struct type *target_type = check_typedef (TYPE_TARGET_TYPE (arg_type));
- if (!pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (target_type),
- buf))
- return false;
- return pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (target_type),
- buf + TYPE_LENGTH (target_type));
- }
- case TYPE_CODE_ARRAY:
- if (arg_type->is_vector ())
- return pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (arg_type),
- value_contents (arg).data ());
- /* fall through. */
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- for (int i = 0; i < arg_type->num_fields (); i++)
- {
- /* Don't include static fields. */
- if (field_is_static (&arg_type->field (i)))
- continue;
- struct value *field = value_primitive_field (arg, 0, i, arg_type);
- struct type *field_type = check_typedef (value_type (field));
- if (!pass_in_v_vfp_candidate (gdbarch, regcache, info, field_type,
- field))
- return false;
- }
- return true;
- default:
- return false;
- }
- }
- /* Implement the "push_dummy_call" gdbarch method. */
- static CORE_ADDR
- aarch64_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)
- {
- int argnum;
- struct aarch64_call_info info;
- /* We need to know what the type of the called function is in order
- to determine the number of named/anonymous arguments for the
- actual argument placement, and the return type in order to handle
- return value correctly.
- The generic code above us views the decision of return in memory
- or return in registers as a two stage processes. The language
- handler is consulted first and may decide to return in memory (eg
- class with copy constructor returned by value), this will cause
- the generic code to allocate space AND insert an initial leading
- argument.
- If the language code does not decide to pass in memory then the
- target code is consulted.
- If the language code decides to pass in memory we want to move
- the pointer inserted as the initial argument from the argument
- list and into X8, the conventional AArch64 struct return pointer
- register. */
- /* Set the return address. For the AArch64, the return breakpoint
- is always at BP_ADDR. */
- regcache_cooked_write_unsigned (regcache, AARCH64_LR_REGNUM, bp_addr);
- /* If we were given an initial argument for the return slot, lose it. */
- if (return_method == return_method_hidden_param)
- {
- args++;
- nargs--;
- }
- /* The struct_return pointer occupies X8. */
- if (return_method != return_method_normal)
- {
- aarch64_debug_printf ("struct return in %s = 0x%s",
- gdbarch_register_name
- (gdbarch, AARCH64_STRUCT_RETURN_REGNUM),
- paddress (gdbarch, struct_addr));
- regcache_cooked_write_unsigned (regcache, AARCH64_STRUCT_RETURN_REGNUM,
- struct_addr);
- }
- for (argnum = 0; argnum < nargs; argnum++)
- {
- struct value *arg = args[argnum];
- struct type *arg_type, *fundamental_type;
- int len, elements;
- arg_type = check_typedef (value_type (arg));
- len = TYPE_LENGTH (arg_type);
- /* If arg can be passed in v registers as per the AAPCS64, then do so if
- if there are enough spare registers. */
- if (aapcs_is_vfp_call_or_return_candidate (arg_type, &elements,
- &fundamental_type))
- {
- if (info.nsrn + elements <= 8)
- {
- /* We know that we have sufficient registers available therefore
- this will never need to fallback to the stack. */
- if (!pass_in_v_vfp_candidate (gdbarch, regcache, &info, arg_type,
- arg))
- gdb_assert_not_reached ("Failed to push args");
- }
- else
- {
- info.nsrn = 8;
- pass_on_stack (&info, arg_type, arg);
- }
- continue;
- }
- switch (arg_type->code ())
- {
- case TYPE_CODE_INT:
- case TYPE_CODE_BOOL:
- case TYPE_CODE_CHAR:
- case TYPE_CODE_RANGE:
- case TYPE_CODE_ENUM:
- if (len < 4 && !is_fixed_point_type (arg_type))
- {
- /* Promote to 32 bit integer. */
- if (arg_type->is_unsigned ())
- arg_type = builtin_type (gdbarch)->builtin_uint32;
- else
- arg_type = builtin_type (gdbarch)->builtin_int32;
- arg = value_cast (arg_type, arg);
- }
- pass_in_x_or_stack (gdbarch, regcache, &info, arg_type, arg);
- break;
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_ARRAY:
- case TYPE_CODE_UNION:
- if (len > 16)
- {
- /* PCS B.7 Aggregates larger than 16 bytes are passed by
- invisible reference. */
- /* Allocate aligned storage. */
- sp = align_down (sp - len, 16);
- /* Write the real data into the stack. */
- write_memory (sp, value_contents (arg).data (), len);
- /* Construct the indirection. */
- arg_type = lookup_pointer_type (arg_type);
- arg = value_from_pointer (arg_type, sp);
- pass_in_x_or_stack (gdbarch, regcache, &info, arg_type, arg);
- }
- else
- /* PCS C.15 / C.18 multiple values pass. */
- pass_in_x_or_stack (gdbarch, regcache, &info, arg_type, arg);
- break;
- default:
- pass_in_x_or_stack (gdbarch, regcache, &info, arg_type, arg);
- break;
- }
- }
- /* Make sure stack retains 16 byte alignment. */
- if (info.nsaa & 15)
- sp -= 16 - (info.nsaa & 15);
- while (!info.si.empty ())
- {
- const stack_item_t &si = info.si.back ();
- sp -= si.len;
- if (si.data != NULL)
- write_memory (sp, si.data, si.len);
- info.si.pop_back ();
- }
- /* Finally, update the SP register. */
- regcache_cooked_write_unsigned (regcache, AARCH64_SP_REGNUM, sp);
- return sp;
- }
- /* Implement the "frame_align" gdbarch method. */
- static CORE_ADDR
- aarch64_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
- {
- /* Align the stack to sixteen bytes. */
- return sp & ~(CORE_ADDR) 15;
- }
- /* Return the type for an AdvSISD Q register. */
- static struct type *
- aarch64_vnq_type (struct gdbarch *gdbarch)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->vnq_type == NULL)
- {
- struct type *t;
- struct type *elem;
- t = arch_composite_type (gdbarch, "__gdb_builtin_type_vnq",
- TYPE_CODE_UNION);
- elem = builtin_type (gdbarch)->builtin_uint128;
- append_composite_type_field (t, "u", elem);
- elem = builtin_type (gdbarch)->builtin_int128;
- append_composite_type_field (t, "s", elem);
- tdep->vnq_type = t;
- }
- return tdep->vnq_type;
- }
- /* Return the type for an AdvSISD D register. */
- static struct type *
- aarch64_vnd_type (struct gdbarch *gdbarch)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->vnd_type == NULL)
- {
- struct type *t;
- struct type *elem;
- t = arch_composite_type (gdbarch, "__gdb_builtin_type_vnd",
- TYPE_CODE_UNION);
- elem = builtin_type (gdbarch)->builtin_double;
- append_composite_type_field (t, "f", elem);
- elem = builtin_type (gdbarch)->builtin_uint64;
- append_composite_type_field (t, "u", elem);
- elem = builtin_type (gdbarch)->builtin_int64;
- append_composite_type_field (t, "s", elem);
- tdep->vnd_type = t;
- }
- return tdep->vnd_type;
- }
- /* Return the type for an AdvSISD S register. */
- static struct type *
- aarch64_vns_type (struct gdbarch *gdbarch)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->vns_type == NULL)
- {
- struct type *t;
- struct type *elem;
- t = arch_composite_type (gdbarch, "__gdb_builtin_type_vns",
- TYPE_CODE_UNION);
- elem = builtin_type (gdbarch)->builtin_float;
- append_composite_type_field (t, "f", elem);
- elem = builtin_type (gdbarch)->builtin_uint32;
- append_composite_type_field (t, "u", elem);
- elem = builtin_type (gdbarch)->builtin_int32;
- append_composite_type_field (t, "s", elem);
- tdep->vns_type = t;
- }
- return tdep->vns_type;
- }
- /* Return the type for an AdvSISD H register. */
- static struct type *
- aarch64_vnh_type (struct gdbarch *gdbarch)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->vnh_type == NULL)
- {
- struct type *t;
- struct type *elem;
- t = arch_composite_type (gdbarch, "__gdb_builtin_type_vnh",
- TYPE_CODE_UNION);
- elem = builtin_type (gdbarch)->builtin_bfloat16;
- append_composite_type_field (t, "bf", elem);
- elem = builtin_type (gdbarch)->builtin_half;
- append_composite_type_field (t, "f", elem);
- elem = builtin_type (gdbarch)->builtin_uint16;
- append_composite_type_field (t, "u", elem);
- elem = builtin_type (gdbarch)->builtin_int16;
- append_composite_type_field (t, "s", elem);
- tdep->vnh_type = t;
- }
- return tdep->vnh_type;
- }
- /* Return the type for an AdvSISD B register. */
- static struct type *
- aarch64_vnb_type (struct gdbarch *gdbarch)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->vnb_type == NULL)
- {
- struct type *t;
- struct type *elem;
- t = arch_composite_type (gdbarch, "__gdb_builtin_type_vnb",
- TYPE_CODE_UNION);
- elem = builtin_type (gdbarch)->builtin_uint8;
- append_composite_type_field (t, "u", elem);
- elem = builtin_type (gdbarch)->builtin_int8;
- append_composite_type_field (t, "s", elem);
- tdep->vnb_type = t;
- }
- return tdep->vnb_type;
- }
- /* Return the type for an AdvSISD V register. */
- static struct type *
- aarch64_vnv_type (struct gdbarch *gdbarch)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->vnv_type == NULL)
- {
- /* The other AArch64 pseudo registers (Q,D,H,S,B) refer to a single value
- slice from the non-pseudo vector registers. However NEON V registers
- are always vector registers, and need constructing as such. */
- const struct builtin_type *bt = builtin_type (gdbarch);
- struct type *t = arch_composite_type (gdbarch, "__gdb_builtin_type_vnv",
- TYPE_CODE_UNION);
- struct type *sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnd",
- TYPE_CODE_UNION);
- append_composite_type_field (sub, "f",
- init_vector_type (bt->builtin_double, 2));
- append_composite_type_field (sub, "u",
- init_vector_type (bt->builtin_uint64, 2));
- append_composite_type_field (sub, "s",
- init_vector_type (bt->builtin_int64, 2));
- append_composite_type_field (t, "d", sub);
- sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vns",
- TYPE_CODE_UNION);
- append_composite_type_field (sub, "f",
- init_vector_type (bt->builtin_float, 4));
- append_composite_type_field (sub, "u",
- init_vector_type (bt->builtin_uint32, 4));
- append_composite_type_field (sub, "s",
- init_vector_type (bt->builtin_int32, 4));
- append_composite_type_field (t, "s", sub);
- sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnh",
- TYPE_CODE_UNION);
- append_composite_type_field (sub, "bf",
- init_vector_type (bt->builtin_bfloat16, 8));
- append_composite_type_field (sub, "f",
- init_vector_type (bt->builtin_half, 8));
- append_composite_type_field (sub, "u",
- init_vector_type (bt->builtin_uint16, 8));
- append_composite_type_field (sub, "s",
- init_vector_type (bt->builtin_int16, 8));
- append_composite_type_field (t, "h", sub);
- sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnb",
- TYPE_CODE_UNION);
- append_composite_type_field (sub, "u",
- init_vector_type (bt->builtin_uint8, 16));
- append_composite_type_field (sub, "s",
- init_vector_type (bt->builtin_int8, 16));
- append_composite_type_field (t, "b", sub);
- sub = arch_composite_type (gdbarch, "__gdb_builtin_type_vnq",
- TYPE_CODE_UNION);
- append_composite_type_field (sub, "u",
- init_vector_type (bt->builtin_uint128, 1));
- append_composite_type_field (sub, "s",
- init_vector_type (bt->builtin_int128, 1));
- append_composite_type_field (t, "q", sub);
- tdep->vnv_type = t;
- }
- return tdep->vnv_type;
- }
- /* Implement the "dwarf2_reg_to_regnum" gdbarch method. */
- static int
- aarch64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (reg >= AARCH64_DWARF_X0 && reg <= AARCH64_DWARF_X0 + 30)
- return AARCH64_X0_REGNUM + reg - AARCH64_DWARF_X0;
- if (reg == AARCH64_DWARF_SP)
- return AARCH64_SP_REGNUM;
- if (reg >= AARCH64_DWARF_V0 && reg <= AARCH64_DWARF_V0 + 31)
- return AARCH64_V0_REGNUM + reg - AARCH64_DWARF_V0;
- if (reg == AARCH64_DWARF_SVE_VG)
- return AARCH64_SVE_VG_REGNUM;
- if (reg == AARCH64_DWARF_SVE_FFR)
- return AARCH64_SVE_FFR_REGNUM;
- if (reg >= AARCH64_DWARF_SVE_P0 && reg <= AARCH64_DWARF_SVE_P0 + 15)
- return AARCH64_SVE_P0_REGNUM + reg - AARCH64_DWARF_SVE_P0;
- if (reg >= AARCH64_DWARF_SVE_Z0 && reg <= AARCH64_DWARF_SVE_Z0 + 15)
- return AARCH64_SVE_Z0_REGNUM + reg - AARCH64_DWARF_SVE_Z0;
- if (tdep->has_pauth ())
- {
- if (reg >= AARCH64_DWARF_PAUTH_DMASK && reg <= AARCH64_DWARF_PAUTH_CMASK)
- return tdep->pauth_reg_base + reg - AARCH64_DWARF_PAUTH_DMASK;
- if (reg == AARCH64_DWARF_PAUTH_RA_STATE)
- return tdep->pauth_ra_state_regnum;
- }
- return -1;
- }
- /* Implement the "print_insn" gdbarch method. */
- static int
- aarch64_gdb_print_insn (bfd_vma memaddr, disassemble_info *info)
- {
- info->symbols = NULL;
- return default_print_insn (memaddr, info);
- }
- /* AArch64 BRK software debug mode instruction.
- Note that AArch64 code is always little-endian.
- 1101.0100.0010.0000.0000.0000.0000.0000 = 0xd4200000. */
- constexpr gdb_byte aarch64_default_breakpoint[] = {0x00, 0x00, 0x20, 0xd4};
- typedef BP_MANIPULATION (aarch64_default_breakpoint) aarch64_breakpoint;
- /* Extract from an array REGS containing the (raw) register state a
- function return value of type TYPE, and copy that, in virtual
- format, into VALBUF. */
- static void
- aarch64_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);
- int elements;
- struct type *fundamental_type;
- if (aapcs_is_vfp_call_or_return_candidate (type, &elements,
- &fundamental_type))
- {
- int len = TYPE_LENGTH (fundamental_type);
- for (int i = 0; i < elements; i++)
- {
- int regno = AARCH64_V0_REGNUM + i;
- /* Enough space for a full vector register. */
- gdb_byte buf[register_size (gdbarch, regno)];
- gdb_assert (len <= sizeof (buf));
- aarch64_debug_printf
- ("read HFA or HVA return value element %d from %s",
- i + 1, gdbarch_register_name (gdbarch, regno));
- regs->cooked_read (regno, buf);
- memcpy (valbuf, buf, len);
- valbuf += len;
- }
- }
- 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 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 = AARCH64_X0_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 > X_REGISTER_SIZE
- ? X_REGISTER_SIZE : len), byte_order, tmp);
- len -= X_REGISTER_SIZE;
- valbuf += X_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 64-bit load instruction(s). */
- int len = TYPE_LENGTH (type);
- int regno = AARCH64_X0_REGNUM;
- bfd_byte buf[X_REGISTER_SIZE];
- while (len > 0)
- {
- regs->cooked_read (regno++, buf);
- memcpy (valbuf, buf, len > X_REGISTER_SIZE ? X_REGISTER_SIZE : len);
- len -= X_REGISTER_SIZE;
- valbuf += X_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
- aarch64_return_in_memory (struct gdbarch *gdbarch, struct type *type)
- {
- type = check_typedef (type);
- int elements;
- struct type *fundamental_type;
- if (aapcs_is_vfp_call_or_return_candidate (type, &elements,
- &fundamental_type))
- {
- /* v0-v7 are used to return values and one register is allocated
- for one member. However, HFA or HVA has at most four members. */
- return 0;
- }
- if (TYPE_LENGTH (type) > 16
- || !language_pass_by_reference (type).trivially_copyable)
- {
- /* PCS B.6 Aggregates larger than 16 bytes are passed by
- invisible reference. */
- return 1;
- }
- return 0;
- }
- /* Write into appropriate registers a function return value of type
- TYPE, given in virtual format. */
- static void
- aarch64_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);
- int elements;
- struct type *fundamental_type;
- if (aapcs_is_vfp_call_or_return_candidate (type, &elements,
- &fundamental_type))
- {
- int len = TYPE_LENGTH (fundamental_type);
- for (int i = 0; i < elements; i++)
- {
- int regno = AARCH64_V0_REGNUM + i;
- /* Enough space for a full vector register. */
- gdb_byte tmpbuf[register_size (gdbarch, regno)];
- gdb_assert (len <= sizeof (tmpbuf));
- aarch64_debug_printf
- ("write HFA or HVA return value element %d to %s",
- i + 1, gdbarch_register_name (gdbarch, regno));
- memcpy (tmpbuf, valbuf,
- len > V_REGISTER_SIZE ? V_REGISTER_SIZE : len);
- regs->cooked_write (regno, tmpbuf);
- valbuf += len;
- }
- }
- 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) <= X_REGISTER_SIZE)
- {
- /* Values of one word or less are zero/sign-extended and
- returned in r0. */
- bfd_byte tmpbuf[X_REGISTER_SIZE];
- LONGEST val = unpack_long (type, valbuf);
- store_signed_integer (tmpbuf, X_REGISTER_SIZE, byte_order, val);
- regs->cooked_write (AARCH64_X0_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 = AARCH64_X0_REGNUM;
- while (len > 0)
- {
- regs->cooked_write (regno++, valbuf);
- len -= X_REGISTER_SIZE;
- valbuf += X_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 64-bit load instruction(s). */
- int len = TYPE_LENGTH (type);
- int regno = AARCH64_X0_REGNUM;
- bfd_byte tmpbuf[X_REGISTER_SIZE];
- while (len > 0)
- {
- memcpy (tmpbuf, valbuf,
- len > X_REGISTER_SIZE ? X_REGISTER_SIZE : len);
- regs->cooked_write (regno++, tmpbuf);
- len -= X_REGISTER_SIZE;
- valbuf += X_REGISTER_SIZE;
- }
- }
- }
- /* Implement the "return_value" gdbarch method. */
- static enum return_value_convention
- aarch64_return_value (struct gdbarch *gdbarch, struct value *func_value,
- struct type *valtype, struct regcache *regcache,
- gdb_byte *readbuf, const gdb_byte *writebuf)
- {
- if (valtype->code () == TYPE_CODE_STRUCT
- || valtype->code () == TYPE_CODE_UNION
- || valtype->code () == TYPE_CODE_ARRAY)
- {
- if (aarch64_return_in_memory (gdbarch, valtype))
- {
- /* From the AAPCS64's Result Return section:
- "Otherwise, the caller shall reserve a block of memory of
- sufficient size and alignment to hold the result. The address
- of the memory block shall be passed as an additional argument to
- the function in x8. */
- aarch64_debug_printf ("return value in memory");
- if (readbuf)
- {
- CORE_ADDR addr;
- regcache->cooked_read (AARCH64_STRUCT_RETURN_REGNUM, &addr);
- read_memory (addr, readbuf, TYPE_LENGTH (valtype));
- }
- return RETURN_VALUE_ABI_RETURNS_ADDRESS;
- }
- }
- if (writebuf)
- aarch64_store_return_value (valtype, regcache, writebuf);
- if (readbuf)
- aarch64_extract_return_value (valtype, regcache, readbuf);
- aarch64_debug_printf ("return value in registers");
- return RETURN_VALUE_REGISTER_CONVENTION;
- }
- /* Implement the "get_longjmp_target" gdbarch method. */
- static int
- aarch64_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
- {
- CORE_ADDR jb_addr;
- gdb_byte buf[X_REGISTER_SIZE];
- struct gdbarch *gdbarch = get_frame_arch (frame);
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- jb_addr = get_frame_register_unsigned (frame, AARCH64_X0_REGNUM);
- if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
- X_REGISTER_SIZE))
- return 0;
- *pc = extract_unsigned_integer (buf, X_REGISTER_SIZE, byte_order);
- return 1;
- }
- /* Implement the "gen_return_address" gdbarch method. */
- static void
- aarch64_gen_return_address (struct gdbarch *gdbarch,
- struct agent_expr *ax, struct axs_value *value,
- CORE_ADDR scope)
- {
- value->type = register_type (gdbarch, AARCH64_LR_REGNUM);
- value->kind = axs_lvalue_register;
- value->u.reg = AARCH64_LR_REGNUM;
- }
- /* Return the pseudo register name corresponding to register regnum. */
- static const char *
- aarch64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- static const char *const q_name[] =
- {
- "q0", "q1", "q2", "q3",
- "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11",
- "q12", "q13", "q14", "q15",
- "q16", "q17", "q18", "q19",
- "q20", "q21", "q22", "q23",
- "q24", "q25", "q26", "q27",
- "q28", "q29", "q30", "q31",
- };
- static const char *const d_name[] =
- {
- "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",
- };
- static const char *const s_name[] =
- {
- "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",
- };
- static const char *const h_name[] =
- {
- "h0", "h1", "h2", "h3",
- "h4", "h5", "h6", "h7",
- "h8", "h9", "h10", "h11",
- "h12", "h13", "h14", "h15",
- "h16", "h17", "h18", "h19",
- "h20", "h21", "h22", "h23",
- "h24", "h25", "h26", "h27",
- "h28", "h29", "h30", "h31",
- };
- static const char *const b_name[] =
- {
- "b0", "b1", "b2", "b3",
- "b4", "b5", "b6", "b7",
- "b8", "b9", "b10", "b11",
- "b12", "b13", "b14", "b15",
- "b16", "b17", "b18", "b19",
- "b20", "b21", "b22", "b23",
- "b24", "b25", "b26", "b27",
- "b28", "b29", "b30", "b31",
- };
- int p_regnum = regnum - gdbarch_num_regs (gdbarch);
- if (p_regnum >= AARCH64_Q0_REGNUM && p_regnum < AARCH64_Q0_REGNUM + 32)
- return q_name[p_regnum - AARCH64_Q0_REGNUM];
- if (p_regnum >= AARCH64_D0_REGNUM && p_regnum < AARCH64_D0_REGNUM + 32)
- return d_name[p_regnum - AARCH64_D0_REGNUM];
- if (p_regnum >= AARCH64_S0_REGNUM && p_regnum < AARCH64_S0_REGNUM + 32)
- return s_name[p_regnum - AARCH64_S0_REGNUM];
- if (p_regnum >= AARCH64_H0_REGNUM && p_regnum < AARCH64_H0_REGNUM + 32)
- return h_name[p_regnum - AARCH64_H0_REGNUM];
- if (p_regnum >= AARCH64_B0_REGNUM && p_regnum < AARCH64_B0_REGNUM + 32)
- return b_name[p_regnum - AARCH64_B0_REGNUM];
- if (tdep->has_sve ())
- {
- static const char *const sve_v_name[] =
- {
- "v0", "v1", "v2", "v3",
- "v4", "v5", "v6", "v7",
- "v8", "v9", "v10", "v11",
- "v12", "v13", "v14", "v15",
- "v16", "v17", "v18", "v19",
- "v20", "v21", "v22", "v23",
- "v24", "v25", "v26", "v27",
- "v28", "v29", "v30", "v31",
- };
- if (p_regnum >= AARCH64_SVE_V0_REGNUM
- && p_regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
- return sve_v_name[p_regnum - AARCH64_SVE_V0_REGNUM];
- }
- /* RA_STATE is used for unwinding only. Do not assign it a name - this
- prevents it from being read by methods such as
- mi_cmd_trace_frame_collected. */
- if (tdep->has_pauth () && regnum == tdep->pauth_ra_state_regnum)
- return "";
- internal_error (__FILE__, __LINE__,
- _("aarch64_pseudo_register_name: bad register number %d"),
- p_regnum);
- }
- /* Implement the "pseudo_register_type" tdesc_arch_data method. */
- static struct type *
- aarch64_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- int p_regnum = regnum - gdbarch_num_regs (gdbarch);
- if (p_regnum >= AARCH64_Q0_REGNUM && p_regnum < AARCH64_Q0_REGNUM + 32)
- return aarch64_vnq_type (gdbarch);
- if (p_regnum >= AARCH64_D0_REGNUM && p_regnum < AARCH64_D0_REGNUM + 32)
- return aarch64_vnd_type (gdbarch);
- if (p_regnum >= AARCH64_S0_REGNUM && p_regnum < AARCH64_S0_REGNUM + 32)
- return aarch64_vns_type (gdbarch);
- if (p_regnum >= AARCH64_H0_REGNUM && p_regnum < AARCH64_H0_REGNUM + 32)
- return aarch64_vnh_type (gdbarch);
- if (p_regnum >= AARCH64_B0_REGNUM && p_regnum < AARCH64_B0_REGNUM + 32)
- return aarch64_vnb_type (gdbarch);
- if (tdep->has_sve () && p_regnum >= AARCH64_SVE_V0_REGNUM
- && p_regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
- return aarch64_vnv_type (gdbarch);
- if (tdep->has_pauth () && regnum == tdep->pauth_ra_state_regnum)
- return builtin_type (gdbarch)->builtin_uint64;
- internal_error (__FILE__, __LINE__,
- _("aarch64_pseudo_register_type: bad register number %d"),
- p_regnum);
- }
- /* Implement the "pseudo_register_reggroup_p" tdesc_arch_data method. */
- static int
- aarch64_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
- const struct reggroup *group)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- int p_regnum = regnum - gdbarch_num_regs (gdbarch);
- if (p_regnum >= AARCH64_Q0_REGNUM && p_regnum < AARCH64_Q0_REGNUM + 32)
- return group == all_reggroup || group == vector_reggroup;
- else if (p_regnum >= AARCH64_D0_REGNUM && p_regnum < AARCH64_D0_REGNUM + 32)
- return (group == all_reggroup || group == vector_reggroup
- || group == float_reggroup);
- else if (p_regnum >= AARCH64_S0_REGNUM && p_regnum < AARCH64_S0_REGNUM + 32)
- return (group == all_reggroup || group == vector_reggroup
- || group == float_reggroup);
- else if (p_regnum >= AARCH64_H0_REGNUM && p_regnum < AARCH64_H0_REGNUM + 32)
- return group == all_reggroup || group == vector_reggroup;
- else if (p_regnum >= AARCH64_B0_REGNUM && p_regnum < AARCH64_B0_REGNUM + 32)
- return group == all_reggroup || group == vector_reggroup;
- else if (tdep->has_sve () && p_regnum >= AARCH64_SVE_V0_REGNUM
- && p_regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
- return group == all_reggroup || group == vector_reggroup;
- /* RA_STATE is used for unwinding only. Do not assign it to any groups. */
- if (tdep->has_pauth () && regnum == tdep->pauth_ra_state_regnum)
- return 0;
- return group == all_reggroup;
- }
- /* Helper for aarch64_pseudo_read_value. */
- static struct value *
- aarch64_pseudo_read_value_1 (struct gdbarch *gdbarch,
- readable_regcache *regcache, int regnum_offset,
- int regsize, struct value *result_value)
- {
- unsigned v_regnum = AARCH64_V0_REGNUM + regnum_offset;
- /* Enough space for a full vector register. */
- gdb_byte reg_buf[register_size (gdbarch, AARCH64_V0_REGNUM)];
- gdb_static_assert (AARCH64_V0_REGNUM == AARCH64_SVE_Z0_REGNUM);
- if (regcache->raw_read (v_regnum, reg_buf) != REG_VALID)
- mark_value_bytes_unavailable (result_value, 0,
- TYPE_LENGTH (value_type (result_value)));
- else
- memcpy (value_contents_raw (result_value).data (), reg_buf, regsize);
- return result_value;
- }
- /* Implement the "pseudo_register_read_value" gdbarch method. */
- static struct value *
- aarch64_pseudo_read_value (struct gdbarch *gdbarch, readable_regcache *regcache,
- int regnum)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- struct value *result_value = allocate_value (register_type (gdbarch, regnum));
- VALUE_LVAL (result_value) = lval_register;
- VALUE_REGNUM (result_value) = regnum;
- regnum -= gdbarch_num_regs (gdbarch);
- if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_Q0_REGNUM,
- Q_REGISTER_SIZE, result_value);
- if (regnum >= AARCH64_D0_REGNUM && regnum < AARCH64_D0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_D0_REGNUM,
- D_REGISTER_SIZE, result_value);
- if (regnum >= AARCH64_S0_REGNUM && regnum < AARCH64_S0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_S0_REGNUM,
- S_REGISTER_SIZE, result_value);
- if (regnum >= AARCH64_H0_REGNUM && regnum < AARCH64_H0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_H0_REGNUM,
- H_REGISTER_SIZE, result_value);
- if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_B0_REGNUM,
- B_REGISTER_SIZE, result_value);
- if (tdep->has_sve () && regnum >= AARCH64_SVE_V0_REGNUM
- && regnum < AARCH64_SVE_V0_REGNUM + 32)
- return aarch64_pseudo_read_value_1 (gdbarch, regcache,
- regnum - AARCH64_SVE_V0_REGNUM,
- V_REGISTER_SIZE, result_value);
- gdb_assert_not_reached ("regnum out of bound");
- }
- /* Helper for aarch64_pseudo_write. */
- static void
- aarch64_pseudo_write_1 (struct gdbarch *gdbarch, struct regcache *regcache,
- int regnum_offset, int regsize, const gdb_byte *buf)
- {
- unsigned v_regnum = AARCH64_V0_REGNUM + regnum_offset;
- /* Enough space for a full vector register. */
- gdb_byte reg_buf[register_size (gdbarch, AARCH64_V0_REGNUM)];
- gdb_static_assert (AARCH64_V0_REGNUM == AARCH64_SVE_Z0_REGNUM);
- /* Ensure the register buffer is zero, we want gdb writes of the
- various 'scalar' pseudo registers to behavior like architectural
- writes, register width bytes are written the remainder are set to
- zero. */
- memset (reg_buf, 0, register_size (gdbarch, AARCH64_V0_REGNUM));
- memcpy (reg_buf, buf, regsize);
- regcache->raw_write (v_regnum, reg_buf);
- }
- /* Implement the "pseudo_register_write" gdbarch method. */
- static void
- aarch64_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
- int regnum, const gdb_byte *buf)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- regnum -= gdbarch_num_regs (gdbarch);
- if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
- return aarch64_pseudo_write_1 (gdbarch, regcache,
- regnum - AARCH64_Q0_REGNUM, Q_REGISTER_SIZE,
- buf);
- if (regnum >= AARCH64_D0_REGNUM && regnum < AARCH64_D0_REGNUM + 32)
- return aarch64_pseudo_write_1 (gdbarch, regcache,
- regnum - AARCH64_D0_REGNUM, D_REGISTER_SIZE,
- buf);
- if (regnum >= AARCH64_S0_REGNUM && regnum < AARCH64_S0_REGNUM + 32)
- return aarch64_pseudo_write_1 (gdbarch, regcache,
- regnum - AARCH64_S0_REGNUM, S_REGISTER_SIZE,
- buf);
- if (regnum >= AARCH64_H0_REGNUM && regnum < AARCH64_H0_REGNUM + 32)
- return aarch64_pseudo_write_1 (gdbarch, regcache,
- regnum - AARCH64_H0_REGNUM, H_REGISTER_SIZE,
- buf);
- if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
- return aarch64_pseudo_write_1 (gdbarch, regcache,
- regnum - AARCH64_B0_REGNUM, B_REGISTER_SIZE,
- buf);
- if (tdep->has_sve () && regnum >= AARCH64_SVE_V0_REGNUM
- && regnum < AARCH64_SVE_V0_REGNUM + 32)
- return aarch64_pseudo_write_1 (gdbarch, regcache,
- regnum - AARCH64_SVE_V0_REGNUM,
- V_REGISTER_SIZE, buf);
- gdb_assert_not_reached ("regnum out of bound");
- }
- /* Callback function for user_reg_add. */
- static struct value *
- value_of_aarch64_user_reg (struct frame_info *frame, const void *baton)
- {
- const int *reg_p = (const int *) baton;
- return value_of_register (*reg_p, frame);
- }
- /* Implement the "software_single_step" gdbarch method, needed to
- single step through atomic sequences on AArch64. */
- static std::vector<CORE_ADDR>
- aarch64_software_single_step (struct regcache *regcache)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- const int insn_size = 4;
- const int atomic_sequence_length = 16; /* Instruction sequence length. */
- CORE_ADDR pc = regcache_read_pc (regcache);
- CORE_ADDR breaks[2] = { CORE_ADDR_MAX, CORE_ADDR_MAX };
- CORE_ADDR loc = pc;
- CORE_ADDR closing_insn = 0;
- uint32_t insn = read_memory_unsigned_integer (loc, insn_size,
- byte_order_for_code);
- int index;
- int insn_count;
- int bc_insn_count = 0; /* Conditional branch instruction count. */
- int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */
- aarch64_inst inst;
- if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0)
- return {};
- /* Look for a Load Exclusive instruction which begins the sequence. */
- if (inst.opcode->iclass != ldstexcl || bit (insn, 22) == 0)
- return {};
- for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
- {
- loc += insn_size;
- insn = read_memory_unsigned_integer (loc, insn_size,
- byte_order_for_code);
- if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0)
- return {};
- /* Check if the instruction is a conditional branch. */
- if (inst.opcode->iclass == condbranch)
- {
- gdb_assert (inst.operands[0].type == AARCH64_OPND_ADDR_PCREL19);
- if (bc_insn_count >= 1)
- return {};
- /* It is, so we'll try to set a breakpoint at the destination. */
- breaks[1] = loc + inst.operands[0].imm.value;
- bc_insn_count++;
- last_breakpoint++;
- }
- /* Look for the Store Exclusive which closes the atomic sequence. */
- if (inst.opcode->iclass == ldstexcl && bit (insn, 22) == 0)
- {
- closing_insn = loc;
- break;
- }
- }
- /* We didn't find a closing Store Exclusive instruction, fall back. */
- if (!closing_insn)
- return {};
- /* Insert breakpoint after the end of the atomic sequence. */
- breaks[0] = loc + insn_size;
- /* Check for duplicated breakpoints, and also check that the second
- breakpoint is not within the atomic sequence. */
- if (last_breakpoint
- && (breaks[1] == breaks[0]
- || (breaks[1] >= pc && breaks[1] <= closing_insn)))
- last_breakpoint = 0;
- std::vector<CORE_ADDR> next_pcs;
- /* Insert the breakpoint at the end of the sequence, and one at the
- destination of the conditional branch, if it exists. */
- for (index = 0; index <= last_breakpoint; index++)
- next_pcs.push_back (breaks[index]);
- return next_pcs;
- }
- struct aarch64_displaced_step_copy_insn_closure
- : public displaced_step_copy_insn_closure
- {
- /* It is true when condition instruction, such as B.CON, TBZ, etc,
- is being displaced stepping. */
- bool cond = false;
- /* PC adjustment offset after displaced stepping. If 0, then we don't
- write the PC back, assuming the PC is already the right address. */
- int32_t pc_adjust = 0;
- };
- /* Data when visiting instructions for displaced stepping. */
- struct aarch64_displaced_step_data
- {
- struct aarch64_insn_data base;
- /* The address where the instruction will be executed at. */
- CORE_ADDR new_addr;
- /* Buffer of instructions to be copied to NEW_ADDR to execute. */
- uint32_t insn_buf[AARCH64_DISPLACED_MODIFIED_INSNS];
- /* Number of instructions in INSN_BUF. */
- unsigned insn_count;
- /* Registers when doing displaced stepping. */
- struct regcache *regs;
- aarch64_displaced_step_copy_insn_closure *dsc;
- };
- /* Implementation of aarch64_insn_visitor method "b". */
- static void
- aarch64_displaced_step_b (const int is_bl, const int32_t offset,
- struct aarch64_insn_data *data)
- {
- struct aarch64_displaced_step_data *dsd
- = (struct aarch64_displaced_step_data *) data;
- int64_t new_offset = data->insn_addr - dsd->new_addr + offset;
- if (can_encode_int32 (new_offset, 28))
- {
- /* Emit B rather than BL, because executing BL on a new address
- will get the wrong address into LR. In order to avoid this,
- we emit B, and update LR if the instruction is BL. */
- emit_b (dsd->insn_buf, 0, new_offset);
- dsd->insn_count++;
- }
- else
- {
- /* Write NOP. */
- emit_nop (dsd->insn_buf);
- dsd->insn_count++;
- dsd->dsc->pc_adjust = offset;
- }
- if (is_bl)
- {
- /* Update LR. */
- regcache_cooked_write_unsigned (dsd->regs, AARCH64_LR_REGNUM,
- data->insn_addr + 4);
- }
- }
- /* Implementation of aarch64_insn_visitor method "b_cond". */
- static void
- aarch64_displaced_step_b_cond (const unsigned cond, const int32_t offset,
- struct aarch64_insn_data *data)
- {
- struct aarch64_displaced_step_data *dsd
- = (struct aarch64_displaced_step_data *) data;
- /* GDB has to fix up PC after displaced step this instruction
- differently according to the condition is true or false. Instead
- of checking COND against conditional flags, we can use
- the following instructions, and GDB can tell how to fix up PC
- according to the PC value.
- B.COND TAKEN ; If cond is true, then jump to TAKEN.
- INSN1 ;
- TAKEN:
- INSN2
- */
- emit_bcond (dsd->insn_buf, cond, 8);
- dsd->dsc->cond = true;
- dsd->dsc->pc_adjust = offset;
- dsd->insn_count = 1;
- }
- /* Dynamically allocate a new register. If we know the register
- statically, we should make it a global as above instead of using this
- helper function. */
- static struct aarch64_register
- aarch64_register (unsigned num, int is64)
- {
- return (struct aarch64_register) { num, is64 };
- }
- /* Implementation of aarch64_insn_visitor method "cb". */
- static void
- aarch64_displaced_step_cb (const int32_t offset, const int is_cbnz,
- const unsigned rn, int is64,
- struct aarch64_insn_data *data)
- {
- struct aarch64_displaced_step_data *dsd
- = (struct aarch64_displaced_step_data *) data;
- /* The offset is out of range for a compare and branch
- instruction. We can use the following instructions instead:
- CBZ xn, TAKEN ; xn == 0, then jump to TAKEN.
- INSN1 ;
- TAKEN:
- INSN2
- */
- emit_cb (dsd->insn_buf, is_cbnz, aarch64_register (rn, is64), 8);
- dsd->insn_count = 1;
- dsd->dsc->cond = true;
- dsd->dsc->pc_adjust = offset;
- }
- /* Implementation of aarch64_insn_visitor method "tb". */
- static void
- aarch64_displaced_step_tb (const int32_t offset, int is_tbnz,
- const unsigned rt, unsigned bit,
- struct aarch64_insn_data *data)
- {
- struct aarch64_displaced_step_data *dsd
- = (struct aarch64_displaced_step_data *) data;
- /* The offset is out of range for a test bit and branch
- instruction We can use the following instructions instead:
- TBZ xn, #bit, TAKEN ; xn[bit] == 0, then jump to TAKEN.
- INSN1 ;
- TAKEN:
- INSN2
- */
- emit_tb (dsd->insn_buf, is_tbnz, bit, aarch64_register (rt, 1), 8);
- dsd->insn_count = 1;
- dsd->dsc->cond = true;
- dsd->dsc->pc_adjust = offset;
- }
- /* Implementation of aarch64_insn_visitor method "adr". */
- static void
- aarch64_displaced_step_adr (const int32_t offset, const unsigned rd,
- const int is_adrp, struct aarch64_insn_data *data)
- {
- struct aarch64_displaced_step_data *dsd
- = (struct aarch64_displaced_step_data *) data;
- /* We know exactly the address the ADR{P,} instruction will compute.
- We can just write it to the destination register. */
- CORE_ADDR address = data->insn_addr + offset;
- if (is_adrp)
- {
- /* Clear the lower 12 bits of the offset to get the 4K page. */
- regcache_cooked_write_unsigned (dsd->regs, AARCH64_X0_REGNUM + rd,
- address & ~0xfff);
- }
- else
- regcache_cooked_write_unsigned (dsd->regs, AARCH64_X0_REGNUM + rd,
- address);
- dsd->dsc->pc_adjust = 4;
- emit_nop (dsd->insn_buf);
- dsd->insn_count = 1;
- }
- /* Implementation of aarch64_insn_visitor method "ldr_literal". */
- static void
- aarch64_displaced_step_ldr_literal (const int32_t offset, const int is_sw,
- const unsigned rt, const int is64,
- struct aarch64_insn_data *data)
- {
- struct aarch64_displaced_step_data *dsd
- = (struct aarch64_displaced_step_data *) data;
- CORE_ADDR address = data->insn_addr + offset;
- struct aarch64_memory_operand zero = { MEMORY_OPERAND_OFFSET, 0 };
- regcache_cooked_write_unsigned (dsd->regs, AARCH64_X0_REGNUM + rt,
- address);
- if (is_sw)
- dsd->insn_count = emit_ldrsw (dsd->insn_buf, aarch64_register (rt, 1),
- aarch64_register (rt, 1), zero);
- else
- dsd->insn_count = emit_ldr (dsd->insn_buf, aarch64_register (rt, is64),
- aarch64_register (rt, 1), zero);
- dsd->dsc->pc_adjust = 4;
- }
- /* Implementation of aarch64_insn_visitor method "others". */
- static void
- aarch64_displaced_step_others (const uint32_t insn,
- struct aarch64_insn_data *data)
- {
- struct aarch64_displaced_step_data *dsd
- = (struct aarch64_displaced_step_data *) data;
- uint32_t masked_insn = (insn & CLEAR_Rn_MASK);
- if (masked_insn == BLR)
- {
- /* Emit a BR to the same register and then update LR to the original
- address (similar to aarch64_displaced_step_b). */
- aarch64_emit_insn (dsd->insn_buf, insn & 0xffdfffff);
- regcache_cooked_write_unsigned (dsd->regs, AARCH64_LR_REGNUM,
- data->insn_addr + 4);
- }
- else
- aarch64_emit_insn (dsd->insn_buf, insn);
- dsd->insn_count = 1;
- if (masked_insn == RET || masked_insn == BR || masked_insn == BLR)
- dsd->dsc->pc_adjust = 0;
- else
- dsd->dsc->pc_adjust = 4;
- }
- static const struct aarch64_insn_visitor visitor =
- {
- aarch64_displaced_step_b,
- aarch64_displaced_step_b_cond,
- aarch64_displaced_step_cb,
- aarch64_displaced_step_tb,
- aarch64_displaced_step_adr,
- aarch64_displaced_step_ldr_literal,
- aarch64_displaced_step_others,
- };
- /* Implement the "displaced_step_copy_insn" gdbarch method. */
- displaced_step_copy_insn_closure_up
- aarch64_displaced_step_copy_insn (struct gdbarch *gdbarch,
- CORE_ADDR from, CORE_ADDR to,
- struct regcache *regs)
- {
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- uint32_t insn = read_memory_unsigned_integer (from, 4, byte_order_for_code);
- struct aarch64_displaced_step_data dsd;
- aarch64_inst inst;
- if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0)
- return NULL;
- /* Look for a Load Exclusive instruction which begins the sequence. */
- if (inst.opcode->iclass == ldstexcl && bit (insn, 22))
- {
- /* We can't displaced step atomic sequences. */
- return NULL;
- }
- std::unique_ptr<aarch64_displaced_step_copy_insn_closure> dsc
- (new aarch64_displaced_step_copy_insn_closure);
- dsd.base.insn_addr = from;
- dsd.new_addr = to;
- dsd.regs = regs;
- dsd.dsc = dsc.get ();
- dsd.insn_count = 0;
- aarch64_relocate_instruction (insn, &visitor,
- (struct aarch64_insn_data *) &dsd);
- gdb_assert (dsd.insn_count <= AARCH64_DISPLACED_MODIFIED_INSNS);
- if (dsd.insn_count != 0)
- {
- int i;
- /* Instruction can be relocated to scratch pad. Copy
- relocated instruction(s) there. */
- for (i = 0; i < dsd.insn_count; i++)
- {
- displaced_debug_printf ("writing insn %.8x at %s",
- dsd.insn_buf[i],
- paddress (gdbarch, to + i * 4));
- write_memory_unsigned_integer (to + i * 4, 4, byte_order_for_code,
- (ULONGEST) dsd.insn_buf[i]);
- }
- }
- else
- {
- dsc = NULL;
- }
- /* This is a work around for a problem with g++ 4.8. */
- return displaced_step_copy_insn_closure_up (dsc.release ());
- }
- /* Implement the "displaced_step_fixup" gdbarch method. */
- void
- aarch64_displaced_step_fixup (struct gdbarch *gdbarch,
- struct displaced_step_copy_insn_closure *dsc_,
- CORE_ADDR from, CORE_ADDR to,
- struct regcache *regs)
- {
- aarch64_displaced_step_copy_insn_closure *dsc
- = (aarch64_displaced_step_copy_insn_closure *) dsc_;
- ULONGEST pc;
- regcache_cooked_read_unsigned (regs, AARCH64_PC_REGNUM, &pc);
- displaced_debug_printf ("PC after stepping: %s (was %s).",
- paddress (gdbarch, pc), paddress (gdbarch, to));
- if (dsc->cond)
- {
- displaced_debug_printf ("[Conditional] pc_adjust before: %d",
- dsc->pc_adjust);
- if (pc - to == 8)
- {
- /* Condition is true. */
- }
- else if (pc - to == 4)
- {
- /* Condition is false. */
- dsc->pc_adjust = 4;
- }
- else
- gdb_assert_not_reached ("Unexpected PC value after displaced stepping");
- displaced_debug_printf ("[Conditional] pc_adjust after: %d",
- dsc->pc_adjust);
- }
- displaced_debug_printf ("%s PC by %d",
- dsc->pc_adjust ? "adjusting" : "not adjusting",
- dsc->pc_adjust);
- if (dsc->pc_adjust != 0)
- {
- /* Make sure the previous instruction was executed (that is, the PC
- has changed). If the PC didn't change, then discard the adjustment
- offset. Otherwise we may skip an instruction before its execution
- took place. */
- if ((pc - to) == 0)
- {
- displaced_debug_printf ("PC did not move. Discarding PC adjustment.");
- dsc->pc_adjust = 0;
- }
- displaced_debug_printf ("fixup: set PC to %s:%d",
- paddress (gdbarch, from), dsc->pc_adjust);
- regcache_cooked_write_unsigned (regs, AARCH64_PC_REGNUM,
- from + dsc->pc_adjust);
- }
- }
- /* Implement the "displaced_step_hw_singlestep" gdbarch method. */
- bool
- aarch64_displaced_step_hw_singlestep (struct gdbarch *gdbarch)
- {
- return true;
- }
- /* Get the correct target description for the given VQ value.
- If VQ is zero then it is assumed SVE is not supported.
- (It is not possible to set VQ to zero on an SVE system).
- MTE_P indicates the presence of the Memory Tagging Extension feature. */
- const target_desc *
- aarch64_read_description (uint64_t vq, bool pauth_p, bool mte_p)
- {
- if (vq > AARCH64_MAX_SVE_VQ)
- error (_("VQ is %" PRIu64 ", maximum supported value is %d"), vq,
- AARCH64_MAX_SVE_VQ);
- struct target_desc *tdesc = tdesc_aarch64_list[vq][pauth_p][mte_p];
- if (tdesc == NULL)
- {
- tdesc = aarch64_create_target_description (vq, pauth_p, mte_p);
- tdesc_aarch64_list[vq][pauth_p][mte_p] = tdesc;
- }
- return tdesc;
- }
- /* Return the VQ used when creating the target description TDESC. */
- static uint64_t
- aarch64_get_tdesc_vq (const struct target_desc *tdesc)
- {
- const struct tdesc_feature *feature_sve;
- if (!tdesc_has_registers (tdesc))
- return 0;
- feature_sve = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve");
- if (feature_sve == nullptr)
- return 0;
- uint64_t vl = tdesc_register_bitsize (feature_sve,
- aarch64_sve_register_names[0]) / 8;
- return sve_vq_from_vl (vl);
- }
- /* Implement the "cannot_store_register" gdbarch method. */
- static int
- aarch64_cannot_store_register (struct gdbarch *gdbarch, int regnum)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (!tdep->has_pauth ())
- return 0;
- /* Pointer authentication registers are read-only. */
- return (regnum == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
- || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base));
- }
- /* Implement the stack_frame_destroyed_p gdbarch method. */
- static int
- aarch64_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- CORE_ADDR func_start, func_end;
- if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
- return 0;
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- uint32_t insn = read_memory_unsigned_integer (pc, 4, byte_order_for_code);
- aarch64_inst inst;
- if (aarch64_decode_insn (insn, &inst, 1, nullptr) != 0)
- return 0;
- return streq (inst.opcode->name, "ret");
- }
- /* 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 *
- aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
- {
- const struct tdesc_feature *feature_core, *feature_fpu, *feature_sve;
- const struct tdesc_feature *feature_pauth;
- bool valid_p = true;
- int i, num_regs = 0, num_pseudo_regs = 0;
- int first_pauth_regnum = -1, pauth_ra_state_offset = -1;
- int first_mte_regnum = -1;
- /* Use the vector length passed via the target info. Here -1 is used for no
- SVE, and 0 is unset. If unset then use the vector length from the existing
- tdesc. */
- uint64_t vq = 0;
- if (info.id == (int *) -1)
- vq = 0;
- else if (info.id != 0)
- vq = (uint64_t) info.id;
- else
- vq = aarch64_get_tdesc_vq (info.target_desc);
- if (vq > AARCH64_MAX_SVE_VQ)
- internal_error (__FILE__, __LINE__, _("VQ out of bounds: %s (max %d)"),
- pulongest (vq), AARCH64_MAX_SVE_VQ);
- /* If there is already a candidate, use it. */
- for (gdbarch_list *best_arch = gdbarch_list_lookup_by_info (arches, &info);
- best_arch != nullptr;
- best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
- {
- aarch64_gdbarch_tdep *tdep
- = (aarch64_gdbarch_tdep *) gdbarch_tdep (best_arch->gdbarch);
- if (tdep && tdep->vq == vq)
- return best_arch->gdbarch;
- }
- /* Ensure we always have a target descriptor, and that it is for the given VQ
- value. */
- const struct target_desc *tdesc = info.target_desc;
- if (!tdesc_has_registers (tdesc) || vq != aarch64_get_tdesc_vq (tdesc))
- tdesc = aarch64_read_description (vq, false, false);
- gdb_assert (tdesc);
- feature_core = tdesc_find_feature (tdesc,"org.gnu.gdb.aarch64.core");
- feature_fpu = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpu");
- feature_sve = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve");
- feature_pauth = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth");
- const struct tdesc_feature *feature_mte
- = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte");
- if (feature_core == nullptr)
- return nullptr;
- tdesc_arch_data_up tdesc_data = tdesc_data_alloc ();
- /* Validate the description provides the mandatory core R registers
- and allocate their numbers. */
- for (i = 0; i < ARRAY_SIZE (aarch64_r_register_names); i++)
- valid_p &= tdesc_numbered_register (feature_core, tdesc_data.get (),
- AARCH64_X0_REGNUM + i,
- aarch64_r_register_names[i]);
- num_regs = AARCH64_X0_REGNUM + i;
- /* Add the V registers. */
- if (feature_fpu != nullptr)
- {
- if (feature_sve != nullptr)
- error (_("Program contains both fpu and SVE features."));
- /* Validate the description provides the mandatory V registers
- and allocate their numbers. */
- for (i = 0; i < ARRAY_SIZE (aarch64_v_register_names); i++)
- valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (),
- AARCH64_V0_REGNUM + i,
- aarch64_v_register_names[i]);
- num_regs = AARCH64_V0_REGNUM + i;
- }
- /* Add the SVE registers. */
- if (feature_sve != nullptr)
- {
- /* Validate the description provides the mandatory SVE registers
- and allocate their numbers. */
- for (i = 0; i < ARRAY_SIZE (aarch64_sve_register_names); i++)
- valid_p &= tdesc_numbered_register (feature_sve, tdesc_data.get (),
- AARCH64_SVE_Z0_REGNUM + i,
- aarch64_sve_register_names[i]);
- num_regs = AARCH64_SVE_Z0_REGNUM + i;
- num_pseudo_regs += 32; /* add the Vn register pseudos. */
- }
- if (feature_fpu != nullptr || feature_sve != nullptr)
- {
- num_pseudo_regs += 32; /* add the Qn scalar register pseudos */
- num_pseudo_regs += 32; /* add the Dn scalar register pseudos */
- num_pseudo_regs += 32; /* add the Sn scalar register pseudos */
- num_pseudo_regs += 32; /* add the Hn scalar register pseudos */
- num_pseudo_regs += 32; /* add the Bn scalar register pseudos */
- }
- /* Add the pauth registers. */
- if (feature_pauth != NULL)
- {
- first_pauth_regnum = num_regs;
- pauth_ra_state_offset = num_pseudo_regs;
- /* Validate the descriptor provides the mandatory PAUTH registers and
- allocate their numbers. */
- for (i = 0; i < ARRAY_SIZE (aarch64_pauth_register_names); i++)
- valid_p &= tdesc_numbered_register (feature_pauth, tdesc_data.get (),
- first_pauth_regnum + i,
- aarch64_pauth_register_names[i]);
- num_regs += i;
- num_pseudo_regs += 1; /* Count RA_STATE pseudo register. */
- }
- /* Add the MTE registers. */
- if (feature_mte != NULL)
- {
- first_mte_regnum = num_regs;
- /* Validate the descriptor provides the mandatory MTE registers and
- allocate their numbers. */
- for (i = 0; i < ARRAY_SIZE (aarch64_mte_register_names); i++)
- valid_p &= tdesc_numbered_register (feature_mte, tdesc_data.get (),
- first_mte_regnum + i,
- aarch64_mte_register_names[i]);
- num_regs += i;
- }
- if (!valid_p)
- return nullptr;
- /* AArch64 code is always little-endian. */
- info.byte_order_for_code = BFD_ENDIAN_LITTLE;
- aarch64_gdbarch_tdep *tdep = new aarch64_gdbarch_tdep;
- struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep);
- /* This should be low enough for everything. */
- tdep->lowest_pc = 0x20;
- tdep->jb_pc = -1; /* Longjump support not enabled by default. */
- tdep->jb_elt_size = 8;
- tdep->vq = vq;
- tdep->pauth_reg_base = first_pauth_regnum;
- tdep->pauth_ra_state_regnum = (feature_pauth == NULL) ? -1
- : pauth_ra_state_offset + num_regs;
- tdep->mte_reg_base = first_mte_regnum;
- set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
- set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
- /* Advance PC across function entry code. */
- set_gdbarch_skip_prologue (gdbarch, aarch64_skip_prologue);
- /* The stack grows downward. */
- set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
- /* Breakpoint manipulation. */
- set_gdbarch_breakpoint_kind_from_pc (gdbarch,
- aarch64_breakpoint::kind_from_pc);
- set_gdbarch_sw_breakpoint_from_kind (gdbarch,
- aarch64_breakpoint::bp_from_kind);
- set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
- set_gdbarch_software_single_step (gdbarch, aarch64_software_single_step);
- /* Information about registers, etc. */
- set_gdbarch_sp_regnum (gdbarch, AARCH64_SP_REGNUM);
- set_gdbarch_pc_regnum (gdbarch, AARCH64_PC_REGNUM);
- set_gdbarch_num_regs (gdbarch, num_regs);
- set_gdbarch_num_pseudo_regs (gdbarch, num_pseudo_regs);
- set_gdbarch_pseudo_register_read_value (gdbarch, aarch64_pseudo_read_value);
- set_gdbarch_pseudo_register_write (gdbarch, aarch64_pseudo_write);
- set_tdesc_pseudo_register_name (gdbarch, aarch64_pseudo_register_name);
- set_tdesc_pseudo_register_type (gdbarch, aarch64_pseudo_register_type);
- set_tdesc_pseudo_register_reggroup_p (gdbarch,
- aarch64_pseudo_register_reggroup_p);
- set_gdbarch_cannot_store_register (gdbarch, aarch64_cannot_store_register);
- /* ABI */
- set_gdbarch_short_bit (gdbarch, 16);
- set_gdbarch_int_bit (gdbarch, 32);
- set_gdbarch_float_bit (gdbarch, 32);
- set_gdbarch_double_bit (gdbarch, 64);
- set_gdbarch_long_double_bit (gdbarch, 128);
- set_gdbarch_long_bit (gdbarch, 64);
- set_gdbarch_long_long_bit (gdbarch, 64);
- set_gdbarch_ptr_bit (gdbarch, 64);
- set_gdbarch_char_signed (gdbarch, 0);
- set_gdbarch_wchar_signed (gdbarch, 0);
- set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
- set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
- set_gdbarch_long_double_format (gdbarch, floatformats_ieee_quad);
- set_gdbarch_type_align (gdbarch, aarch64_type_align);
- /* Detect whether PC is at a point where the stack has been destroyed. */
- set_gdbarch_stack_frame_destroyed_p (gdbarch, aarch64_stack_frame_destroyed_p);
- /* Internal <-> external register number maps. */
- set_gdbarch_dwarf2_reg_to_regnum (gdbarch, aarch64_dwarf_reg_to_regnum);
- /* Returning results. */
- set_gdbarch_return_value (gdbarch, aarch64_return_value);
- /* Disassembly. */
- set_gdbarch_print_insn (gdbarch, aarch64_gdb_print_insn);
- /* Virtual tables. */
- set_gdbarch_vbit_in_delta (gdbarch, 1);
- /* Hook in the ABI-specific overrides, if they have been registered. */
- info.target_desc = tdesc;
- info.tdesc_data = tdesc_data.get ();
- gdbarch_init_osabi (info, gdbarch);
- dwarf2_frame_set_init_reg (gdbarch, aarch64_dwarf2_frame_init_reg);
- /* Register DWARF CFA vendor handler. */
- set_gdbarch_execute_dwarf_cfa_vendor_op (gdbarch,
- aarch64_execute_dwarf_cfa_vendor_op);
- /* Permanent/Program breakpoint handling. */
- set_gdbarch_program_breakpoint_here_p (gdbarch,
- aarch64_program_breakpoint_here_p);
- /* Add some default predicates. */
- frame_unwind_append_unwinder (gdbarch, &aarch64_stub_unwind);
- dwarf2_append_unwinders (gdbarch);
- frame_unwind_append_unwinder (gdbarch, &aarch64_prologue_unwind);
- frame_base_set_default (gdbarch, &aarch64_normal_base);
- /* Now we have tuned the configuration, set a few final things,
- based on what the OS ABI has told us. */
- if (tdep->jb_pc >= 0)
- set_gdbarch_get_longjmp_target (gdbarch, aarch64_get_longjmp_target);
- set_gdbarch_gen_return_address (gdbarch, aarch64_gen_return_address);
- set_gdbarch_get_pc_address_flags (gdbarch, aarch64_get_pc_address_flags);
- tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data));
- /* Add standard register aliases. */
- for (i = 0; i < ARRAY_SIZE (aarch64_register_aliases); i++)
- user_reg_add (gdbarch, aarch64_register_aliases[i].name,
- value_of_aarch64_user_reg,
- &aarch64_register_aliases[i].regnum);
- register_aarch64_ravenscar_ops (gdbarch);
- return gdbarch;
- }
- static void
- aarch64_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
- {
- aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep == NULL)
- return;
- gdb_printf (file, _("aarch64_dump_tdep: Lowest pc = 0x%s"),
- paddress (gdbarch, tdep->lowest_pc));
- }
- #if GDB_SELF_TEST
- namespace selftests
- {
- static void aarch64_process_record_test (void);
- }
- #endif
- void _initialize_aarch64_tdep ();
- void
- _initialize_aarch64_tdep ()
- {
- gdbarch_register (bfd_arch_aarch64, aarch64_gdbarch_init,
- aarch64_dump_tdep);
- /* Debug this file's internals. */
- add_setshow_boolean_cmd ("aarch64", class_maintenance, &aarch64_debug, _("\
- Set AArch64 debugging."), _("\
- Show AArch64 debugging."), _("\
- When on, AArch64 specific debugging is enabled."),
- NULL,
- show_aarch64_debug,
- &setdebuglist, &showdebuglist);
- #if GDB_SELF_TEST
- selftests::register_test ("aarch64-analyze-prologue",
- selftests::aarch64_analyze_prologue_test);
- selftests::register_test ("aarch64-process-record",
- selftests::aarch64_process_record_test);
- #endif
- }
- /* AArch64 process record-replay related structures, defines etc. */
- #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 aarch64_mem_r, mem_len); \
- memcpy(MEMS, &RECORD_BUF[0], \
- sizeof(struct aarch64_mem_r) * LENGTH); \
- } \
- } \
- while (0)
- /* AArch64 record/replay structures and enumerations. */
- struct aarch64_mem_r
- {
- uint64_t len; /* Record length. */
- uint64_t addr; /* Memory address. */
- };
- enum aarch64_record_result
- {
- AARCH64_RECORD_SUCCESS,
- AARCH64_RECORD_UNSUPPORTED,
- AARCH64_RECORD_UNKNOWN
- };
- typedef struct insn_decode_record_t
- {
- struct gdbarch *gdbarch;
- struct regcache *regcache;
- CORE_ADDR this_addr; /* Address of insn to be recorded. */
- uint32_t aarch64_insn; /* Insn to be recorded. */
- uint32_t mem_rec_count; /* Count of memory records. */
- uint32_t reg_rec_count; /* Count of register records. */
- uint32_t *aarch64_regs; /* Registers to be recorded. */
- struct aarch64_mem_r *aarch64_mems; /* Memory locations to be recorded. */
- } insn_decode_record;
- /* Record handler for data processing - register instructions. */
- static unsigned int
- aarch64_record_data_proc_reg (insn_decode_record *aarch64_insn_r)
- {
- uint8_t reg_rd, insn_bits24_27, insn_bits21_23;
- uint32_t record_buf[4];
- reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4);
- insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27);
- insn_bits21_23 = bits (aarch64_insn_r->aarch64_insn, 21, 23);
- if (!bit (aarch64_insn_r->aarch64_insn, 28))
- {
- uint8_t setflags;
- /* Logical (shifted register). */
- if (insn_bits24_27 == 0x0a)
- setflags = (bits (aarch64_insn_r->aarch64_insn, 29, 30) == 0x03);
- /* Add/subtract. */
- else if (insn_bits24_27 == 0x0b)
- setflags = bit (aarch64_insn_r->aarch64_insn, 29);
- else
- return AARCH64_RECORD_UNKNOWN;
- record_buf[0] = reg_rd;
- aarch64_insn_r->reg_rec_count = 1;
- if (setflags)
- record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM;
- }
- else
- {
- if (insn_bits24_27 == 0x0b)
- {
- /* Data-processing (3 source). */
- record_buf[0] = reg_rd;
- aarch64_insn_r->reg_rec_count = 1;
- }
- else if (insn_bits24_27 == 0x0a)
- {
- if (insn_bits21_23 == 0x00)
- {
- /* Add/subtract (with carry). */
- record_buf[0] = reg_rd;
- aarch64_insn_r->reg_rec_count = 1;
- if (bit (aarch64_insn_r->aarch64_insn, 29))
- {
- record_buf[1] = AARCH64_CPSR_REGNUM;
- aarch64_insn_r->reg_rec_count = 2;
- }
- }
- else if (insn_bits21_23 == 0x02)
- {
- /* Conditional compare (register) and conditional compare
- (immediate) instructions. */
- record_buf[0] = AARCH64_CPSR_REGNUM;
- aarch64_insn_r->reg_rec_count = 1;
- }
- else if (insn_bits21_23 == 0x04 || insn_bits21_23 == 0x06)
- {
- /* Conditional select. */
- /* Data-processing (2 source). */
- /* Data-processing (1 source). */
- record_buf[0] = reg_rd;
- aarch64_insn_r->reg_rec_count = 1;
- }
- else
- return AARCH64_RECORD_UNKNOWN;
- }
- }
- REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count,
- record_buf);
- return AARCH64_RECORD_SUCCESS;
- }
- /* Record handler for data processing - immediate instructions. */
- static unsigned int
- aarch64_record_data_proc_imm (insn_decode_record *aarch64_insn_r)
- {
- uint8_t reg_rd, insn_bit23, insn_bits24_27, setflags;
- uint32_t record_buf[4];
- reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4);
- insn_bit23 = bit (aarch64_insn_r->aarch64_insn, 23);
- insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27);
- if (insn_bits24_27 == 0x00 /* PC rel addressing. */
- || insn_bits24_27 == 0x03 /* Bitfield and Extract. */
- || (insn_bits24_27 == 0x02 && insn_bit23)) /* Move wide (immediate). */
- {
- record_buf[0] = reg_rd;
- aarch64_insn_r->reg_rec_count = 1;
- }
- else if (insn_bits24_27 == 0x01)
- {
- /* Add/Subtract (immediate). */
- setflags = bit (aarch64_insn_r->aarch64_insn, 29);
- record_buf[0] = reg_rd;
- aarch64_insn_r->reg_rec_count = 1;
- if (setflags)
- record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM;
- }
- else if (insn_bits24_27 == 0x02 && !insn_bit23)
- {
- /* Logical (immediate). */
- setflags = bits (aarch64_insn_r->aarch64_insn, 29, 30) == 0x03;
- record_buf[0] = reg_rd;
- aarch64_insn_r->reg_rec_count = 1;
- if (setflags)
- record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_CPSR_REGNUM;
- }
- else
- return AARCH64_RECORD_UNKNOWN;
- REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count,
- record_buf);
- return AARCH64_RECORD_SUCCESS;
- }
- /* Record handler for branch, exception generation and system instructions. */
- static unsigned int
- aarch64_record_branch_except_sys (insn_decode_record *aarch64_insn_r)
- {
- aarch64_gdbarch_tdep *tdep
- = (aarch64_gdbarch_tdep *) gdbarch_tdep (aarch64_insn_r->gdbarch);
- uint8_t insn_bits24_27, insn_bits28_31, insn_bits22_23;
- uint32_t record_buf[4];
- insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27);
- insn_bits28_31 = bits (aarch64_insn_r->aarch64_insn, 28, 31);
- insn_bits22_23 = bits (aarch64_insn_r->aarch64_insn, 22, 23);
- if (insn_bits28_31 == 0x0d)
- {
- /* Exception generation instructions. */
- if (insn_bits24_27 == 0x04)
- {
- if (!bits (aarch64_insn_r->aarch64_insn, 2, 4)
- && !bits (aarch64_insn_r->aarch64_insn, 21, 23)
- && bits (aarch64_insn_r->aarch64_insn, 0, 1) == 0x01)
- {
- ULONGEST svc_number;
- regcache_raw_read_unsigned (aarch64_insn_r->regcache, 8,
- &svc_number);
- return tdep->aarch64_syscall_record (aarch64_insn_r->regcache,
- svc_number);
- }
- else
- return AARCH64_RECORD_UNSUPPORTED;
- }
- /* System instructions. */
- else if (insn_bits24_27 == 0x05 && insn_bits22_23 == 0x00)
- {
- uint32_t reg_rt, reg_crn;
- reg_rt = bits (aarch64_insn_r->aarch64_insn, 0, 4);
- reg_crn = bits (aarch64_insn_r->aarch64_insn, 12, 15);
- /* Record rt in case of sysl and mrs instructions. */
- if (bit (aarch64_insn_r->aarch64_insn, 21))
- {
- record_buf[0] = reg_rt;
- aarch64_insn_r->reg_rec_count = 1;
- }
- /* Record cpsr for hint and msr(immediate) instructions. */
- else if (reg_crn == 0x02 || reg_crn == 0x04)
- {
- record_buf[0] = AARCH64_CPSR_REGNUM;
- aarch64_insn_r->reg_rec_count = 1;
- }
- }
- /* Unconditional branch (register). */
- else if((insn_bits24_27 & 0x0e) == 0x06)
- {
- record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM;
- if (bits (aarch64_insn_r->aarch64_insn, 21, 22) == 0x01)
- record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_LR_REGNUM;
- }
- else
- return AARCH64_RECORD_UNKNOWN;
- }
- /* Unconditional branch (immediate). */
- else if ((insn_bits28_31 & 0x07) == 0x01 && (insn_bits24_27 & 0x0c) == 0x04)
- {
- record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM;
- if (bit (aarch64_insn_r->aarch64_insn, 31))
- record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_LR_REGNUM;
- }
- else
- /* Compare & branch (immediate), Test & branch (immediate) and
- Conditional branch (immediate). */
- record_buf[aarch64_insn_r->reg_rec_count++] = AARCH64_PC_REGNUM;
- REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count,
- record_buf);
- return AARCH64_RECORD_SUCCESS;
- }
- /* Record handler for advanced SIMD load and store instructions. */
- static unsigned int
- aarch64_record_asimd_load_store (insn_decode_record *aarch64_insn_r)
- {
- CORE_ADDR address;
- uint64_t addr_offset = 0;
- uint32_t record_buf[24];
- uint64_t record_buf_mem[24];
- uint32_t reg_rn, reg_rt;
- uint32_t reg_index = 0, mem_index = 0;
- uint8_t opcode_bits, size_bits;
- reg_rt = bits (aarch64_insn_r->aarch64_insn, 0, 4);
- reg_rn = bits (aarch64_insn_r->aarch64_insn, 5, 9);
- size_bits = bits (aarch64_insn_r->aarch64_insn, 10, 11);
- opcode_bits = bits (aarch64_insn_r->aarch64_insn, 12, 15);
- regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn, &address);
- if (record_debug)
- debug_printf ("Process record: Advanced SIMD load/store\n");
- /* Load/store single structure. */
- if (bit (aarch64_insn_r->aarch64_insn, 24))
- {
- uint8_t sindex, scale, selem, esize, replicate = 0;
- scale = opcode_bits >> 2;
- selem = ((opcode_bits & 0x02) |
- bit (aarch64_insn_r->aarch64_insn, 21)) + 1;
- switch (scale)
- {
- case 1:
- if (size_bits & 0x01)
- return AARCH64_RECORD_UNKNOWN;
- break;
- case 2:
- if ((size_bits >> 1) & 0x01)
- return AARCH64_RECORD_UNKNOWN;
- if (size_bits & 0x01)
- {
- if (!((opcode_bits >> 1) & 0x01))
- scale = 3;
- else
- return AARCH64_RECORD_UNKNOWN;
- }
- break;
- case 3:
- if (bit (aarch64_insn_r->aarch64_insn, 22) && !(opcode_bits & 0x01))
- {
- scale = size_bits;
- replicate = 1;
- break;
- }
- else
- return AARCH64_RECORD_UNKNOWN;
- default:
- break;
- }
- esize = 8 << scale;
- if (replicate)
- for (sindex = 0; sindex < selem; sindex++)
- {
- record_buf[reg_index++] = reg_rt + AARCH64_V0_REGNUM;
- reg_rt = (reg_rt + 1) % 32;
- }
- else
- {
- for (sindex = 0; sindex < selem; sindex++)
- {
- if (bit (aarch64_insn_r->aarch64_insn, 22))
- record_buf[reg_index++] = reg_rt + AARCH64_V0_REGNUM;
- else
- {
- record_buf_mem[mem_index++] = esize / 8;
- record_buf_mem[mem_index++] = address + addr_offset;
- }
- addr_offset = addr_offset + (esize / 8);
- reg_rt = (reg_rt + 1) % 32;
- }
- }
- }
- /* Load/store multiple structure. */
- else
- {
- uint8_t selem, esize, rpt, elements;
- uint8_t eindex, rindex;
- esize = 8 << size_bits;
- if (bit (aarch64_insn_r->aarch64_insn, 30))
- elements = 128 / esize;
- else
- elements = 64 / esize;
- switch (opcode_bits)
- {
- /*LD/ST4 (4 Registers). */
- case 0:
- rpt = 1;
- selem = 4;
- break;
- /*LD/ST1 (4 Registers). */
- case 2:
- rpt = 4;
- selem = 1;
- break;
- /*LD/ST3 (3 Registers). */
- case 4:
- rpt = 1;
- selem = 3;
- break;
- /*LD/ST1 (3 Registers). */
- case 6:
- rpt = 3;
- selem = 1;
- break;
- /*LD/ST1 (1 Register). */
- case 7:
- rpt = 1;
- selem = 1;
- break;
- /*LD/ST2 (2 Registers). */
- case 8:
- rpt = 1;
- selem = 2;
- break;
- /*LD/ST1 (2 Registers). */
- case 10:
- rpt = 2;
- selem = 1;
- break;
- default:
- return AARCH64_RECORD_UNSUPPORTED;
- break;
- }
- for (rindex = 0; rindex < rpt; rindex++)
- for (eindex = 0; eindex < elements; eindex++)
- {
- uint8_t reg_tt, sindex;
- reg_tt = (reg_rt + rindex) % 32;
- for (sindex = 0; sindex < selem; sindex++)
- {
- if (bit (aarch64_insn_r->aarch64_insn, 22))
- record_buf[reg_index++] = reg_tt + AARCH64_V0_REGNUM;
- else
- {
- record_buf_mem[mem_index++] = esize / 8;
- record_buf_mem[mem_index++] = address + addr_offset;
- }
- addr_offset = addr_offset + (esize / 8);
- reg_tt = (reg_tt + 1) % 32;
- }
- }
- }
- if (bit (aarch64_insn_r->aarch64_insn, 23))
- record_buf[reg_index++] = reg_rn;
- aarch64_insn_r->reg_rec_count = reg_index;
- aarch64_insn_r->mem_rec_count = mem_index / 2;
- MEM_ALLOC (aarch64_insn_r->aarch64_mems, aarch64_insn_r->mem_rec_count,
- record_buf_mem);
- REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count,
- record_buf);
- return AARCH64_RECORD_SUCCESS;
- }
- /* Record handler for load and store instructions. */
- static unsigned int
- aarch64_record_load_store (insn_decode_record *aarch64_insn_r)
- {
- uint8_t insn_bits24_27, insn_bits28_29, insn_bits10_11;
- uint8_t insn_bit23, insn_bit21;
- uint8_t opc, size_bits, ld_flag, vector_flag;
- uint32_t reg_rn, reg_rt, reg_rt2;
- uint64_t datasize, offset;
- uint32_t record_buf[8];
- uint64_t record_buf_mem[8];
- CORE_ADDR address;
- insn_bits10_11 = bits (aarch64_insn_r->aarch64_insn, 10, 11);
- insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27);
- insn_bits28_29 = bits (aarch64_insn_r->aarch64_insn, 28, 29);
- insn_bit21 = bit (aarch64_insn_r->aarch64_insn, 21);
- insn_bit23 = bit (aarch64_insn_r->aarch64_insn, 23);
- ld_flag = bit (aarch64_insn_r->aarch64_insn, 22);
- vector_flag = bit (aarch64_insn_r->aarch64_insn, 26);
- reg_rt = bits (aarch64_insn_r->aarch64_insn, 0, 4);
- reg_rn = bits (aarch64_insn_r->aarch64_insn, 5, 9);
- reg_rt2 = bits (aarch64_insn_r->aarch64_insn, 10, 14);
- size_bits = bits (aarch64_insn_r->aarch64_insn, 30, 31);
- /* Load/store exclusive. */
- if (insn_bits24_27 == 0x08 && insn_bits28_29 == 0x00)
- {
- if (record_debug)
- debug_printf ("Process record: load/store exclusive\n");
- if (ld_flag)
- {
- record_buf[0] = reg_rt;
- aarch64_insn_r->reg_rec_count = 1;
- if (insn_bit21)
- {
- record_buf[1] = reg_rt2;
- aarch64_insn_r->reg_rec_count = 2;
- }
- }
- else
- {
- if (insn_bit21)
- datasize = (8 << size_bits) * 2;
- else
- datasize = (8 << size_bits);
- regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
- &address);
- record_buf_mem[0] = datasize / 8;
- record_buf_mem[1] = address;
- aarch64_insn_r->mem_rec_count = 1;
- if (!insn_bit23)
- {
- /* Save register rs. */
- record_buf[0] = bits (aarch64_insn_r->aarch64_insn, 16, 20);
- aarch64_insn_r->reg_rec_count = 1;
- }
- }
- }
- /* Load register (literal) instructions decoding. */
- else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x01)
- {
- if (record_debug)
- debug_printf ("Process record: load register (literal)\n");
- if (vector_flag)
- record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
- else
- record_buf[0] = reg_rt;
- aarch64_insn_r->reg_rec_count = 1;
- }
- /* All types of load/store pair instructions decoding. */
- else if ((insn_bits24_27 & 0x0a) == 0x08 && insn_bits28_29 == 0x02)
- {
- if (record_debug)
- debug_printf ("Process record: load/store pair\n");
- if (ld_flag)
- {
- if (vector_flag)
- {
- record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
- record_buf[1] = reg_rt2 + AARCH64_V0_REGNUM;
- }
- else
- {
- record_buf[0] = reg_rt;
- record_buf[1] = reg_rt2;
- }
- aarch64_insn_r->reg_rec_count = 2;
- }
- else
- {
- uint16_t imm7_off;
- imm7_off = bits (aarch64_insn_r->aarch64_insn, 15, 21);
- if (!vector_flag)
- size_bits = size_bits >> 1;
- datasize = 8 << (2 + size_bits);
- offset = (imm7_off & 0x40) ? (~imm7_off & 0x007f) + 1 : imm7_off;
- offset = offset << (2 + size_bits);
- regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
- &address);
- if (!((insn_bits24_27 & 0x0b) == 0x08 && insn_bit23))
- {
- if (imm7_off & 0x40)
- address = address - offset;
- else
- address = address + offset;
- }
- record_buf_mem[0] = datasize / 8;
- record_buf_mem[1] = address;
- record_buf_mem[2] = datasize / 8;
- record_buf_mem[3] = address + (datasize / 8);
- aarch64_insn_r->mem_rec_count = 2;
- }
- if (bit (aarch64_insn_r->aarch64_insn, 23))
- record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn;
- }
- /* Load/store register (unsigned immediate) instructions. */
- else if ((insn_bits24_27 & 0x0b) == 0x09 && insn_bits28_29 == 0x03)
- {
- opc = bits (aarch64_insn_r->aarch64_insn, 22, 23);
- if (!(opc >> 1))
- {
- if (opc & 0x01)
- ld_flag = 0x01;
- else
- ld_flag = 0x0;
- }
- else
- {
- if (size_bits == 0x3 && vector_flag == 0x0 && opc == 0x2)
- {
- /* PRFM (immediate) */
- return AARCH64_RECORD_SUCCESS;
- }
- else if (size_bits == 0x2 && vector_flag == 0x0 && opc == 0x2)
- {
- /* LDRSW (immediate) */
- ld_flag = 0x1;
- }
- else
- {
- if (opc & 0x01)
- ld_flag = 0x01;
- else
- ld_flag = 0x0;
- }
- }
- if (record_debug)
- {
- debug_printf ("Process record: load/store (unsigned immediate):"
- " size %x V %d opc %x\n", size_bits, vector_flag,
- opc);
- }
- if (!ld_flag)
- {
- offset = bits (aarch64_insn_r->aarch64_insn, 10, 21);
- datasize = 8 << size_bits;
- regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
- &address);
- offset = offset << size_bits;
- address = address + offset;
- record_buf_mem[0] = datasize >> 3;
- record_buf_mem[1] = address;
- aarch64_insn_r->mem_rec_count = 1;
- }
- else
- {
- if (vector_flag)
- record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
- else
- record_buf[0] = reg_rt;
- aarch64_insn_r->reg_rec_count = 1;
- }
- }
- /* Load/store register (register offset) instructions. */
- else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03
- && insn_bits10_11 == 0x02 && insn_bit21)
- {
- if (record_debug)
- debug_printf ("Process record: load/store (register offset)\n");
- opc = bits (aarch64_insn_r->aarch64_insn, 22, 23);
- if (!(opc >> 1))
- if (opc & 0x01)
- ld_flag = 0x01;
- else
- ld_flag = 0x0;
- else
- if (size_bits != 0x03)
- ld_flag = 0x01;
- else
- return AARCH64_RECORD_UNKNOWN;
- if (!ld_flag)
- {
- ULONGEST reg_rm_val;
- regcache_raw_read_unsigned (aarch64_insn_r->regcache,
- bits (aarch64_insn_r->aarch64_insn, 16, 20), ®_rm_val);
- if (bit (aarch64_insn_r->aarch64_insn, 12))
- offset = reg_rm_val << size_bits;
- else
- offset = reg_rm_val;
- datasize = 8 << size_bits;
- regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
- &address);
- address = address + offset;
- record_buf_mem[0] = datasize >> 3;
- record_buf_mem[1] = address;
- aarch64_insn_r->mem_rec_count = 1;
- }
- else
- {
- if (vector_flag)
- record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
- else
- record_buf[0] = reg_rt;
- aarch64_insn_r->reg_rec_count = 1;
- }
- }
- /* Load/store register (immediate and unprivileged) instructions. */
- else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03
- && !insn_bit21)
- {
- if (record_debug)
- {
- debug_printf ("Process record: load/store "
- "(immediate and unprivileged)\n");
- }
- opc = bits (aarch64_insn_r->aarch64_insn, 22, 23);
- if (!(opc >> 1))
- if (opc & 0x01)
- ld_flag = 0x01;
- else
- ld_flag = 0x0;
- else
- if (size_bits != 0x03)
- ld_flag = 0x01;
- else
- return AARCH64_RECORD_UNKNOWN;
- if (!ld_flag)
- {
- uint16_t imm9_off;
- imm9_off = bits (aarch64_insn_r->aarch64_insn, 12, 20);
- offset = (imm9_off & 0x0100) ? (((~imm9_off) & 0x01ff) + 1) : imm9_off;
- datasize = 8 << size_bits;
- regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
- &address);
- if (insn_bits10_11 != 0x01)
- {
- if (imm9_off & 0x0100)
- address = address - offset;
- else
- address = address + offset;
- }
- record_buf_mem[0] = datasize >> 3;
- record_buf_mem[1] = address;
- aarch64_insn_r->mem_rec_count = 1;
- }
- else
- {
- if (vector_flag)
- record_buf[0] = reg_rt + AARCH64_V0_REGNUM;
- else
- record_buf[0] = reg_rt;
- aarch64_insn_r->reg_rec_count = 1;
- }
- if (insn_bits10_11 == 0x01 || insn_bits10_11 == 0x03)
- record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn;
- }
- /* Advanced SIMD load/store instructions. */
- else
- return aarch64_record_asimd_load_store (aarch64_insn_r);
- MEM_ALLOC (aarch64_insn_r->aarch64_mems, aarch64_insn_r->mem_rec_count,
- record_buf_mem);
- REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count,
- record_buf);
- return AARCH64_RECORD_SUCCESS;
- }
- /* Record handler for data processing SIMD and floating point instructions. */
- static unsigned int
- aarch64_record_data_proc_simd_fp (insn_decode_record *aarch64_insn_r)
- {
- uint8_t insn_bit21, opcode, rmode, reg_rd;
- uint8_t insn_bits24_27, insn_bits28_31, insn_bits10_11, insn_bits12_15;
- uint8_t insn_bits11_14;
- uint32_t record_buf[2];
- insn_bits24_27 = bits (aarch64_insn_r->aarch64_insn, 24, 27);
- insn_bits28_31 = bits (aarch64_insn_r->aarch64_insn, 28, 31);
- insn_bits10_11 = bits (aarch64_insn_r->aarch64_insn, 10, 11);
- insn_bits12_15 = bits (aarch64_insn_r->aarch64_insn, 12, 15);
- insn_bits11_14 = bits (aarch64_insn_r->aarch64_insn, 11, 14);
- opcode = bits (aarch64_insn_r->aarch64_insn, 16, 18);
- rmode = bits (aarch64_insn_r->aarch64_insn, 19, 20);
- reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4);
- insn_bit21 = bit (aarch64_insn_r->aarch64_insn, 21);
- if (record_debug)
- debug_printf ("Process record: data processing SIMD/FP: ");
- if ((insn_bits28_31 & 0x05) == 0x01 && insn_bits24_27 == 0x0e)
- {
- /* Floating point - fixed point conversion instructions. */
- if (!insn_bit21)
- {
- if (record_debug)
- debug_printf ("FP - fixed point conversion");
- if ((opcode >> 1) == 0x0 && rmode == 0x03)
- record_buf[0] = reg_rd;
- else
- record_buf[0] = reg_rd + AARCH64_V0_REGNUM;
- }
- /* Floating point - conditional compare instructions. */
- else if (insn_bits10_11 == 0x01)
- {
- if (record_debug)
- debug_printf ("FP - conditional compare");
- record_buf[0] = AARCH64_CPSR_REGNUM;
- }
- /* Floating point - data processing (2-source) and
- conditional select instructions. */
- else if (insn_bits10_11 == 0x02 || insn_bits10_11 == 0x03)
- {
- if (record_debug)
- debug_printf ("FP - DP (2-source)");
- record_buf[0] = reg_rd + AARCH64_V0_REGNUM;
- }
- else if (insn_bits10_11 == 0x00)
- {
- /* Floating point - immediate instructions. */
- if ((insn_bits12_15 & 0x01) == 0x01
- || (insn_bits12_15 & 0x07) == 0x04)
- {
- if (record_debug)
- debug_printf ("FP - immediate");
- record_buf[0] = reg_rd + AARCH64_V0_REGNUM;
- }
- /* Floating point - compare instructions. */
- else if ((insn_bits12_15 & 0x03) == 0x02)
- {
- if (record_debug)
- debug_printf ("FP - immediate");
- record_buf[0] = AARCH64_CPSR_REGNUM;
- }
- /* Floating point - integer conversions instructions. */
- else if (insn_bits12_15 == 0x00)
- {
- /* Convert float to integer instruction. */
- if (!(opcode >> 1) || ((opcode >> 1) == 0x02 && !rmode))
- {
- if (record_debug)
- debug_printf ("float to int conversion");
- record_buf[0] = reg_rd + AARCH64_X0_REGNUM;
- }
- /* Convert integer to float instruction. */
- else if ((opcode >> 1) == 0x01 && !rmode)
- {
- if (record_debug)
- debug_printf ("int to float conversion");
- record_buf[0] = reg_rd + AARCH64_V0_REGNUM;
- }
- /* Move float to integer instruction. */
- else if ((opcode >> 1) == 0x03)
- {
- if (record_debug)
- debug_printf ("move float to int");
- if (!(opcode & 0x01))
- record_buf[0] = reg_rd + AARCH64_X0_REGNUM;
- else
- record_buf[0] = reg_rd + AARCH64_V0_REGNUM;
- }
- else
- return AARCH64_RECORD_UNKNOWN;
- }
- else
- return AARCH64_RECORD_UNKNOWN;
- }
- else
- return AARCH64_RECORD_UNKNOWN;
- }
- else if ((insn_bits28_31 & 0x09) == 0x00 && insn_bits24_27 == 0x0e)
- {
- if (record_debug)
- debug_printf ("SIMD copy");
- /* Advanced SIMD copy instructions. */
- if (!bits (aarch64_insn_r->aarch64_insn, 21, 23)
- && !bit (aarch64_insn_r->aarch64_insn, 15)
- && bit (aarch64_insn_r->aarch64_insn, 10))
- {
- if (insn_bits11_14 == 0x05 || insn_bits11_14 == 0x07)
- record_buf[0] = reg_rd + AARCH64_X0_REGNUM;
- else
- record_buf[0] = reg_rd + AARCH64_V0_REGNUM;
- }
- else
- record_buf[0] = reg_rd + AARCH64_V0_REGNUM;
- }
- /* All remaining floating point or advanced SIMD instructions. */
- else
- {
- if (record_debug)
- debug_printf ("all remain");
- record_buf[0] = reg_rd + AARCH64_V0_REGNUM;
- }
- if (record_debug)
- debug_printf ("\n");
- /* Record the V/X register. */
- aarch64_insn_r->reg_rec_count++;
- /* Some of these instructions may set bits in the FPSR, so record it
- too. */
- record_buf[1] = AARCH64_FPSR_REGNUM;
- aarch64_insn_r->reg_rec_count++;
- gdb_assert (aarch64_insn_r->reg_rec_count == 2);
- REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count,
- record_buf);
- return AARCH64_RECORD_SUCCESS;
- }
- /* Decodes insns type and invokes its record handler. */
- static unsigned int
- aarch64_record_decode_insn_handler (insn_decode_record *aarch64_insn_r)
- {
- uint32_t ins_bit25, ins_bit26, ins_bit27, ins_bit28;
- ins_bit25 = bit (aarch64_insn_r->aarch64_insn, 25);
- ins_bit26 = bit (aarch64_insn_r->aarch64_insn, 26);
- ins_bit27 = bit (aarch64_insn_r->aarch64_insn, 27);
- ins_bit28 = bit (aarch64_insn_r->aarch64_insn, 28);
- /* Data processing - immediate instructions. */
- if (!ins_bit26 && !ins_bit27 && ins_bit28)
- return aarch64_record_data_proc_imm (aarch64_insn_r);
- /* Branch, exception generation and system instructions. */
- if (ins_bit26 && !ins_bit27 && ins_bit28)
- return aarch64_record_branch_except_sys (aarch64_insn_r);
- /* Load and store instructions. */
- if (!ins_bit25 && ins_bit27)
- return aarch64_record_load_store (aarch64_insn_r);
- /* Data processing - register instructions. */
- if (ins_bit25 && !ins_bit26 && ins_bit27)
- return aarch64_record_data_proc_reg (aarch64_insn_r);
- /* Data processing - SIMD and floating point instructions. */
- if (ins_bit25 && ins_bit26 && ins_bit27)
- return aarch64_record_data_proc_simd_fp (aarch64_insn_r);
- return AARCH64_RECORD_UNSUPPORTED;
- }
- /* Cleans up local record registers and memory allocations. */
- static void
- deallocate_reg_mem (insn_decode_record *record)
- {
- xfree (record->aarch64_regs);
- xfree (record->aarch64_mems);
- }
- #if GDB_SELF_TEST
- namespace selftests {
- static void
- aarch64_process_record_test (void)
- {
- struct gdbarch_info info;
- uint32_t ret;
- info.bfd_arch_info = bfd_scan_arch ("aarch64");
- struct gdbarch *gdbarch = gdbarch_find_by_info (info);
- SELF_CHECK (gdbarch != NULL);
- insn_decode_record aarch64_record;
- memset (&aarch64_record, 0, sizeof (insn_decode_record));
- aarch64_record.regcache = NULL;
- aarch64_record.this_addr = 0;
- aarch64_record.gdbarch = gdbarch;
- /* 20 00 80 f9 prfm pldl1keep, [x1] */
- aarch64_record.aarch64_insn = 0xf9800020;
- ret = aarch64_record_decode_insn_handler (&aarch64_record);
- SELF_CHECK (ret == AARCH64_RECORD_SUCCESS);
- SELF_CHECK (aarch64_record.reg_rec_count == 0);
- SELF_CHECK (aarch64_record.mem_rec_count == 0);
- deallocate_reg_mem (&aarch64_record);
- }
- } // namespace selftests
- #endif /* GDB_SELF_TEST */
- /* 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
- aarch64_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
- CORE_ADDR insn_addr)
- {
- uint32_t rec_no = 0;
- uint8_t insn_size = 4;
- uint32_t ret = 0;
- gdb_byte buf[insn_size];
- insn_decode_record aarch64_record;
- memset (&buf[0], 0, insn_size);
- memset (&aarch64_record, 0, sizeof (insn_decode_record));
- target_read_memory (insn_addr, &buf[0], insn_size);
- aarch64_record.aarch64_insn
- = (uint32_t) extract_unsigned_integer (&buf[0],
- insn_size,
- gdbarch_byte_order (gdbarch));
- aarch64_record.regcache = regcache;
- aarch64_record.this_addr = insn_addr;
- aarch64_record.gdbarch = gdbarch;
- ret = aarch64_record_decode_insn_handler (&aarch64_record);
- if (ret == AARCH64_RECORD_UNSUPPORTED)
- {
- gdb_printf (gdb_stderr,
- _("Process record does not support instruction "
- "0x%0x at address %s.\n"),
- aarch64_record.aarch64_insn,
- paddress (gdbarch, insn_addr));
- ret = -1;
- }
- if (0 == ret)
- {
- /* Record registers. */
- record_full_arch_list_add_reg (aarch64_record.regcache,
- AARCH64_PC_REGNUM);
- /* Always record register CPSR. */
- record_full_arch_list_add_reg (aarch64_record.regcache,
- AARCH64_CPSR_REGNUM);
- if (aarch64_record.aarch64_regs)
- for (rec_no = 0; rec_no < aarch64_record.reg_rec_count; rec_no++)
- if (record_full_arch_list_add_reg (aarch64_record.regcache,
- aarch64_record.aarch64_regs[rec_no]))
- ret = -1;
- /* Record memories. */
- if (aarch64_record.aarch64_mems)
- for (rec_no = 0; rec_no < aarch64_record.mem_rec_count; rec_no++)
- if (record_full_arch_list_add_mem
- ((CORE_ADDR)aarch64_record.aarch64_mems[rec_no].addr,
- aarch64_record.aarch64_mems[rec_no].len))
- ret = -1;
- if (record_full_arch_list_add_end ())
- ret = -1;
- }
- deallocate_reg_mem (&aarch64_record);
- return ret;
- }
|