1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459 |
- /* Tracepoint code for remote server for GDB.
- Copyright (C) 2009-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "server.h"
- #include "tracepoint.h"
- #include "gdbthread.h"
- #include "gdbsupport/rsp-low.h"
- #include <ctype.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <chrono>
- #include <inttypes.h>
- #include "ax.h"
- #include "tdesc.h"
- #define IPA_SYM_STRUCT_NAME ipa_sym_addresses
- #include "gdbsupport/agent.h"
- #define DEFAULT_TRACE_BUFFER_SIZE 5242880 /* 5*1024*1024 */
- /* This file is built for both GDBserver, and the in-process
- agent (IPA), a shared library that includes a tracing agent that is
- loaded by the inferior to support fast tracepoints. Fast
- tracepoints (or more accurately, jump based tracepoints) are
- implemented by patching the tracepoint location with a jump into a
- small trampoline function whose job is to save the register state,
- call the in-process tracing agent, and then execute the original
- instruction that was under the tracepoint jump (possibly adjusted,
- if PC-relative, or some such).
- The current synchronization design is pull based. That means,
- GDBserver does most of the work, by peeking/poking at the inferior
- agent's memory directly for downloading tracepoint and associated
- objects, and for uploading trace frames. Whenever the IPA needs
- something from GDBserver (trace buffer is full, tracing stopped for
- some reason, etc.) the IPA calls a corresponding hook function
- where GDBserver has placed a breakpoint.
- Each of the agents has its own trace buffer. When browsing the
- trace frames built from slow and fast tracepoints from GDB (tfind
- mode), there's no guarantee the user is seeing the trace frames in
- strict chronological creation order, although, GDBserver tries to
- keep the order relatively reasonable, by syncing the trace buffers
- at appropriate times.
- */
- #ifdef IN_PROCESS_AGENT
- static void trace_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2);
- static void
- trace_vdebug (const char *fmt, ...)
- {
- char buf[1024];
- va_list ap;
- va_start (ap, fmt);
- vsprintf (buf, fmt, ap);
- fprintf (stderr, PROG "/tracepoint: %s\n", buf);
- va_end (ap);
- }
- #define trace_debug(fmt, args...) \
- do { \
- if (debug_threads) \
- trace_vdebug ((fmt), ##args); \
- } while (0)
- #else
- #define trace_debug(fmt, args...) \
- do { \
- threads_debug_printf ((fmt), ##args); \
- } while (0)
- #endif
- /* Prefix exported symbols, for good citizenship. All the symbols
- that need exporting are defined in this module. Note that all
- these symbols must be tagged with IP_AGENT_EXPORT_*. */
- #ifdef IN_PROCESS_AGENT
- # define gdb_tp_heap_buffer IPA_SYM_EXPORTED_NAME (gdb_tp_heap_buffer)
- # define gdb_jump_pad_buffer IPA_SYM_EXPORTED_NAME (gdb_jump_pad_buffer)
- # define gdb_jump_pad_buffer_end IPA_SYM_EXPORTED_NAME (gdb_jump_pad_buffer_end)
- # define gdb_trampoline_buffer IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer)
- # define gdb_trampoline_buffer_end IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_end)
- # define gdb_trampoline_buffer_error IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_error)
- # define collecting IPA_SYM_EXPORTED_NAME (collecting)
- # define gdb_collect_ptr IPA_SYM_EXPORTED_NAME (gdb_collect_ptr)
- # define stop_tracing IPA_SYM_EXPORTED_NAME (stop_tracing)
- # define flush_trace_buffer IPA_SYM_EXPORTED_NAME (flush_trace_buffer)
- # define about_to_request_buffer_space IPA_SYM_EXPORTED_NAME (about_to_request_buffer_space)
- # define trace_buffer_is_full IPA_SYM_EXPORTED_NAME (trace_buffer_is_full)
- # define stopping_tracepoint IPA_SYM_EXPORTED_NAME (stopping_tracepoint)
- # define expr_eval_result IPA_SYM_EXPORTED_NAME (expr_eval_result)
- # define error_tracepoint IPA_SYM_EXPORTED_NAME (error_tracepoint)
- # define tracepoints IPA_SYM_EXPORTED_NAME (tracepoints)
- # define tracing IPA_SYM_EXPORTED_NAME (tracing)
- # define trace_buffer_ctrl IPA_SYM_EXPORTED_NAME (trace_buffer_ctrl)
- # define trace_buffer_ctrl_curr IPA_SYM_EXPORTED_NAME (trace_buffer_ctrl_curr)
- # define trace_buffer_lo IPA_SYM_EXPORTED_NAME (trace_buffer_lo)
- # define trace_buffer_hi IPA_SYM_EXPORTED_NAME (trace_buffer_hi)
- # define traceframe_read_count IPA_SYM_EXPORTED_NAME (traceframe_read_count)
- # define traceframe_write_count IPA_SYM_EXPORTED_NAME (traceframe_write_count)
- # define traceframes_created IPA_SYM_EXPORTED_NAME (traceframes_created)
- # define trace_state_variables IPA_SYM_EXPORTED_NAME (trace_state_variables)
- # define get_raw_reg_ptr IPA_SYM_EXPORTED_NAME (get_raw_reg_ptr)
- # define get_trace_state_variable_value_ptr \
- IPA_SYM_EXPORTED_NAME (get_trace_state_variable_value_ptr)
- # define set_trace_state_variable_value_ptr \
- IPA_SYM_EXPORTED_NAME (set_trace_state_variable_value_ptr)
- # define ust_loaded IPA_SYM_EXPORTED_NAME (ust_loaded)
- # define helper_thread_id IPA_SYM_EXPORTED_NAME (helper_thread_id)
- # define cmd_buf IPA_SYM_EXPORTED_NAME (cmd_buf)
- # define ipa_tdesc_idx IPA_SYM_EXPORTED_NAME (ipa_tdesc_idx)
- #endif
- #ifndef IN_PROCESS_AGENT
- /* Addresses of in-process agent's symbols GDBserver cares about. */
- struct ipa_sym_addresses
- {
- CORE_ADDR addr_gdb_tp_heap_buffer;
- CORE_ADDR addr_gdb_jump_pad_buffer;
- CORE_ADDR addr_gdb_jump_pad_buffer_end;
- CORE_ADDR addr_gdb_trampoline_buffer;
- CORE_ADDR addr_gdb_trampoline_buffer_end;
- CORE_ADDR addr_gdb_trampoline_buffer_error;
- CORE_ADDR addr_collecting;
- CORE_ADDR addr_gdb_collect_ptr;
- CORE_ADDR addr_stop_tracing;
- CORE_ADDR addr_flush_trace_buffer;
- CORE_ADDR addr_about_to_request_buffer_space;
- CORE_ADDR addr_trace_buffer_is_full;
- CORE_ADDR addr_stopping_tracepoint;
- CORE_ADDR addr_expr_eval_result;
- CORE_ADDR addr_error_tracepoint;
- CORE_ADDR addr_tracepoints;
- CORE_ADDR addr_tracing;
- CORE_ADDR addr_trace_buffer_ctrl;
- CORE_ADDR addr_trace_buffer_ctrl_curr;
- CORE_ADDR addr_trace_buffer_lo;
- CORE_ADDR addr_trace_buffer_hi;
- CORE_ADDR addr_traceframe_read_count;
- CORE_ADDR addr_traceframe_write_count;
- CORE_ADDR addr_traceframes_created;
- CORE_ADDR addr_trace_state_variables;
- CORE_ADDR addr_get_raw_reg_ptr;
- CORE_ADDR addr_get_trace_state_variable_value_ptr;
- CORE_ADDR addr_set_trace_state_variable_value_ptr;
- CORE_ADDR addr_ust_loaded;
- CORE_ADDR addr_ipa_tdesc_idx;
- };
- static struct
- {
- const char *name;
- int offset;
- } symbol_list[] = {
- IPA_SYM(gdb_tp_heap_buffer),
- IPA_SYM(gdb_jump_pad_buffer),
- IPA_SYM(gdb_jump_pad_buffer_end),
- IPA_SYM(gdb_trampoline_buffer),
- IPA_SYM(gdb_trampoline_buffer_end),
- IPA_SYM(gdb_trampoline_buffer_error),
- IPA_SYM(collecting),
- IPA_SYM(gdb_collect_ptr),
- IPA_SYM(stop_tracing),
- IPA_SYM(flush_trace_buffer),
- IPA_SYM(about_to_request_buffer_space),
- IPA_SYM(trace_buffer_is_full),
- IPA_SYM(stopping_tracepoint),
- IPA_SYM(expr_eval_result),
- IPA_SYM(error_tracepoint),
- IPA_SYM(tracepoints),
- IPA_SYM(tracing),
- IPA_SYM(trace_buffer_ctrl),
- IPA_SYM(trace_buffer_ctrl_curr),
- IPA_SYM(trace_buffer_lo),
- IPA_SYM(trace_buffer_hi),
- IPA_SYM(traceframe_read_count),
- IPA_SYM(traceframe_write_count),
- IPA_SYM(traceframes_created),
- IPA_SYM(trace_state_variables),
- IPA_SYM(get_raw_reg_ptr),
- IPA_SYM(get_trace_state_variable_value_ptr),
- IPA_SYM(set_trace_state_variable_value_ptr),
- IPA_SYM(ust_loaded),
- IPA_SYM(ipa_tdesc_idx),
- };
- static struct ipa_sym_addresses ipa_sym_addrs;
- static int read_inferior_integer (CORE_ADDR symaddr, int *val);
- /* Returns true if both the in-process agent library and the static
- tracepoints libraries are loaded in the inferior, and agent has
- capability on static tracepoints. */
- static int
- in_process_agent_supports_ust (void)
- {
- int loaded = 0;
- if (!agent_loaded_p ())
- {
- warning ("In-process agent not loaded");
- return 0;
- }
- if (agent_capability_check (AGENT_CAPA_STATIC_TRACE))
- {
- /* Agent understands static tracepoint, then check whether UST is in
- fact loaded in the inferior. */
- if (read_inferior_integer (ipa_sym_addrs.addr_ust_loaded, &loaded))
- {
- warning ("Error reading ust_loaded in lib");
- return 0;
- }
- return loaded;
- }
- else
- return 0;
- }
- static void
- write_e_ipa_not_loaded (char *buffer)
- {
- sprintf (buffer,
- "E.In-process agent library not loaded in process. "
- "Fast and static tracepoints unavailable.");
- }
- /* Write an error to BUFFER indicating that UST isn't loaded in the
- inferior. */
- static void
- write_e_ust_not_loaded (char *buffer)
- {
- #ifdef HAVE_UST
- sprintf (buffer,
- "E.UST library not loaded in process. "
- "Static tracepoints unavailable.");
- #else
- sprintf (buffer, "E.GDBserver was built without static tracepoints support");
- #endif
- }
- /* If the in-process agent library isn't loaded in the inferior, write
- an error to BUFFER, and return 1. Otherwise, return 0. */
- static int
- maybe_write_ipa_not_loaded (char *buffer)
- {
- if (!agent_loaded_p ())
- {
- write_e_ipa_not_loaded (buffer);
- return 1;
- }
- return 0;
- }
- /* If the in-process agent library and the ust (static tracepoints)
- library aren't loaded in the inferior, write an error to BUFFER,
- and return 1. Otherwise, return 0. */
- static int
- maybe_write_ipa_ust_not_loaded (char *buffer)
- {
- if (!agent_loaded_p ())
- {
- write_e_ipa_not_loaded (buffer);
- return 1;
- }
- else if (!in_process_agent_supports_ust ())
- {
- write_e_ust_not_loaded (buffer);
- return 1;
- }
- return 0;
- }
- /* Cache all future symbols that the tracepoints module might request.
- We can not request symbols at arbitrary states in the remote
- protocol, only when the client tells us that new symbols are
- available. So when we load the in-process library, make sure to
- check the entire list. */
- void
- tracepoint_look_up_symbols (void)
- {
- int i;
- if (agent_loaded_p ())
- return;
- for (i = 0; i < sizeof (symbol_list) / sizeof (symbol_list[0]); i++)
- {
- CORE_ADDR *addrp =
- (CORE_ADDR *) ((char *) &ipa_sym_addrs + symbol_list[i].offset);
- if (look_up_one_symbol (symbol_list[i].name, addrp, 1) == 0)
- {
- threads_debug_printf ("symbol `%s' not found", symbol_list[i].name);
- return;
- }
- }
- agent_look_up_symbols (NULL);
- }
- #endif
- /* GDBserver places a breakpoint on the IPA's version (which is a nop)
- of the "stop_tracing" function. When this breakpoint is hit,
- tracing stopped in the IPA for some reason. E.g., due to
- tracepoint reaching the pass count, hitting conditional expression
- evaluation error, etc.
- The IPA's trace buffer is never in circular tracing mode: instead,
- GDBserver's is, and whenever the in-process buffer fills, it calls
- "flush_trace_buffer", which triggers an internal breakpoint.
- GDBserver reacts to this breakpoint by pulling the meanwhile
- collected data. Old frames discarding is always handled on the
- GDBserver side. */
- #ifdef IN_PROCESS_AGENT
- int
- read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
- {
- memcpy (myaddr, (void *) (uintptr_t) memaddr, len);
- return 0;
- }
- /* Call this in the functions where GDBserver places a breakpoint, so
- that the compiler doesn't try to be clever and skip calling the
- function at all. This is necessary, even if we tell the compiler
- to not inline said functions. */
- #if defined(__GNUC__)
- # define UNKNOWN_SIDE_EFFECTS() asm ("")
- #else
- # define UNKNOWN_SIDE_EFFECTS() do {} while (0)
- #endif
- /* This is needed for -Wmissing-declarations. */
- IP_AGENT_EXPORT_FUNC void stop_tracing (void);
- IP_AGENT_EXPORT_FUNC void
- stop_tracing (void)
- {
- /* GDBserver places breakpoint here. */
- UNKNOWN_SIDE_EFFECTS();
- }
- /* This is needed for -Wmissing-declarations. */
- IP_AGENT_EXPORT_FUNC void flush_trace_buffer (void);
- IP_AGENT_EXPORT_FUNC void
- flush_trace_buffer (void)
- {
- /* GDBserver places breakpoint here. */
- UNKNOWN_SIDE_EFFECTS();
- }
- #endif
- #ifndef IN_PROCESS_AGENT
- static int
- tracepoint_handler (CORE_ADDR address)
- {
- trace_debug ("tracepoint_handler: tracepoint at 0x%s hit",
- paddress (address));
- return 0;
- }
- /* Breakpoint at "stop_tracing" in the inferior lib. */
- static struct breakpoint *stop_tracing_bkpt;
- static int stop_tracing_handler (CORE_ADDR);
- /* Breakpoint at "flush_trace_buffer" in the inferior lib. */
- static struct breakpoint *flush_trace_buffer_bkpt;
- static int flush_trace_buffer_handler (CORE_ADDR);
- static void download_trace_state_variables (void);
- static void upload_fast_traceframes (void);
- static int run_inferior_command (char *cmd, int len);
- static int
- read_inferior_integer (CORE_ADDR symaddr, int *val)
- {
- return read_inferior_memory (symaddr, (unsigned char *) val,
- sizeof (*val));
- }
- struct tracepoint;
- static int tracepoint_send_agent (struct tracepoint *tpoint);
- static int
- read_inferior_uinteger (CORE_ADDR symaddr, unsigned int *val)
- {
- return read_inferior_memory (symaddr, (unsigned char *) val,
- sizeof (*val));
- }
- static int
- read_inferior_data_pointer (CORE_ADDR symaddr, CORE_ADDR *val)
- {
- void *pval = (void *) (uintptr_t) val;
- int ret;
- ret = read_inferior_memory (symaddr, (unsigned char *) &pval, sizeof (pval));
- *val = (uintptr_t) pval;
- return ret;
- }
- static int
- write_inferior_data_pointer (CORE_ADDR symaddr, CORE_ADDR val)
- {
- void *pval = (void *) (uintptr_t) val;
- return target_write_memory (symaddr,
- (unsigned char *) &pval, sizeof (pval));
- }
- static int
- write_inferior_integer (CORE_ADDR symaddr, int val)
- {
- return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val));
- }
- static int
- write_inferior_int8 (CORE_ADDR symaddr, int8_t val)
- {
- return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val));
- }
- static int
- write_inferior_uinteger (CORE_ADDR symaddr, unsigned int val)
- {
- return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val));
- }
- static CORE_ADDR target_malloc (ULONGEST size);
- #define COPY_FIELD_TO_BUF(BUF, OBJ, FIELD) \
- do { \
- memcpy (BUF, &(OBJ)->FIELD, sizeof ((OBJ)->FIELD)); \
- BUF += sizeof ((OBJ)->FIELD); \
- } while (0)
- #endif
- /* Base action. Concrete actions inherit this. */
- struct tracepoint_action
- {
- char type;
- };
- /* An 'M' (collect memory) action. */
- struct collect_memory_action
- {
- struct tracepoint_action base;
- ULONGEST addr;
- ULONGEST len;
- int32_t basereg;
- };
- /* An 'R' (collect registers) action. */
- struct collect_registers_action
- {
- struct tracepoint_action base;
- };
- /* An 'X' (evaluate expression) action. */
- struct eval_expr_action
- {
- struct tracepoint_action base;
- struct agent_expr *expr;
- };
- /* An 'L' (collect static trace data) action. */
- struct collect_static_trace_data_action
- {
- struct tracepoint_action base;
- };
- #ifndef IN_PROCESS_AGENT
- static CORE_ADDR
- m_tracepoint_action_download (const struct tracepoint_action *action)
- {
- CORE_ADDR ipa_action = target_malloc (sizeof (struct collect_memory_action));
- target_write_memory (ipa_action, (unsigned char *) action,
- sizeof (struct collect_memory_action));
- return ipa_action;
- }
- static char *
- m_tracepoint_action_send (char *buffer, const struct tracepoint_action *action)
- {
- struct collect_memory_action *maction
- = (struct collect_memory_action *) action;
- COPY_FIELD_TO_BUF (buffer, maction, addr);
- COPY_FIELD_TO_BUF (buffer, maction, len);
- COPY_FIELD_TO_BUF (buffer, maction, basereg);
- return buffer;
- }
- static CORE_ADDR
- r_tracepoint_action_download (const struct tracepoint_action *action)
- {
- CORE_ADDR ipa_action = target_malloc (sizeof (struct collect_registers_action));
- target_write_memory (ipa_action, (unsigned char *) action,
- sizeof (struct collect_registers_action));
- return ipa_action;
- }
- static char *
- r_tracepoint_action_send (char *buffer, const struct tracepoint_action *action)
- {
- return buffer;
- }
- static CORE_ADDR download_agent_expr (struct agent_expr *expr);
- static CORE_ADDR
- x_tracepoint_action_download (const struct tracepoint_action *action)
- {
- CORE_ADDR ipa_action = target_malloc (sizeof (struct eval_expr_action));
- CORE_ADDR expr;
- target_write_memory (ipa_action, (unsigned char *) action,
- sizeof (struct eval_expr_action));
- expr = download_agent_expr (((struct eval_expr_action *) action)->expr);
- write_inferior_data_pointer (ipa_action
- + offsetof (struct eval_expr_action, expr),
- expr);
- return ipa_action;
- }
- /* Copy agent expression AEXPR to buffer pointed by P. If AEXPR is NULL,
- copy 0 to P. Return updated header of buffer. */
- static char *
- agent_expr_send (char *p, const struct agent_expr *aexpr)
- {
- /* Copy the length of condition first, and then copy its
- content. */
- if (aexpr == NULL)
- {
- memset (p, 0, 4);
- p += 4;
- }
- else
- {
- memcpy (p, &aexpr->length, 4);
- p +=4;
- memcpy (p, aexpr->bytes, aexpr->length);
- p += aexpr->length;
- }
- return p;
- }
- static char *
- x_tracepoint_action_send ( char *buffer, const struct tracepoint_action *action)
- {
- struct eval_expr_action *eaction = (struct eval_expr_action *) action;
- return agent_expr_send (buffer, eaction->expr);
- }
- static CORE_ADDR
- l_tracepoint_action_download (const struct tracepoint_action *action)
- {
- CORE_ADDR ipa_action
- = target_malloc (sizeof (struct collect_static_trace_data_action));
- target_write_memory (ipa_action, (unsigned char *) action,
- sizeof (struct collect_static_trace_data_action));
- return ipa_action;
- }
- static char *
- l_tracepoint_action_send (char *buffer, const struct tracepoint_action *action)
- {
- return buffer;
- }
- static char *
- tracepoint_action_send (char *buffer, const struct tracepoint_action *action)
- {
- switch (action->type)
- {
- case 'M':
- return m_tracepoint_action_send (buffer, action);
- case 'R':
- return r_tracepoint_action_send (buffer, action);
- case 'X':
- return x_tracepoint_action_send (buffer, action);
- case 'L':
- return l_tracepoint_action_send (buffer, action);
- }
- error ("Unknown trace action '%c'.", action->type);
- }
- static CORE_ADDR
- tracepoint_action_download (const struct tracepoint_action *action)
- {
- switch (action->type)
- {
- case 'M':
- return m_tracepoint_action_download (action);
- case 'R':
- return r_tracepoint_action_download (action);
- case 'X':
- return x_tracepoint_action_download (action);
- case 'L':
- return l_tracepoint_action_download (action);
- }
- error ("Unknown trace action '%c'.", action->type);
- }
- #endif
- /* This structure describes a piece of the source-level definition of
- the tracepoint. The contents are not interpreted by the target,
- but preserved verbatim for uploading upon reconnection. */
- struct source_string
- {
- /* The type of string, such as "cond" for a conditional. */
- char *type;
- /* The source-level string itself. For the sake of target
- debugging, we store it in plaintext, even though it is always
- transmitted in hex. */
- char *str;
- /* Link to the next one in the list. We link them in the order
- received, in case some make up an ordered list of commands or
- some such. */
- struct source_string *next;
- };
- enum tracepoint_type
- {
- /* Trap based tracepoint. */
- trap_tracepoint,
- /* A fast tracepoint implemented with a jump instead of a trap. */
- fast_tracepoint,
- /* A static tracepoint, implemented by a program call into a tracing
- library. */
- static_tracepoint
- };
- struct tracepoint_hit_ctx;
- typedef enum eval_result_type (*condfn) (unsigned char *,
- ULONGEST *);
- /* The definition of a tracepoint. */
- /* Tracepoints may have multiple locations, each at a different
- address. This can occur with optimizations, template
- instantiation, etc. Since the locations may be in different
- scopes, the conditions and actions may be different for each
- location. Our target version of tracepoints is more like GDB's
- notion of "breakpoint locations", but we have almost nothing that
- is not per-location, so we bother having two kinds of objects. The
- key consequence is that numbers are not unique, and that it takes
- both number and address to identify a tracepoint uniquely. */
- struct tracepoint
- {
- /* The number of the tracepoint, as specified by GDB. Several
- tracepoint objects here may share a number. */
- uint32_t number;
- /* Address at which the tracepoint is supposed to trigger. Several
- tracepoints may share an address. */
- CORE_ADDR address;
- /* Tracepoint type. */
- enum tracepoint_type type;
- /* True if the tracepoint is currently enabled. */
- int8_t enabled;
- /* The number of single steps that will be performed after each
- tracepoint hit. */
- uint64_t step_count;
- /* The number of times the tracepoint may be hit before it will
- terminate the entire tracing run. */
- uint64_t pass_count;
- /* Pointer to the agent expression that is the tracepoint's
- conditional, or NULL if the tracepoint is unconditional. */
- struct agent_expr *cond;
- /* The list of actions to take when the tracepoint triggers. */
- uint32_t numactions;
- struct tracepoint_action **actions;
- /* Count of the times we've hit this tracepoint during the run.
- Note that while-stepping steps are not counted as "hits". */
- uint64_t hit_count;
- /* Cached sum of the sizes of traceframes created by this point. */
- uint64_t traceframe_usage;
- CORE_ADDR compiled_cond;
- /* Link to the next tracepoint in the list. */
- struct tracepoint *next;
- #ifndef IN_PROCESS_AGENT
- /* The list of actions to take when the tracepoint triggers, in
- string/packet form. */
- char **actions_str;
- /* The collection of strings that describe the tracepoint as it was
- entered into GDB. These are not used by the target, but are
- reported back to GDB upon reconnection. */
- struct source_string *source_strings;
- /* The number of bytes displaced by fast tracepoints. It may subsume
- multiple instructions, for multi-byte fast tracepoints. This
- field is only valid for fast tracepoints. */
- uint32_t orig_size;
- /* Only for fast tracepoints. */
- CORE_ADDR obj_addr_on_target;
- /* Address range where the original instruction under a fast
- tracepoint was relocated to. (_end is actually one byte past
- the end). */
- CORE_ADDR adjusted_insn_addr;
- CORE_ADDR adjusted_insn_addr_end;
- /* The address range of the piece of the jump pad buffer that was
- assigned to this fast tracepoint. (_end is actually one byte
- past the end).*/
- CORE_ADDR jump_pad;
- CORE_ADDR jump_pad_end;
- /* The address range of the piece of the trampoline buffer that was
- assigned to this fast tracepoint. (_end is actually one byte
- past the end). */
- CORE_ADDR trampoline;
- CORE_ADDR trampoline_end;
- /* The list of actions to take while in a stepping loop. These
- fields are only valid for patch-based tracepoints. */
- int num_step_actions;
- struct tracepoint_action **step_actions;
- /* Same, but in string/packet form. */
- char **step_actions_str;
- /* Handle returned by the breakpoint or tracepoint module when we
- inserted the trap or jump, or hooked into a static tracepoint.
- NULL if we haven't inserted it yet. */
- void *handle;
- #endif
- };
- #ifndef IN_PROCESS_AGENT
- /* Given `while-stepping', a thread may be collecting data for more
- than one tracepoint simultaneously. On the other hand, the same
- tracepoint with a while-stepping action may be hit by more than one
- thread simultaneously (but not quite, each thread could be handling
- a different step). Each thread holds a list of these objects,
- representing the current step of each while-stepping action being
- collected. */
- struct wstep_state
- {
- struct wstep_state *next;
- /* The tracepoint number. */
- int tp_number;
- /* The tracepoint's address. */
- CORE_ADDR tp_address;
- /* The number of the current step in this 'while-stepping'
- action. */
- long current_step;
- };
- #endif
- EXTERN_C_PUSH
- /* The linked list of all tracepoints. Marked explicitly as used as
- the in-process library doesn't use it for the fast tracepoints
- support. */
- IP_AGENT_EXPORT_VAR struct tracepoint *tracepoints;
- /* The first tracepoint to exceed its pass count. */
- IP_AGENT_EXPORT_VAR struct tracepoint *stopping_tracepoint;
- /* True if the trace buffer is full or otherwise no longer usable. */
- IP_AGENT_EXPORT_VAR int trace_buffer_is_full;
- /* The first error that occurred during expression evaluation. */
- /* Stored as an int to avoid the IPA ABI being dependent on whatever
- the compiler decides to use for the enum's underlying type. Holds
- enum eval_result_type values. */
- IP_AGENT_EXPORT_VAR int expr_eval_result = expr_eval_no_error;
- EXTERN_C_POP
- #ifndef IN_PROCESS_AGENT
- /* Pointer to the last tracepoint in the list, new tracepoints are
- linked in at the end. */
- static struct tracepoint *last_tracepoint;
- static const char * const eval_result_names[] =
- {
- "terror:in the attic", /* this should never be reported */
- "terror:empty expression",
- "terror:empty stack",
- "terror:stack overflow",
- "terror:stack underflow",
- "terror:unhandled opcode",
- "terror:unrecognized opcode",
- "terror:divide by zero"
- };
- #endif
- /* The tracepoint in which the error occurred. */
- EXTERN_C_PUSH
- IP_AGENT_EXPORT_VAR struct tracepoint *error_tracepoint;
- EXTERN_C_POP
- struct trace_state_variable
- {
- /* This is the name of the variable as used in GDB. The target
- doesn't use the name, but needs to have it for saving and
- reconnection purposes. */
- char *name;
- /* This number identifies the variable uniquely. Numbers may be
- assigned either by the target (in the case of builtin variables),
- or by GDB, and are presumed unique during the course of a trace
- experiment. */
- int number;
- /* The variable's initial value, a 64-bit signed integer always. */
- LONGEST initial_value;
- /* The variable's value, a 64-bit signed integer always. */
- LONGEST value;
- /* Pointer to a getter function, used to supply computed values. */
- LONGEST (*getter) (void);
- /* Link to the next variable. */
- struct trace_state_variable *next;
- };
- /* Linked list of all trace state variables. */
- #ifdef IN_PROCESS_AGENT
- static struct trace_state_variable *alloced_trace_state_variables;
- #endif
- IP_AGENT_EXPORT_VAR struct trace_state_variable *trace_state_variables;
- /* The results of tracing go into a fixed-size space known as the
- "trace buffer". Because usage follows a limited number of
- patterns, we manage it ourselves rather than with malloc. Basic
- rules are that we create only one trace frame at a time, each is
- variable in size, they are never moved once created, and we only
- discard if we are doing a circular buffer, and then only the oldest
- ones. Each trace frame includes its own size, so we don't need to
- link them together, and the trace frame number is relative to the
- first one, so we don't need to record numbers. A trace frame also
- records the number of the tracepoint that created it. The data
- itself is a series of blocks, each introduced by a single character
- and with a defined format. Each type of block has enough
- type/length info to allow scanners to jump quickly from one block
- to the next without reading each byte in the block. */
- /* Trace buffer management would be simple - advance a free pointer
- from beginning to end, then stop - were it not for the circular
- buffer option, which is a useful way to prevent a trace run from
- stopping prematurely because the buffer filled up. In the circular
- case, the location of the first trace frame (trace_buffer_start)
- moves as old trace frames are discarded. Also, since we grow trace
- frames incrementally as actions are performed, we wrap around to
- the beginning of the trace buffer. This is per-block, so each
- block within a trace frame remains contiguous. Things get messy
- when the wrapped-around trace frame is the one being discarded; the
- free space ends up in two parts at opposite ends of the buffer. */
- #ifndef ATTR_PACKED
- # if defined(__GNUC__)
- # define ATTR_PACKED __attribute__ ((packed))
- # else
- # define ATTR_PACKED /* nothing */
- # endif
- #endif
- /* The data collected at a tracepoint hit. This object should be as
- small as possible, since there may be a great many of them. We do
- not need to keep a frame number, because they are all sequential
- and there are no deletions; so the Nth frame in the buffer is
- always frame number N. */
- struct traceframe
- {
- /* Number of the tracepoint that collected this traceframe. A value
- of 0 indicates the current end of the trace buffer. We make this
- a 16-bit field because it's never going to happen that GDB's
- numbering of tracepoints reaches 32,000. */
- int tpnum : 16;
- /* The size of the data in this trace frame. We limit this to 32
- bits, even on a 64-bit target, because it's just implausible that
- one is validly going to collect 4 gigabytes of data at a single
- tracepoint hit. */
- unsigned int data_size : 32;
- /* The base of the trace data, which is contiguous from this point. */
- unsigned char data[0];
- } ATTR_PACKED;
- /* The size of the EOB marker, in bytes. A traceframe with zeroed
- fields (and no data) marks the end of trace data. */
- #define TRACEFRAME_EOB_MARKER_SIZE offsetof (struct traceframe, data)
- /* This flag is true if the trace buffer is circular, meaning that
- when it fills, the oldest trace frames are discarded in order to
- make room. */
- #ifndef IN_PROCESS_AGENT
- static int circular_trace_buffer;
- #endif
- /* Size of the trace buffer. */
- static LONGEST trace_buffer_size;
- EXTERN_C_PUSH
- /* Pointer to the block of memory that traceframes all go into. */
- IP_AGENT_EXPORT_VAR unsigned char *trace_buffer_lo;
- /* Pointer to the end of the trace buffer, more precisely to the byte
- after the end of the buffer. */
- IP_AGENT_EXPORT_VAR unsigned char *trace_buffer_hi;
- EXTERN_C_POP
- /* Control structure holding the read/write/etc. pointers into the
- trace buffer. We need more than one of these to implement a
- transaction-like mechanism to guarantees that both GDBserver and the
- in-process agent can try to change the trace buffer
- simultaneously. */
- struct trace_buffer_control
- {
- /* Pointer to the first trace frame in the buffer. In the
- non-circular case, this is equal to trace_buffer_lo, otherwise it
- moves around in the buffer. */
- unsigned char *start;
- /* Pointer to the free part of the trace buffer. Note that we clear
- several bytes at and after this pointer, so that traceframe
- scans/searches terminate properly. */
- unsigned char *free;
- /* Pointer to the byte after the end of the free part. Note that
- this may be smaller than trace_buffer_free in the circular case,
- and means that the free part is in two pieces. Initially it is
- equal to trace_buffer_hi, then is generally equivalent to
- trace_buffer_start. */
- unsigned char *end_free;
- /* Pointer to the wraparound. If not equal to trace_buffer_hi, then
- this is the point at which the trace data breaks, and resumes at
- trace_buffer_lo. */
- unsigned char *wrap;
- };
- /* Same as above, to be used by GDBserver when updating the in-process
- agent. */
- struct ipa_trace_buffer_control
- {
- uintptr_t start;
- uintptr_t free;
- uintptr_t end_free;
- uintptr_t wrap;
- };
- /* We have possibly both GDBserver and an inferior thread accessing
- the same IPA trace buffer memory. The IPA is the producer (tries
- to put new frames in the buffer), while GDBserver occasionally
- consumes them, that is, flushes the IPA's buffer into its own
- buffer. Both sides need to update the trace buffer control
- pointers (current head, tail, etc.). We can't use a global lock to
- synchronize the accesses, as otherwise we could deadlock GDBserver
- (if the thread holding the lock stops for a signal, say). So
- instead of that, we use a transaction scheme where GDBserver writes
- always prevail over the IPAs writes, and, we have the IPA detect
- the commit failure/overwrite, and retry the whole attempt. This is
- mainly implemented by having a global token object that represents
- who wrote last to the buffer control structure. We need to freeze
- any inferior writing to the buffer while GDBserver touches memory,
- so that the inferior can correctly detect that GDBserver had been
- there, otherwise, it could mistakingly think its commit was
- successful; that's implemented by simply having GDBserver set a
- breakpoint the inferior hits if it is the critical region.
- There are three cycling trace buffer control structure copies
- (buffer head, tail, etc.), with the token object including an index
- indicating which is current live copy. The IPA tentatively builds
- an updated copy in a non-current control structure, while GDBserver
- always clobbers the current version directly. The IPA then tries
- to atomically "commit" its version; if GDBserver clobbered the
- structure meanwhile, that will fail, and the IPA restarts the
- allocation process.
- Listing the step in further detail, we have:
- In-process agent (producer):
- - passes by `about_to_request_buffer_space' breakpoint/lock
- - reads current token, extracts current trace buffer control index,
- and starts tentatively updating the rightmost one (0->1, 1->2,
- 2->0). Note that only one inferior thread is executing this code
- at any given time, due to an outer lock in the jump pads.
- - updates counters, and tries to commit the token.
- - passes by second `about_to_request_buffer_space' breakpoint/lock,
- leaving the sync region.
- - checks if the update was effective.
- - if trace buffer was found full, hits flush_trace_buffer
- breakpoint, and restarts later afterwards.
- GDBserver (consumer):
- - sets `about_to_request_buffer_space' breakpoint/lock.
- - updates the token unconditionally, using the current buffer
- control index, since it knows that the IP agent always writes to
- the rightmost, and due to the breakpoint, at most one IP thread
- can try to update the trace buffer concurrently to GDBserver, so
- there will be no danger of trace buffer control index wrap making
- the IPA write to the same index as GDBserver.
- - flushes the IP agent's trace buffer completely, and updates the
- current trace buffer control structure. GDBserver *always* wins.
- - removes the `about_to_request_buffer_space' breakpoint.
- The token is stored in the `trace_buffer_ctrl_curr' variable.
- Internally, it's bits are defined as:
- |-------------+-----+-------------+--------+-------------+--------------|
- | Bit offsets | 31 | 30 - 20 | 19 | 18-8 | 7-0 |
- |-------------+-----+-------------+--------+-------------+--------------|
- | What | GSB | PC (11-bit) | unused | CC (11-bit) | TBCI (8-bit) |
- |-------------+-----+-------------+--------+-------------+--------------|
- GSB - GDBserver Stamp Bit
- PC - Previous Counter
- CC - Current Counter
- TBCI - Trace Buffer Control Index
- An IPA update of `trace_buffer_ctrl_curr' does:
- - read CC from the current token, save as PC.
- - updates pointers
- - atomically tries to write PC+1,CC
- A GDBserver update of `trace_buffer_ctrl_curr' does:
- - reads PC and CC from the current token.
- - updates pointers
- - writes GSB,PC,CC
- */
- /* These are the bits of `trace_buffer_ctrl_curr' that are reserved
- for the counters described below. The cleared bits are used to
- hold the index of the items of the `trace_buffer_ctrl' array that
- is "current". */
- #define GDBSERVER_FLUSH_COUNT_MASK 0xfffffff0
- /* `trace_buffer_ctrl_curr' contains two counters. The `previous'
- counter, and the `current' counter. */
- #define GDBSERVER_FLUSH_COUNT_MASK_PREV 0x7ff00000
- #define GDBSERVER_FLUSH_COUNT_MASK_CURR 0x0007ff00
- /* When GDBserver update the IP agent's `trace_buffer_ctrl_curr', it
- always stamps this bit as set. */
- #define GDBSERVER_UPDATED_FLUSH_COUNT_BIT 0x80000000
- #ifdef IN_PROCESS_AGENT
- IP_AGENT_EXPORT_VAR struct trace_buffer_control trace_buffer_ctrl[3];
- IP_AGENT_EXPORT_VAR unsigned int trace_buffer_ctrl_curr;
- # define TRACE_BUFFER_CTRL_CURR \
- (trace_buffer_ctrl_curr & ~GDBSERVER_FLUSH_COUNT_MASK)
- #else
- /* The GDBserver side agent only needs one instance of this object, as
- it doesn't need to sync with itself. Define it as array anyway so
- that the rest of the code base doesn't need to care for the
- difference. */
- static trace_buffer_control trace_buffer_ctrl[1];
- # define TRACE_BUFFER_CTRL_CURR 0
- #endif
- /* These are convenience macros used to access the current trace
- buffer control in effect. */
- #define trace_buffer_start (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].start)
- #define trace_buffer_free (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].free)
- #define trace_buffer_end_free \
- (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].end_free)
- #define trace_buffer_wrap (trace_buffer_ctrl[TRACE_BUFFER_CTRL_CURR].wrap)
- /* Macro that returns a pointer to the first traceframe in the buffer. */
- #define FIRST_TRACEFRAME() ((struct traceframe *) trace_buffer_start)
- /* Macro that returns a pointer to the next traceframe in the buffer.
- If the computed location is beyond the wraparound point, subtract
- the offset of the wraparound. */
- #define NEXT_TRACEFRAME_1(TF) \
- (((unsigned char *) (TF)) + sizeof (struct traceframe) + (TF)->data_size)
- #define NEXT_TRACEFRAME(TF) \
- ((struct traceframe *) (NEXT_TRACEFRAME_1 (TF) \
- - ((NEXT_TRACEFRAME_1 (TF) >= trace_buffer_wrap) \
- ? (trace_buffer_wrap - trace_buffer_lo) \
- : 0)))
- /* The difference between these counters represents the total number
- of complete traceframes present in the trace buffer. The IP agent
- writes to the write count, GDBserver writes to read count. */
- IP_AGENT_EXPORT_VAR unsigned int traceframe_write_count;
- IP_AGENT_EXPORT_VAR unsigned int traceframe_read_count;
- /* Convenience macro. */
- #define traceframe_count \
- ((unsigned int) (traceframe_write_count - traceframe_read_count))
- /* The count of all traceframes created in the current run, including
- ones that were discarded to make room. */
- IP_AGENT_EXPORT_VAR int traceframes_created;
- #ifndef IN_PROCESS_AGENT
- /* Read-only regions are address ranges whose contents don't change,
- and so can be read from target memory even while looking at a trace
- frame. Without these, disassembly for instance will likely fail,
- because the program code is not usually collected into a trace
- frame. This data structure does not need to be very complicated or
- particularly efficient, it's only going to be used occasionally,
- and only by some commands. */
- struct readonly_region
- {
- /* The bounds of the region. */
- CORE_ADDR start, end;
- /* Link to the next one. */
- struct readonly_region *next;
- };
- /* Linked list of readonly regions. This list stays in effect from
- one tstart to the next. */
- static struct readonly_region *readonly_regions;
- #endif
- /* The global that controls tracing overall. */
- IP_AGENT_EXPORT_VAR int tracing;
- #ifndef IN_PROCESS_AGENT
- /* Controls whether tracing should continue after GDB disconnects. */
- int disconnected_tracing;
- /* The reason for the last tracing run to have stopped. We initialize
- to a distinct string so that GDB can distinguish between "stopped
- after running" and "stopped because never run" cases. */
- static const char *tracing_stop_reason = "tnotrun";
- static int tracing_stop_tpnum;
- /* 64-bit timestamps for the trace run's start and finish, expressed
- in microseconds from the Unix epoch. */
- static LONGEST tracing_start_time;
- static LONGEST tracing_stop_time;
- /* The (optional) user-supplied name of the user that started the run.
- This is an arbitrary string, and may be NULL. */
- static char *tracing_user_name;
- /* Optional user-supplied text describing the run. This is
- an arbitrary string, and may be NULL. */
- static char *tracing_notes;
- /* Optional user-supplied text explaining a tstop command. This is an
- arbitrary string, and may be NULL. */
- static char *tracing_stop_note;
- #endif
- /* Functions local to this file. */
- /* Base "class" for tracepoint type specific data to be passed down to
- collect_data_at_tracepoint. */
- struct tracepoint_hit_ctx
- {
- enum tracepoint_type type;
- };
- #ifdef IN_PROCESS_AGENT
- /* Fast/jump tracepoint specific data to be passed down to
- collect_data_at_tracepoint. */
- struct fast_tracepoint_ctx
- {
- struct tracepoint_hit_ctx base;
- struct regcache regcache;
- int regcache_initted;
- unsigned char *regspace;
- unsigned char *regs;
- struct tracepoint *tpoint;
- };
- /* Static tracepoint specific data to be passed down to
- collect_data_at_tracepoint. */
- struct static_tracepoint_ctx
- {
- struct tracepoint_hit_ctx base;
- /* The regcache corresponding to the registers state at the time of
- the tracepoint hit. Initialized lazily, from REGS. */
- struct regcache regcache;
- int regcache_initted;
- /* The buffer space REGCACHE above uses. We use a separate buffer
- instead of letting the regcache malloc for both signal safety and
- performance reasons; this is allocated on the stack instead. */
- unsigned char *regspace;
- /* The register buffer as passed on by lttng/ust. */
- struct registers *regs;
- /* The "printf" formatter and the args the user passed to the marker
- call. We use this to be able to collect "static trace data"
- ($_sdata). */
- const char *fmt;
- va_list *args;
- /* The GDB tracepoint matching the probed marker that was "hit". */
- struct tracepoint *tpoint;
- };
- #else
- /* Static tracepoint specific data to be passed down to
- collect_data_at_tracepoint. */
- struct trap_tracepoint_ctx
- {
- struct tracepoint_hit_ctx base;
- struct regcache *regcache;
- };
- #endif
- #ifndef IN_PROCESS_AGENT
- static CORE_ADDR traceframe_get_pc (struct traceframe *tframe);
- static int traceframe_read_tsv (int num, LONGEST *val);
- #endif
- static int condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx,
- struct tracepoint *tpoint);
- #ifndef IN_PROCESS_AGENT
- static void clear_readonly_regions (void);
- static void clear_installed_tracepoints (void);
- #endif
- static void collect_data_at_tracepoint (struct tracepoint_hit_ctx *ctx,
- CORE_ADDR stop_pc,
- struct tracepoint *tpoint);
- #ifndef IN_PROCESS_AGENT
- static void collect_data_at_step (struct tracepoint_hit_ctx *ctx,
- CORE_ADDR stop_pc,
- struct tracepoint *tpoint, int current_step);
- static void compile_tracepoint_condition (struct tracepoint *tpoint,
- CORE_ADDR *jump_entry);
- #endif
- static void do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
- CORE_ADDR stop_pc,
- struct tracepoint *tpoint,
- struct traceframe *tframe,
- struct tracepoint_action *taction);
- #ifndef IN_PROCESS_AGENT
- static struct tracepoint *fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR);
- static void install_tracepoint (struct tracepoint *, char *own_buf);
- static void download_tracepoint (struct tracepoint *);
- static int install_fast_tracepoint (struct tracepoint *, char *errbuf);
- static void clone_fast_tracepoint (struct tracepoint *to,
- const struct tracepoint *from);
- #endif
- static LONGEST get_timestamp (void);
- #if defined(__GNUC__)
- # define memory_barrier() asm volatile ("" : : : "memory")
- #else
- # define memory_barrier() do {} while (0)
- #endif
- /* We only build the IPA if this builtin is supported, and there are
- no uses of this in GDBserver itself, so we're safe in defining this
- unconditionally. */
- #define cmpxchg(mem, oldval, newval) \
- __sync_val_compare_and_swap (mem, oldval, newval)
- /* Record that an error occurred during expression evaluation. */
- static void
- record_tracepoint_error (struct tracepoint *tpoint, const char *which,
- enum eval_result_type rtype)
- {
- trace_debug ("Tracepoint %d at %s %s eval reports error %d",
- tpoint->number, paddress (tpoint->address), which, rtype);
- #ifdef IN_PROCESS_AGENT
- /* Only record the first error we get. */
- if (cmpxchg (&expr_eval_result,
- expr_eval_no_error,
- rtype) != expr_eval_no_error)
- return;
- #else
- if (expr_eval_result != expr_eval_no_error)
- return;
- #endif
- error_tracepoint = tpoint;
- }
- /* Trace buffer management. */
- static void
- clear_trace_buffer (void)
- {
- trace_buffer_start = trace_buffer_lo;
- trace_buffer_free = trace_buffer_lo;
- trace_buffer_end_free = trace_buffer_hi;
- trace_buffer_wrap = trace_buffer_hi;
- /* A traceframe with zeroed fields marks the end of trace data. */
- ((struct traceframe *) trace_buffer_free)->tpnum = 0;
- ((struct traceframe *) trace_buffer_free)->data_size = 0;
- traceframe_read_count = traceframe_write_count = 0;
- traceframes_created = 0;
- }
- #ifndef IN_PROCESS_AGENT
- static void
- clear_inferior_trace_buffer (void)
- {
- CORE_ADDR ipa_trace_buffer_lo;
- CORE_ADDR ipa_trace_buffer_hi;
- struct traceframe ipa_traceframe = { 0 };
- struct ipa_trace_buffer_control ipa_trace_buffer_ctrl;
- read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_lo,
- &ipa_trace_buffer_lo);
- read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_hi,
- &ipa_trace_buffer_hi);
- ipa_trace_buffer_ctrl.start = ipa_trace_buffer_lo;
- ipa_trace_buffer_ctrl.free = ipa_trace_buffer_lo;
- ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_hi;
- ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi;
- /* A traceframe with zeroed fields marks the end of trace data. */
- target_write_memory (ipa_sym_addrs.addr_trace_buffer_ctrl,
- (unsigned char *) &ipa_trace_buffer_ctrl,
- sizeof (ipa_trace_buffer_ctrl));
- write_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr, 0);
- /* A traceframe with zeroed fields marks the end of trace data. */
- target_write_memory (ipa_trace_buffer_lo,
- (unsigned char *) &ipa_traceframe,
- sizeof (ipa_traceframe));
- write_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count, 0);
- write_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count, 0);
- write_inferior_integer (ipa_sym_addrs.addr_traceframes_created, 0);
- }
- #endif
- static void
- init_trace_buffer (LONGEST bufsize)
- {
- size_t alloc_size;
- trace_buffer_size = bufsize;
- /* Make sure to internally allocate at least space for the EOB
- marker. */
- alloc_size = (bufsize < TRACEFRAME_EOB_MARKER_SIZE
- ? TRACEFRAME_EOB_MARKER_SIZE : bufsize);
- trace_buffer_lo = (unsigned char *) xrealloc (trace_buffer_lo, alloc_size);
- trace_buffer_hi = trace_buffer_lo + trace_buffer_size;
- clear_trace_buffer ();
- }
- #ifdef IN_PROCESS_AGENT
- /* This is needed for -Wmissing-declarations. */
- IP_AGENT_EXPORT_FUNC void about_to_request_buffer_space (void);
- IP_AGENT_EXPORT_FUNC void
- about_to_request_buffer_space (void)
- {
- /* GDBserver places breakpoint here while it goes about to flush
- data at random times. */
- UNKNOWN_SIDE_EFFECTS();
- }
- #endif
- /* Carve out a piece of the trace buffer, returning NULL in case of
- failure. */
- static void *
- trace_buffer_alloc (size_t amt)
- {
- unsigned char *rslt;
- struct trace_buffer_control *tbctrl;
- unsigned int curr;
- #ifdef IN_PROCESS_AGENT
- unsigned int prev, prev_filtered;
- unsigned int commit_count;
- unsigned int commit;
- unsigned int readout;
- #else
- struct traceframe *oldest;
- unsigned char *new_start;
- #endif
- trace_debug ("Want to allocate %ld+%ld bytes in trace buffer",
- (long) amt, (long) sizeof (struct traceframe));
- /* Account for the EOB marker. */
- amt += TRACEFRAME_EOB_MARKER_SIZE;
- #ifdef IN_PROCESS_AGENT
- again:
- memory_barrier ();
- /* Read the current token and extract the index to try to write to,
- storing it in CURR. */
- prev = trace_buffer_ctrl_curr;
- prev_filtered = prev & ~GDBSERVER_FLUSH_COUNT_MASK;
- curr = prev_filtered + 1;
- if (curr > 2)
- curr = 0;
- about_to_request_buffer_space ();
- /* Start out with a copy of the current state. GDBserver may be
- midway writing to the PREV_FILTERED TBC, but, that's OK, we won't
- be able to commit anyway if that happens. */
- trace_buffer_ctrl[curr]
- = trace_buffer_ctrl[prev_filtered];
- trace_debug ("trying curr=%u", curr);
- #else
- /* The GDBserver's agent doesn't need all that syncing, and always
- updates TCB 0 (there's only one, mind you). */
- curr = 0;
- #endif
- tbctrl = &trace_buffer_ctrl[curr];
- /* Offsets are easier to grok for debugging than raw addresses,
- especially for the small trace buffer sizes that are useful for
- testing. */
- trace_debug ("Trace buffer [%d] start=%d free=%d endfree=%d wrap=%d hi=%d",
- curr,
- (int) (tbctrl->start - trace_buffer_lo),
- (int) (tbctrl->free - trace_buffer_lo),
- (int) (tbctrl->end_free - trace_buffer_lo),
- (int) (tbctrl->wrap - trace_buffer_lo),
- (int) (trace_buffer_hi - trace_buffer_lo));
- /* The algorithm here is to keep trying to get a contiguous block of
- the requested size, possibly discarding older traceframes to free
- up space. Since free space might come in one or two pieces,
- depending on whether discarded traceframes wrapped around at the
- high end of the buffer, we test both pieces after each
- discard. */
- while (1)
- {
- /* First, if we have two free parts, try the upper one first. */
- if (tbctrl->end_free < tbctrl->free)
- {
- if (tbctrl->free + amt <= trace_buffer_hi)
- /* We have enough in the upper part. */
- break;
- else
- {
- /* Our high part of free space wasn't enough. Give up
- on it for now, set wraparound. We will recover the
- space later, if/when the wrapped-around traceframe is
- discarded. */
- trace_debug ("Upper part too small, setting wraparound");
- tbctrl->wrap = tbctrl->free;
- tbctrl->free = trace_buffer_lo;
- }
- }
- /* The normal case. */
- if (tbctrl->free + amt <= tbctrl->end_free)
- break;
- #ifdef IN_PROCESS_AGENT
- /* The IP Agent's buffer is always circular. It isn't used
- currently, but `circular_trace_buffer' could represent
- GDBserver's mode. If we didn't find space, ask GDBserver to
- flush. */
- flush_trace_buffer ();
- memory_barrier ();
- if (tracing)
- {
- trace_debug ("gdbserver flushed buffer, retrying");
- goto again;
- }
- /* GDBserver cancelled the tracing. Bail out as well. */
- return NULL;
- #else
- /* If we're here, then neither part is big enough, and
- non-circular trace buffers are now full. */
- if (!circular_trace_buffer)
- {
- trace_debug ("Not enough space in the trace buffer");
- return NULL;
- }
- trace_debug ("Need more space in the trace buffer");
- /* If we have a circular buffer, we can try discarding the
- oldest traceframe and see if that helps. */
- oldest = FIRST_TRACEFRAME ();
- if (oldest->tpnum == 0)
- {
- /* Not good; we have no traceframes to free. Perhaps we're
- asking for a block that is larger than the buffer? In
- any case, give up. */
- trace_debug ("No traceframes to discard");
- return NULL;
- }
- /* We don't run this code in the in-process agent currently.
- E.g., we could leave the in-process agent in autonomous
- circular mode if we only have fast tracepoints. If we do
- that, then this bit becomes racy with GDBserver, which also
- writes to this counter. */
- --traceframe_write_count;
- new_start = (unsigned char *) NEXT_TRACEFRAME (oldest);
- /* If we freed the traceframe that wrapped around, go back
- to the non-wrap case. */
- if (new_start < tbctrl->start)
- {
- trace_debug ("Discarding past the wraparound");
- tbctrl->wrap = trace_buffer_hi;
- }
- tbctrl->start = new_start;
- tbctrl->end_free = tbctrl->start;
- trace_debug ("Discarded a traceframe\n"
- "Trace buffer [%d], start=%d free=%d "
- "endfree=%d wrap=%d hi=%d",
- curr,
- (int) (tbctrl->start - trace_buffer_lo),
- (int) (tbctrl->free - trace_buffer_lo),
- (int) (tbctrl->end_free - trace_buffer_lo),
- (int) (tbctrl->wrap - trace_buffer_lo),
- (int) (trace_buffer_hi - trace_buffer_lo));
- /* Now go back around the loop. The discard might have resulted
- in either one or two pieces of free space, so we want to try
- both before freeing any more traceframes. */
- #endif
- }
- /* If we get here, we know we can provide the asked-for space. */
- rslt = tbctrl->free;
- /* Adjust the request back down, now that we know we have space for
- the marker, but don't commit to AMT yet, we may still need to
- restart the operation if GDBserver touches the trace buffer
- (obviously only important in the in-process agent's version). */
- tbctrl->free += (amt - sizeof (struct traceframe));
- /* Or not. If GDBserver changed the trace buffer behind our back,
- we get to restart a new allocation attempt. */
- #ifdef IN_PROCESS_AGENT
- /* Build the tentative token. */
- commit_count = (((prev & GDBSERVER_FLUSH_COUNT_MASK_CURR) + 0x100)
- & GDBSERVER_FLUSH_COUNT_MASK_CURR);
- commit = (((prev & GDBSERVER_FLUSH_COUNT_MASK_CURR) << 12)
- | commit_count
- | curr);
- /* Try to commit it. */
- readout = cmpxchg (&trace_buffer_ctrl_curr, prev, commit);
- if (readout != prev)
- {
- trace_debug ("GDBserver has touched the trace buffer, restarting."
- " (prev=%08x, commit=%08x, readout=%08x)",
- prev, commit, readout);
- goto again;
- }
- /* Hold your horses here. Even if that change was committed,
- GDBserver could come in, and clobber it. We need to hold to be
- able to tell if GDBserver clobbers before or after we committed
- the change. Whenever GDBserver goes about touching the IPA
- buffer, it sets a breakpoint in this routine, so we have a sync
- point here. */
- about_to_request_buffer_space ();
- /* Check if the change has been effective, even if GDBserver stopped
- us at the breakpoint. */
- {
- unsigned int refetch;
- memory_barrier ();
- refetch = trace_buffer_ctrl_curr;
- if (refetch == commit
- || ((refetch & GDBSERVER_FLUSH_COUNT_MASK_PREV) >> 12) == commit_count)
- {
- /* effective */
- trace_debug ("change is effective: (prev=%08x, commit=%08x, "
- "readout=%08x, refetch=%08x)",
- prev, commit, readout, refetch);
- }
- else
- {
- trace_debug ("GDBserver has touched the trace buffer, not effective."
- " (prev=%08x, commit=%08x, readout=%08x, refetch=%08x)",
- prev, commit, readout, refetch);
- goto again;
- }
- }
- #endif
- /* We have a new piece of the trace buffer. Hurray! */
- /* Add an EOB marker just past this allocation. */
- ((struct traceframe *) tbctrl->free)->tpnum = 0;
- ((struct traceframe *) tbctrl->free)->data_size = 0;
- /* Adjust the request back down, now that we know we have space for
- the marker. */
- amt -= sizeof (struct traceframe);
- if (debug_threads)
- {
- trace_debug ("Allocated %d bytes", (int) amt);
- trace_debug ("Trace buffer [%d] start=%d free=%d "
- "endfree=%d wrap=%d hi=%d",
- curr,
- (int) (tbctrl->start - trace_buffer_lo),
- (int) (tbctrl->free - trace_buffer_lo),
- (int) (tbctrl->end_free - trace_buffer_lo),
- (int) (tbctrl->wrap - trace_buffer_lo),
- (int) (trace_buffer_hi - trace_buffer_lo));
- }
- return rslt;
- }
- #ifndef IN_PROCESS_AGENT
- /* Return the total free space. This is not necessarily the largest
- block we can allocate, because of the two-part case. */
- static int
- free_space (void)
- {
- if (trace_buffer_free <= trace_buffer_end_free)
- return trace_buffer_end_free - trace_buffer_free;
- else
- return ((trace_buffer_end_free - trace_buffer_lo)
- + (trace_buffer_hi - trace_buffer_free));
- }
- /* An 'S' in continuation packets indicates remainder are for
- while-stepping. */
- static int seen_step_action_flag;
- /* Create a tracepoint (location) with given number and address. Add this
- new tracepoint to list and sort this list. */
- static struct tracepoint *
- add_tracepoint (int num, CORE_ADDR addr)
- {
- struct tracepoint *tpoint, **tp_next;
- tpoint = XNEW (struct tracepoint);
- tpoint->number = num;
- tpoint->address = addr;
- tpoint->numactions = 0;
- tpoint->actions = NULL;
- tpoint->actions_str = NULL;
- tpoint->cond = NULL;
- tpoint->num_step_actions = 0;
- tpoint->step_actions = NULL;
- tpoint->step_actions_str = NULL;
- /* Start all off as regular (slow) tracepoints. */
- tpoint->type = trap_tracepoint;
- tpoint->orig_size = -1;
- tpoint->source_strings = NULL;
- tpoint->compiled_cond = 0;
- tpoint->handle = NULL;
- tpoint->next = NULL;
- /* Find a place to insert this tracepoint into list in order to keep
- the tracepoint list still in the ascending order. There may be
- multiple tracepoints at the same address as TPOINT's, and this
- guarantees TPOINT is inserted after all the tracepoints which are
- set at the same address. For example, fast tracepoints A, B, C are
- set at the same address, and D is to be insert at the same place as
- well,
- -->| A |--> | B |-->| C |->...
- One jump pad was created for tracepoint A, B, and C, and the target
- address of A is referenced/used in jump pad. So jump pad will let
- inferior jump to A. If D is inserted in front of A, like this,
- -->| D |-->| A |--> | B |-->| C |->...
- without updating jump pad, D is not reachable during collect, which
- is wrong. As we can see, the order of B, C and D doesn't matter, but
- A should always be the `first' one. */
- for (tp_next = &tracepoints;
- (*tp_next) != NULL && (*tp_next)->address <= tpoint->address;
- tp_next = &(*tp_next)->next)
- ;
- tpoint->next = *tp_next;
- *tp_next = tpoint;
- last_tracepoint = tpoint;
- seen_step_action_flag = 0;
- return tpoint;
- }
- #ifndef IN_PROCESS_AGENT
- /* Return the tracepoint with the given number and address, or NULL. */
- static struct tracepoint *
- find_tracepoint (int id, CORE_ADDR addr)
- {
- struct tracepoint *tpoint;
- for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
- if (tpoint->number == id && tpoint->address == addr)
- return tpoint;
- return NULL;
- }
- /* Remove TPOINT from global list. */
- static void
- remove_tracepoint (struct tracepoint *tpoint)
- {
- struct tracepoint *tp, *tp_prev;
- for (tp = tracepoints, tp_prev = NULL; tp && tp != tpoint;
- tp_prev = tp, tp = tp->next)
- ;
- if (tp)
- {
- if (tp_prev)
- tp_prev->next = tp->next;
- else
- tracepoints = tp->next;
- xfree (tp);
- }
- }
- /* There may be several tracepoints with the same number (because they
- are "locations", in GDB parlance); return the next one after the
- given tracepoint, or search from the beginning of the list if the
- first argument is NULL. */
- static struct tracepoint *
- find_next_tracepoint_by_number (struct tracepoint *prev_tp, int num)
- {
- struct tracepoint *tpoint;
- if (prev_tp)
- tpoint = prev_tp->next;
- else
- tpoint = tracepoints;
- for (; tpoint; tpoint = tpoint->next)
- if (tpoint->number == num)
- return tpoint;
- return NULL;
- }
- #endif
- /* Append another action to perform when the tracepoint triggers. */
- static void
- add_tracepoint_action (struct tracepoint *tpoint, const char *packet)
- {
- const char *act;
- if (*packet == 'S')
- {
- seen_step_action_flag = 1;
- ++packet;
- }
- act = packet;
- while (*act)
- {
- const char *act_start = act;
- struct tracepoint_action *action = NULL;
- switch (*act)
- {
- case 'M':
- {
- struct collect_memory_action *maction =
- XNEW (struct collect_memory_action);
- ULONGEST basereg;
- int is_neg;
- maction->base.type = *act;
- action = &maction->base;
- ++act;
- is_neg = (*act == '-');
- if (*act == '-')
- ++act;
- act = unpack_varlen_hex (act, &basereg);
- ++act;
- act = unpack_varlen_hex (act, &maction->addr);
- ++act;
- act = unpack_varlen_hex (act, &maction->len);
- maction->basereg = (is_neg
- ? - (int) basereg
- : (int) basereg);
- trace_debug ("Want to collect %s bytes at 0x%s (basereg %d)",
- pulongest (maction->len),
- paddress (maction->addr), maction->basereg);
- break;
- }
- case 'R':
- {
- struct collect_registers_action *raction =
- XNEW (struct collect_registers_action);
- raction->base.type = *act;
- action = &raction->base;
- trace_debug ("Want to collect registers");
- ++act;
- /* skip past hex digits of mask for now */
- while (isxdigit(*act))
- ++act;
- break;
- }
- case 'L':
- {
- struct collect_static_trace_data_action *raction =
- XNEW (struct collect_static_trace_data_action);
- raction->base.type = *act;
- action = &raction->base;
- trace_debug ("Want to collect static trace data");
- ++act;
- break;
- }
- case 'S':
- trace_debug ("Unexpected step action, ignoring");
- ++act;
- break;
- case 'X':
- {
- struct eval_expr_action *xaction = XNEW (struct eval_expr_action);
- xaction->base.type = *act;
- action = &xaction->base;
- trace_debug ("Want to evaluate expression");
- xaction->expr = gdb_parse_agent_expr (&act);
- break;
- }
- default:
- trace_debug ("unknown trace action '%c', ignoring...", *act);
- break;
- case '-':
- break;
- }
- if (action == NULL)
- break;
- if (seen_step_action_flag)
- {
- tpoint->num_step_actions++;
- tpoint->step_actions
- = XRESIZEVEC (struct tracepoint_action *, tpoint->step_actions,
- tpoint->num_step_actions);
- tpoint->step_actions_str
- = XRESIZEVEC (char *, tpoint->step_actions_str,
- tpoint->num_step_actions);
- tpoint->step_actions[tpoint->num_step_actions - 1] = action;
- tpoint->step_actions_str[tpoint->num_step_actions - 1]
- = savestring (act_start, act - act_start);
- }
- else
- {
- tpoint->numactions++;
- tpoint->actions
- = XRESIZEVEC (struct tracepoint_action *, tpoint->actions,
- tpoint->numactions);
- tpoint->actions_str
- = XRESIZEVEC (char *, tpoint->actions_str, tpoint->numactions);
- tpoint->actions[tpoint->numactions - 1] = action;
- tpoint->actions_str[tpoint->numactions - 1]
- = savestring (act_start, act - act_start);
- }
- }
- }
- #endif
- /* Find or create a trace state variable with the given number. */
- static struct trace_state_variable *
- get_trace_state_variable (int num)
- {
- struct trace_state_variable *tsv;
- #ifdef IN_PROCESS_AGENT
- /* Search for an existing variable. */
- for (tsv = alloced_trace_state_variables; tsv; tsv = tsv->next)
- if (tsv->number == num)
- return tsv;
- #endif
- /* Search for an existing variable. */
- for (tsv = trace_state_variables; tsv; tsv = tsv->next)
- if (tsv->number == num)
- return tsv;
- return NULL;
- }
- /* Find or create a trace state variable with the given number. */
- static struct trace_state_variable *
- create_trace_state_variable (int num, int gdb)
- {
- struct trace_state_variable *tsv;
- tsv = get_trace_state_variable (num);
- if (tsv != NULL)
- return tsv;
- /* Create a new variable. */
- tsv = XNEW (struct trace_state_variable);
- tsv->number = num;
- tsv->initial_value = 0;
- tsv->value = 0;
- tsv->getter = NULL;
- tsv->name = NULL;
- #ifdef IN_PROCESS_AGENT
- if (!gdb)
- {
- tsv->next = alloced_trace_state_variables;
- alloced_trace_state_variables = tsv;
- }
- else
- #endif
- {
- tsv->next = trace_state_variables;
- trace_state_variables = tsv;
- }
- return tsv;
- }
- /* This is needed for -Wmissing-declarations. */
- IP_AGENT_EXPORT_FUNC LONGEST get_trace_state_variable_value (int num);
- IP_AGENT_EXPORT_FUNC LONGEST
- get_trace_state_variable_value (int num)
- {
- struct trace_state_variable *tsv;
- tsv = get_trace_state_variable (num);
- if (!tsv)
- {
- trace_debug ("No trace state variable %d, skipping value get", num);
- return 0;
- }
- /* Call a getter function if we have one. While it's tempting to
- set up something to only call the getter once per tracepoint hit,
- it could run afoul of thread races. Better to let the getter
- handle it directly, if necessary to worry about it. */
- if (tsv->getter)
- tsv->value = (tsv->getter) ();
- trace_debug ("get_trace_state_variable_value(%d) ==> %s",
- num, plongest (tsv->value));
- return tsv->value;
- }
- /* This is needed for -Wmissing-declarations. */
- IP_AGENT_EXPORT_FUNC void set_trace_state_variable_value (int num,
- LONGEST val);
- IP_AGENT_EXPORT_FUNC void
- set_trace_state_variable_value (int num, LONGEST val)
- {
- struct trace_state_variable *tsv;
- tsv = get_trace_state_variable (num);
- if (!tsv)
- {
- trace_debug ("No trace state variable %d, skipping value set", num);
- return;
- }
- tsv->value = val;
- }
- LONGEST
- agent_get_trace_state_variable_value (int num)
- {
- return get_trace_state_variable_value (num);
- }
- void
- agent_set_trace_state_variable_value (int num, LONGEST val)
- {
- set_trace_state_variable_value (num, val);
- }
- static void
- set_trace_state_variable_name (int num, const char *name)
- {
- struct trace_state_variable *tsv;
- tsv = get_trace_state_variable (num);
- if (!tsv)
- {
- trace_debug ("No trace state variable %d, skipping name set", num);
- return;
- }
- tsv->name = (char *) name;
- }
- static void
- set_trace_state_variable_getter (int num, LONGEST (*getter) (void))
- {
- struct trace_state_variable *tsv;
- tsv = get_trace_state_variable (num);
- if (!tsv)
- {
- trace_debug ("No trace state variable %d, skipping getter set", num);
- return;
- }
- tsv->getter = getter;
- }
- /* Add a raw traceframe for the given tracepoint. */
- static struct traceframe *
- add_traceframe (struct tracepoint *tpoint)
- {
- struct traceframe *tframe;
- tframe
- = (struct traceframe *) trace_buffer_alloc (sizeof (struct traceframe));
- if (tframe == NULL)
- return NULL;
- tframe->tpnum = tpoint->number;
- tframe->data_size = 0;
- return tframe;
- }
- /* Add a block to the traceframe currently being worked on. */
- static unsigned char *
- add_traceframe_block (struct traceframe *tframe,
- struct tracepoint *tpoint, int amt)
- {
- unsigned char *block;
- if (!tframe)
- return NULL;
- block = (unsigned char *) trace_buffer_alloc (amt);
- if (!block)
- return NULL;
- gdb_assert (tframe->tpnum == tpoint->number);
- tframe->data_size += amt;
- tpoint->traceframe_usage += amt;
- return block;
- }
- /* Flag that the current traceframe is finished. */
- static void
- finish_traceframe (struct traceframe *tframe)
- {
- ++traceframe_write_count;
- ++traceframes_created;
- }
- #ifndef IN_PROCESS_AGENT
- /* Given a traceframe number NUM, find the NUMth traceframe in the
- buffer. */
- static struct traceframe *
- find_traceframe (int num)
- {
- struct traceframe *tframe;
- int tfnum = 0;
- for (tframe = FIRST_TRACEFRAME ();
- tframe->tpnum != 0;
- tframe = NEXT_TRACEFRAME (tframe))
- {
- if (tfnum == num)
- return tframe;
- ++tfnum;
- }
- return NULL;
- }
- static CORE_ADDR
- get_traceframe_address (struct traceframe *tframe)
- {
- CORE_ADDR addr;
- struct tracepoint *tpoint;
- addr = traceframe_get_pc (tframe);
- if (addr)
- return addr;
- /* Fallback strategy, will be incorrect for while-stepping frames
- and multi-location tracepoints. */
- tpoint = find_next_tracepoint_by_number (NULL, tframe->tpnum);
- return tpoint->address;
- }
- /* Search for the next traceframe whose address is inside or outside
- the given range. */
- static struct traceframe *
- find_next_traceframe_in_range (CORE_ADDR lo, CORE_ADDR hi, int inside_p,
- int *tfnump)
- {
- client_state &cs = get_client_state ();
- struct traceframe *tframe;
- CORE_ADDR tfaddr;
- *tfnump = cs.current_traceframe + 1;
- tframe = find_traceframe (*tfnump);
- /* The search is not supposed to wrap around. */
- if (!tframe)
- {
- *tfnump = -1;
- return NULL;
- }
- for (; tframe->tpnum != 0; tframe = NEXT_TRACEFRAME (tframe))
- {
- tfaddr = get_traceframe_address (tframe);
- if (inside_p
- ? (lo <= tfaddr && tfaddr <= hi)
- : (lo > tfaddr || tfaddr > hi))
- return tframe;
- ++*tfnump;
- }
- *tfnump = -1;
- return NULL;
- }
- /* Search for the next traceframe recorded by the given tracepoint.
- Note that for multi-location tracepoints, this will find whatever
- location appears first. */
- static struct traceframe *
- find_next_traceframe_by_tracepoint (int num, int *tfnump)
- {
- client_state &cs = get_client_state ();
- struct traceframe *tframe;
- *tfnump = cs.current_traceframe + 1;
- tframe = find_traceframe (*tfnump);
- /* The search is not supposed to wrap around. */
- if (!tframe)
- {
- *tfnump = -1;
- return NULL;
- }
- for (; tframe->tpnum != 0; tframe = NEXT_TRACEFRAME (tframe))
- {
- if (tframe->tpnum == num)
- return tframe;
- ++*tfnump;
- }
- *tfnump = -1;
- return NULL;
- }
- #endif
- #ifndef IN_PROCESS_AGENT
- /* Clear all past trace state. */
- static void
- cmd_qtinit (char *packet)
- {
- client_state &cs = get_client_state ();
- struct trace_state_variable *tsv, *prev, *next;
- /* Can't do this command without a pid attached. */
- if (current_thread == NULL)
- {
- write_enn (packet);
- return;
- }
- /* Make sure we don't try to read from a trace frame. */
- cs.current_traceframe = -1;
- stop_tracing ();
- trace_debug ("Initializing the trace");
- clear_installed_tracepoints ();
- clear_readonly_regions ();
- tracepoints = NULL;
- last_tracepoint = NULL;
- /* Clear out any leftover trace state variables. Ones with target
- defined getters should be kept however. */
- prev = NULL;
- tsv = trace_state_variables;
- while (tsv)
- {
- trace_debug ("Looking at var %d", tsv->number);
- if (tsv->getter == NULL)
- {
- next = tsv->next;
- if (prev)
- prev->next = next;
- else
- trace_state_variables = next;
- trace_debug ("Deleting var %d", tsv->number);
- free (tsv);
- tsv = next;
- }
- else
- {
- prev = tsv;
- tsv = tsv->next;
- }
- }
- clear_trace_buffer ();
- clear_inferior_trace_buffer ();
- write_ok (packet);
- }
- /* Unprobe the UST marker at ADDRESS. */
- static void
- unprobe_marker_at (CORE_ADDR address)
- {
- char cmd[IPA_CMD_BUF_SIZE];
- sprintf (cmd, "unprobe_marker_at:%s", paddress (address));
- run_inferior_command (cmd, strlen (cmd) + 1);
- }
- /* Restore the program to its pre-tracing state. This routine may be called
- in error situations, so it needs to be careful about only restoring
- from known-valid bits. */
- static void
- clear_installed_tracepoints (void)
- {
- struct tracepoint *tpoint;
- struct tracepoint *prev_stpoint;
- target_pause_all (true);
- prev_stpoint = NULL;
- /* Restore any bytes overwritten by tracepoints. */
- for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
- {
- /* Catch the case where we might try to remove a tracepoint that
- was never actually installed. */
- if (tpoint->handle == NULL)
- {
- trace_debug ("Tracepoint %d at 0x%s was "
- "never installed, nothing to clear",
- tpoint->number, paddress (tpoint->address));
- continue;
- }
- switch (tpoint->type)
- {
- case trap_tracepoint:
- {
- struct breakpoint *bp
- = (struct breakpoint *) tpoint->handle;
- delete_breakpoint (bp);
- }
- break;
- case fast_tracepoint:
- {
- struct fast_tracepoint_jump *jump
- = (struct fast_tracepoint_jump *) tpoint->handle;
- delete_fast_tracepoint_jump (jump);
- }
- break;
- case static_tracepoint:
- if (prev_stpoint != NULL
- && prev_stpoint->address == tpoint->address)
- /* Nothing to do. We already unprobed a tracepoint set at
- this marker address (and there can only be one probe
- per marker). */
- ;
- else
- {
- unprobe_marker_at (tpoint->address);
- prev_stpoint = tpoint;
- }
- break;
- }
- tpoint->handle = NULL;
- }
- target_unpause_all (true);
- }
- /* Parse a packet that defines a tracepoint. */
- static void
- cmd_qtdp (char *own_buf)
- {
- int tppacket;
- /* Whether there is a trailing hyphen at the end of the QTDP packet. */
- int trail_hyphen = 0;
- ULONGEST num;
- ULONGEST addr;
- ULONGEST count;
- struct tracepoint *tpoint;
- const char *packet = own_buf;
- packet += strlen ("QTDP:");
- /* A hyphen at the beginning marks a packet specifying actions for a
- tracepoint already supplied. */
- tppacket = 1;
- if (*packet == '-')
- {
- tppacket = 0;
- ++packet;
- }
- packet = unpack_varlen_hex (packet, &num);
- ++packet; /* skip a colon */
- packet = unpack_varlen_hex (packet, &addr);
- ++packet; /* skip a colon */
- /* See if we already have this tracepoint. */
- tpoint = find_tracepoint (num, addr);
- if (tppacket)
- {
- /* Duplicate tracepoints are never allowed. */
- if (tpoint)
- {
- trace_debug ("Tracepoint error: tracepoint %d"
- " at 0x%s already exists",
- (int) num, paddress (addr));
- write_enn (own_buf);
- return;
- }
- tpoint = add_tracepoint (num, addr);
- tpoint->enabled = (*packet == 'E');
- ++packet; /* skip 'E' */
- ++packet; /* skip a colon */
- packet = unpack_varlen_hex (packet, &count);
- tpoint->step_count = count;
- ++packet; /* skip a colon */
- packet = unpack_varlen_hex (packet, &count);
- tpoint->pass_count = count;
- /* See if we have any of the additional optional fields. */
- while (*packet == ':')
- {
- ++packet;
- if (*packet == 'F')
- {
- tpoint->type = fast_tracepoint;
- ++packet;
- packet = unpack_varlen_hex (packet, &count);
- tpoint->orig_size = count;
- }
- else if (*packet == 'S')
- {
- tpoint->type = static_tracepoint;
- ++packet;
- }
- else if (*packet == 'X')
- {
- tpoint->cond = gdb_parse_agent_expr (&packet);
- }
- else if (*packet == '-')
- break;
- else if (*packet == '\0')
- break;
- else
- trace_debug ("Unknown optional tracepoint field");
- }
- if (*packet == '-')
- {
- trail_hyphen = 1;
- trace_debug ("Also has actions\n");
- }
- trace_debug ("Defined %stracepoint %d at 0x%s, "
- "enabled %d step %" PRIu64 " pass %" PRIu64,
- tpoint->type == fast_tracepoint ? "fast "
- : tpoint->type == static_tracepoint ? "static " : "",
- tpoint->number, paddress (tpoint->address), tpoint->enabled,
- tpoint->step_count, tpoint->pass_count);
- }
- else if (tpoint)
- add_tracepoint_action (tpoint, packet);
- else
- {
- trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found",
- (int) num, paddress (addr));
- write_enn (own_buf);
- return;
- }
- /* Install tracepoint during tracing only once for each tracepoint location.
- For each tracepoint loc, GDB may send multiple QTDP packets, and we can
- determine the last QTDP packet for one tracepoint location by checking
- trailing hyphen in QTDP packet. */
- if (tracing && !trail_hyphen)
- {
- struct tracepoint *tp = NULL;
- /* Pause all threads temporarily while we patch tracepoints. */
- target_pause_all (false);
- /* download_tracepoint will update global `tracepoints'
- list, so it is unsafe to leave threads in jump pad. */
- target_stabilize_threads ();
- /* Freeze threads. */
- target_pause_all (true);
- if (tpoint->type != trap_tracepoint)
- {
- /* Find another fast or static tracepoint at the same address. */
- for (tp = tracepoints; tp; tp = tp->next)
- {
- if (tp->address == tpoint->address && tp->type == tpoint->type
- && tp->number != tpoint->number)
- break;
- }
- /* TPOINT is installed at the same address as TP. */
- if (tp)
- {
- if (tpoint->type == fast_tracepoint)
- clone_fast_tracepoint (tpoint, tp);
- else if (tpoint->type == static_tracepoint)
- tpoint->handle = (void *) -1;
- }
- }
- if (use_agent && tpoint->type == fast_tracepoint
- && agent_capability_check (AGENT_CAPA_FAST_TRACE))
- {
- /* Download and install fast tracepoint by agent. */
- if (tracepoint_send_agent (tpoint) == 0)
- write_ok (own_buf);
- else
- {
- write_enn (own_buf);
- remove_tracepoint (tpoint);
- }
- }
- else
- {
- download_tracepoint (tpoint);
- if (tpoint->type == trap_tracepoint || tp == NULL)
- {
- install_tracepoint (tpoint, own_buf);
- if (strcmp (own_buf, "OK") != 0)
- remove_tracepoint (tpoint);
- }
- else
- write_ok (own_buf);
- }
- target_unpause_all (true);
- return;
- }
- write_ok (own_buf);
- }
- static void
- cmd_qtdpsrc (char *own_buf)
- {
- ULONGEST num, addr, start, slen;
- struct tracepoint *tpoint;
- const char *packet = own_buf;
- const char *saved;
- char *srctype, *src;
- size_t nbytes;
- struct source_string *last, *newlast;
- packet += strlen ("QTDPsrc:");
- packet = unpack_varlen_hex (packet, &num);
- ++packet; /* skip a colon */
- packet = unpack_varlen_hex (packet, &addr);
- ++packet; /* skip a colon */
- /* See if we already have this tracepoint. */
- tpoint = find_tracepoint (num, addr);
- if (!tpoint)
- {
- trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found",
- (int) num, paddress (addr));
- write_enn (own_buf);
- return;
- }
- saved = packet;
- packet = strchr (packet, ':');
- srctype = (char *) xmalloc (packet - saved + 1);
- memcpy (srctype, saved, packet - saved);
- srctype[packet - saved] = '\0';
- ++packet;
- packet = unpack_varlen_hex (packet, &start);
- ++packet; /* skip a colon */
- packet = unpack_varlen_hex (packet, &slen);
- ++packet; /* skip a colon */
- src = (char *) xmalloc (slen + 1);
- nbytes = hex2bin (packet, (gdb_byte *) src, strlen (packet) / 2);
- src[nbytes] = '\0';
- newlast = XNEW (struct source_string);
- newlast->type = srctype;
- newlast->str = src;
- newlast->next = NULL;
- /* Always add a source string to the end of the list;
- this keeps sequences of actions/commands in the right
- order. */
- if (tpoint->source_strings)
- {
- for (last = tpoint->source_strings; last->next; last = last->next)
- ;
- last->next = newlast;
- }
- else
- tpoint->source_strings = newlast;
- write_ok (own_buf);
- }
- static void
- cmd_qtdv (char *own_buf)
- {
- ULONGEST num, val, builtin;
- char *varname;
- size_t nbytes;
- struct trace_state_variable *tsv;
- const char *packet = own_buf;
- packet += strlen ("QTDV:");
- packet = unpack_varlen_hex (packet, &num);
- ++packet; /* skip a colon */
- packet = unpack_varlen_hex (packet, &val);
- ++packet; /* skip a colon */
- packet = unpack_varlen_hex (packet, &builtin);
- ++packet; /* skip a colon */
- nbytes = strlen (packet) / 2;
- varname = (char *) xmalloc (nbytes + 1);
- nbytes = hex2bin (packet, (gdb_byte *) varname, nbytes);
- varname[nbytes] = '\0';
- tsv = create_trace_state_variable (num, 1);
- tsv->initial_value = (LONGEST) val;
- tsv->name = varname;
- set_trace_state_variable_value (num, (LONGEST) val);
- write_ok (own_buf);
- }
- static void
- cmd_qtenable_disable (char *own_buf, int enable)
- {
- const char *packet = own_buf;
- ULONGEST num, addr;
- struct tracepoint *tp;
- packet += strlen (enable ? "QTEnable:" : "QTDisable:");
- packet = unpack_varlen_hex (packet, &num);
- ++packet; /* skip a colon */
- packet = unpack_varlen_hex (packet, &addr);
- tp = find_tracepoint (num, addr);
- if (tp)
- {
- if ((enable && tp->enabled) || (!enable && !tp->enabled))
- {
- trace_debug ("Tracepoint %d at 0x%s is already %s",
- (int) num, paddress (addr),
- enable ? "enabled" : "disabled");
- write_ok (own_buf);
- return;
- }
- trace_debug ("%s tracepoint %d at 0x%s",
- enable ? "Enabling" : "Disabling",
- (int) num, paddress (addr));
- tp->enabled = enable;
- if (tp->type == fast_tracepoint || tp->type == static_tracepoint)
- {
- int ret;
- int offset = offsetof (struct tracepoint, enabled);
- CORE_ADDR obj_addr = tp->obj_addr_on_target + offset;
- ret = prepare_to_access_memory ();
- if (ret)
- {
- trace_debug ("Failed to temporarily stop inferior threads");
- write_enn (own_buf);
- return;
- }
- ret = write_inferior_int8 (obj_addr, enable);
- done_accessing_memory ();
-
- if (ret)
- {
- trace_debug ("Cannot write enabled flag into "
- "inferior process memory");
- write_enn (own_buf);
- return;
- }
- }
- write_ok (own_buf);
- }
- else
- {
- trace_debug ("Tracepoint %d at 0x%s not found",
- (int) num, paddress (addr));
- write_enn (own_buf);
- }
- }
- static void
- cmd_qtv (char *own_buf)
- {
- client_state &cs = get_client_state ();
- ULONGEST num;
- LONGEST val = 0;
- int err;
- char *packet = own_buf;
- packet += strlen ("qTV:");
- unpack_varlen_hex (packet, &num);
- if (cs.current_traceframe >= 0)
- {
- err = traceframe_read_tsv ((int) num, &val);
- if (err)
- {
- strcpy (own_buf, "U");
- return;
- }
- }
- /* Only make tsv's be undefined before the first trace run. After a
- trace run is over, the user might want to see the last value of
- the tsv, and it might not be available in a traceframe. */
- else if (!tracing && strcmp (tracing_stop_reason, "tnotrun") == 0)
- {
- strcpy (own_buf, "U");
- return;
- }
- else
- val = get_trace_state_variable_value (num);
- sprintf (own_buf, "V%s", phex_nz (val, 0));
- }
- /* Clear out the list of readonly regions. */
- static void
- clear_readonly_regions (void)
- {
- struct readonly_region *roreg;
- while (readonly_regions)
- {
- roreg = readonly_regions;
- readonly_regions = readonly_regions->next;
- free (roreg);
- }
- }
- /* Parse the collection of address ranges whose contents GDB believes
- to be unchanging and so can be read directly from target memory
- even while looking at a traceframe. */
- static void
- cmd_qtro (char *own_buf)
- {
- ULONGEST start, end;
- struct readonly_region *roreg;
- const char *packet = own_buf;
- trace_debug ("Want to mark readonly regions");
- clear_readonly_regions ();
- packet += strlen ("QTro");
- while (*packet == ':')
- {
- ++packet; /* skip a colon */
- packet = unpack_varlen_hex (packet, &start);
- ++packet; /* skip a comma */
- packet = unpack_varlen_hex (packet, &end);
- roreg = XNEW (struct readonly_region);
- roreg->start = start;
- roreg->end = end;
- roreg->next = readonly_regions;
- readonly_regions = roreg;
- trace_debug ("Added readonly region from 0x%s to 0x%s",
- paddress (roreg->start), paddress (roreg->end));
- }
- write_ok (own_buf);
- }
- /* Test to see if the given range is in our list of readonly ranges.
- We only test for being entirely within a range, GDB is not going to
- send a single memory packet that spans multiple regions. */
- int
- in_readonly_region (CORE_ADDR addr, ULONGEST length)
- {
- struct readonly_region *roreg;
- for (roreg = readonly_regions; roreg; roreg = roreg->next)
- if (roreg->start <= addr && (addr + length - 1) <= roreg->end)
- return 1;
- return 0;
- }
- static CORE_ADDR gdb_jump_pad_head;
- /* Return the address of the next free jump space. */
- static CORE_ADDR
- get_jump_space_head (void)
- {
- if (gdb_jump_pad_head == 0)
- {
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer,
- &gdb_jump_pad_head))
- {
- internal_error (__FILE__, __LINE__,
- "error extracting jump_pad_buffer");
- }
- }
- return gdb_jump_pad_head;
- }
- /* Reserve USED bytes from the jump space. */
- static void
- claim_jump_space (ULONGEST used)
- {
- trace_debug ("claim_jump_space reserves %s bytes at %s",
- pulongest (used), paddress (gdb_jump_pad_head));
- gdb_jump_pad_head += used;
- }
- static CORE_ADDR trampoline_buffer_head = 0;
- static CORE_ADDR trampoline_buffer_tail;
- /* Reserve USED bytes from the trampoline buffer and return the
- address of the start of the reserved space in TRAMPOLINE. Returns
- non-zero if the space is successfully claimed. */
- int
- claim_trampoline_space (ULONGEST used, CORE_ADDR *trampoline)
- {
- if (!trampoline_buffer_head)
- {
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer,
- &trampoline_buffer_tail))
- {
- internal_error (__FILE__, __LINE__,
- "error extracting trampoline_buffer");
- }
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end,
- &trampoline_buffer_head))
- {
- internal_error (__FILE__, __LINE__,
- "error extracting trampoline_buffer_end");
- }
- }
- /* Start claiming space from the top of the trampoline space. If
- the space is located at the bottom of the virtual address space,
- this reduces the possibility that corruption will occur if a null
- pointer is used to write to memory. */
- if (trampoline_buffer_head - trampoline_buffer_tail < used)
- {
- trace_debug ("claim_trampoline_space failed to reserve %s bytes",
- pulongest (used));
- return 0;
- }
- trampoline_buffer_head -= used;
- trace_debug ("claim_trampoline_space reserves %s bytes at %s",
- pulongest (used), paddress (trampoline_buffer_head));
- *trampoline = trampoline_buffer_head;
- return 1;
- }
- /* Returns non-zero if there is space allocated for use in trampolines
- for fast tracepoints. */
- int
- have_fast_tracepoint_trampoline_buffer (char *buf)
- {
- CORE_ADDR trampoline_end, errbuf;
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end,
- &trampoline_end))
- {
- internal_error (__FILE__, __LINE__,
- "error extracting trampoline_buffer_end");
- }
-
- if (buf)
- {
- buf[0] = '\0';
- strcpy (buf, "was claiming");
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_error,
- &errbuf))
- {
- internal_error (__FILE__, __LINE__,
- "error extracting errbuf");
- }
- read_inferior_memory (errbuf, (unsigned char *) buf, 100);
- }
- return trampoline_end != 0;
- }
- /* Ask the IPA to probe the marker at ADDRESS. Returns -1 if running
- the command fails, or 0 otherwise. If the command ran
- successfully, but probing the marker failed, ERROUT will be filled
- with the error to reply to GDB, and -1 is also returned. This
- allows directly passing IPA errors to GDB. */
- static int
- probe_marker_at (CORE_ADDR address, char *errout)
- {
- char cmd[IPA_CMD_BUF_SIZE];
- int err;
- sprintf (cmd, "probe_marker_at:%s", paddress (address));
- err = run_inferior_command (cmd, strlen (cmd) + 1);
- if (err == 0)
- {
- if (*cmd == 'E')
- {
- strcpy (errout, cmd);
- return -1;
- }
- }
- return err;
- }
- static void
- clone_fast_tracepoint (struct tracepoint *to, const struct tracepoint *from)
- {
- to->jump_pad = from->jump_pad;
- to->jump_pad_end = from->jump_pad_end;
- to->trampoline = from->trampoline;
- to->trampoline_end = from->trampoline_end;
- to->adjusted_insn_addr = from->adjusted_insn_addr;
- to->adjusted_insn_addr_end = from->adjusted_insn_addr_end;
- to->handle = from->handle;
- gdb_assert (from->handle);
- inc_ref_fast_tracepoint_jump ((struct fast_tracepoint_jump *) from->handle);
- }
- #define MAX_JUMP_SIZE 20
- /* Install fast tracepoint. Return 0 if successful, otherwise return
- non-zero. */
- static int
- install_fast_tracepoint (struct tracepoint *tpoint, char *errbuf)
- {
- CORE_ADDR jentry, jump_entry;
- CORE_ADDR trampoline;
- CORE_ADDR collect;
- ULONGEST trampoline_size;
- int err = 0;
- /* The jump to the jump pad of the last fast tracepoint
- installed. */
- unsigned char fjump[MAX_JUMP_SIZE];
- ULONGEST fjump_size;
- if (tpoint->orig_size < target_get_min_fast_tracepoint_insn_len ())
- {
- trace_debug ("Requested a fast tracepoint on an instruction "
- "that is of less than the minimum length.");
- return 0;
- }
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_collect_ptr,
- &collect))
- {
- error ("error extracting gdb_collect_ptr");
- return 1;
- }
- jentry = jump_entry = get_jump_space_head ();
- trampoline = 0;
- trampoline_size = 0;
- /* Install the jump pad. */
- err = target_install_fast_tracepoint_jump_pad
- (tpoint->obj_addr_on_target, tpoint->address, collect,
- ipa_sym_addrs.addr_collecting, tpoint->orig_size, &jentry,
- &trampoline, &trampoline_size, fjump, &fjump_size,
- &tpoint->adjusted_insn_addr, &tpoint->adjusted_insn_addr_end, errbuf);
- if (err)
- return 1;
- /* Wire it in. */
- tpoint->handle = set_fast_tracepoint_jump (tpoint->address, fjump,
- fjump_size);
- if (tpoint->handle != NULL)
- {
- tpoint->jump_pad = jump_entry;
- tpoint->jump_pad_end = jentry;
- tpoint->trampoline = trampoline;
- tpoint->trampoline_end = trampoline + trampoline_size;
- /* Pad to 8-byte alignment. */
- jentry = ((jentry + 7) & ~0x7);
- claim_jump_space (jentry - jump_entry);
- }
- return 0;
- }
- /* Install tracepoint TPOINT, and write reply message in OWN_BUF. */
- static void
- install_tracepoint (struct tracepoint *tpoint, char *own_buf)
- {
- tpoint->handle = NULL;
- *own_buf = '\0';
- if (tpoint->type == trap_tracepoint)
- {
- /* Tracepoints are installed as memory breakpoints. Just go
- ahead and install the trap. The breakpoints module
- handles duplicated breakpoints, and the memory read
- routine handles un-patching traps from memory reads. */
- tpoint->handle = set_breakpoint_at (tpoint->address,
- tracepoint_handler);
- }
- else if (tpoint->type == fast_tracepoint || tpoint->type == static_tracepoint)
- {
- if (!agent_loaded_p ())
- {
- trace_debug ("Requested a %s tracepoint, but fast "
- "tracepoints aren't supported.",
- tpoint->type == static_tracepoint ? "static" : "fast");
- write_e_ipa_not_loaded (own_buf);
- return;
- }
- if (tpoint->type == static_tracepoint
- && !in_process_agent_supports_ust ())
- {
- trace_debug ("Requested a static tracepoint, but static "
- "tracepoints are not supported.");
- write_e_ust_not_loaded (own_buf);
- return;
- }
- if (tpoint->type == fast_tracepoint)
- install_fast_tracepoint (tpoint, own_buf);
- else
- {
- if (probe_marker_at (tpoint->address, own_buf) == 0)
- tpoint->handle = (void *) -1;
- }
- }
- else
- internal_error (__FILE__, __LINE__, "Unknown tracepoint type");
- if (tpoint->handle == NULL)
- {
- if (*own_buf == '\0')
- write_enn (own_buf);
- }
- else
- write_ok (own_buf);
- }
- static void download_tracepoint_1 (struct tracepoint *tpoint);
- static void
- cmd_qtstart (char *packet)
- {
- struct tracepoint *tpoint, *prev_ftpoint, *prev_stpoint;
- CORE_ADDR tpptr = 0, prev_tpptr = 0;
- trace_debug ("Starting the trace");
- /* Pause all threads temporarily while we patch tracepoints. */
- target_pause_all (false);
- /* Get threads out of jump pads. Safe to do here, since this is a
- top level command. And, required to do here, since we're
- deleting/rewriting jump pads. */
- target_stabilize_threads ();
- /* Freeze threads. */
- target_pause_all (true);
- /* Sync the fast tracepoints list in the inferior ftlib. */
- if (agent_loaded_p ())
- download_trace_state_variables ();
- /* No previous fast tpoint yet. */
- prev_ftpoint = NULL;
- /* No previous static tpoint yet. */
- prev_stpoint = NULL;
- *packet = '\0';
- if (agent_loaded_p ())
- {
- /* Tell IPA about the correct tdesc. */
- if (write_inferior_integer (ipa_sym_addrs.addr_ipa_tdesc_idx,
- target_get_ipa_tdesc_idx ()))
- error ("Error setting ipa_tdesc_idx variable in lib");
- }
- /* Start out empty. */
- if (agent_loaded_p ())
- write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints, 0);
- /* Download and install tracepoints. */
- for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
- {
- /* Ensure all the hit counts start at zero. */
- tpoint->hit_count = 0;
- tpoint->traceframe_usage = 0;
- if (tpoint->type == trap_tracepoint)
- {
- /* Tracepoints are installed as memory breakpoints. Just go
- ahead and install the trap. The breakpoints module
- handles duplicated breakpoints, and the memory read
- routine handles un-patching traps from memory reads. */
- tpoint->handle = set_breakpoint_at (tpoint->address,
- tracepoint_handler);
- }
- else if (tpoint->type == fast_tracepoint
- || tpoint->type == static_tracepoint)
- {
- if (maybe_write_ipa_not_loaded (packet))
- {
- trace_debug ("Requested a %s tracepoint, but fast "
- "tracepoints aren't supported.",
- tpoint->type == static_tracepoint
- ? "static" : "fast");
- break;
- }
- if (tpoint->type == fast_tracepoint)
- {
- int use_agent_p
- = use_agent && agent_capability_check (AGENT_CAPA_FAST_TRACE);
- if (prev_ftpoint != NULL
- && prev_ftpoint->address == tpoint->address)
- {
- if (use_agent_p)
- tracepoint_send_agent (tpoint);
- else
- download_tracepoint_1 (tpoint);
- clone_fast_tracepoint (tpoint, prev_ftpoint);
- }
- else
- {
- /* Tracepoint is installed successfully? */
- int installed = 0;
- /* Download and install fast tracepoint by agent. */
- if (use_agent_p)
- installed = !tracepoint_send_agent (tpoint);
- else
- {
- download_tracepoint_1 (tpoint);
- installed = !install_fast_tracepoint (tpoint, packet);
- }
- if (installed)
- prev_ftpoint = tpoint;
- }
- }
- else
- {
- if (!in_process_agent_supports_ust ())
- {
- trace_debug ("Requested a static tracepoint, but static "
- "tracepoints are not supported.");
- break;
- }
- download_tracepoint_1 (tpoint);
- /* Can only probe a given marker once. */
- if (prev_stpoint != NULL
- && prev_stpoint->address == tpoint->address)
- tpoint->handle = (void *) -1;
- else
- {
- if (probe_marker_at (tpoint->address, packet) == 0)
- {
- tpoint->handle = (void *) -1;
- /* So that we can handle multiple static tracepoints
- at the same address easily. */
- prev_stpoint = tpoint;
- }
- }
- }
- prev_tpptr = tpptr;
- tpptr = tpoint->obj_addr_on_target;
- if (tpoint == tracepoints)
- /* First object in list, set the head pointer in the
- inferior. */
- write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints, tpptr);
- else
- write_inferior_data_pointer (prev_tpptr
- + offsetof (struct tracepoint, next),
- tpptr);
- }
- /* Any failure in the inner loop is sufficient cause to give
- up. */
- if (tpoint->handle == NULL)
- break;
- }
- /* Any error in tracepoint insertion is unacceptable; better to
- address the problem now, than end up with a useless or misleading
- trace run. */
- if (tpoint != NULL)
- {
- clear_installed_tracepoints ();
- if (*packet == '\0')
- write_enn (packet);
- target_unpause_all (true);
- return;
- }
- stopping_tracepoint = NULL;
- trace_buffer_is_full = 0;
- expr_eval_result = expr_eval_no_error;
- error_tracepoint = NULL;
- tracing_start_time = get_timestamp ();
- /* Tracing is now active, hits will now start being logged. */
- tracing = 1;
- if (agent_loaded_p ())
- {
- if (write_inferior_integer (ipa_sym_addrs.addr_tracing, 1))
- {
- internal_error (__FILE__, __LINE__,
- "Error setting tracing variable in lib");
- }
- if (write_inferior_data_pointer (ipa_sym_addrs.addr_stopping_tracepoint,
- 0))
- {
- internal_error (__FILE__, __LINE__,
- "Error clearing stopping_tracepoint variable"
- " in lib");
- }
- if (write_inferior_integer (ipa_sym_addrs.addr_trace_buffer_is_full, 0))
- {
- internal_error (__FILE__, __LINE__,
- "Error clearing trace_buffer_is_full variable"
- " in lib");
- }
- stop_tracing_bkpt = set_breakpoint_at (ipa_sym_addrs.addr_stop_tracing,
- stop_tracing_handler);
- if (stop_tracing_bkpt == NULL)
- error ("Error setting stop_tracing breakpoint");
- flush_trace_buffer_bkpt
- = set_breakpoint_at (ipa_sym_addrs.addr_flush_trace_buffer,
- flush_trace_buffer_handler);
- if (flush_trace_buffer_bkpt == NULL)
- error ("Error setting flush_trace_buffer breakpoint");
- }
- target_unpause_all (true);
- write_ok (packet);
- }
- /* End a tracing run, filling in a stop reason to report back to GDB,
- and removing the tracepoints from the code. */
- void
- stop_tracing (void)
- {
- if (!tracing)
- {
- trace_debug ("Tracing is already off, ignoring");
- return;
- }
- trace_debug ("Stopping the trace");
- /* Pause all threads before removing fast jumps from memory,
- breakpoints, and touching IPA state variables (inferior memory).
- Some thread may hit the internal tracing breakpoints, or be
- collecting this moment, but that's ok, we don't release the
- tpoint object's memory or the jump pads here (we only do that
- when we're sure we can move all threads out of the jump pads).
- We can't now, since we may be getting here due to the inferior
- agent calling us. */
- target_pause_all (true);
- /* Stop logging. Tracepoints can still be hit, but they will not be
- recorded. */
- tracing = 0;
- if (agent_loaded_p ())
- {
- if (write_inferior_integer (ipa_sym_addrs.addr_tracing, 0))
- {
- internal_error (__FILE__, __LINE__,
- "Error clearing tracing variable in lib");
- }
- }
- tracing_stop_time = get_timestamp ();
- tracing_stop_reason = "t???";
- tracing_stop_tpnum = 0;
- if (stopping_tracepoint)
- {
- trace_debug ("Stopping the trace because "
- "tracepoint %d was hit %" PRIu64 " times",
- stopping_tracepoint->number,
- stopping_tracepoint->pass_count);
- tracing_stop_reason = "tpasscount";
- tracing_stop_tpnum = stopping_tracepoint->number;
- }
- else if (trace_buffer_is_full)
- {
- trace_debug ("Stopping the trace because the trace buffer is full");
- tracing_stop_reason = "tfull";
- }
- else if (expr_eval_result != expr_eval_no_error)
- {
- trace_debug ("Stopping the trace because of an expression eval error");
- tracing_stop_reason = eval_result_names[expr_eval_result];
- tracing_stop_tpnum = error_tracepoint->number;
- }
- #ifndef IN_PROCESS_AGENT
- else if (!gdb_connected ())
- {
- trace_debug ("Stopping the trace because GDB disconnected");
- tracing_stop_reason = "tdisconnected";
- }
- #endif
- else
- {
- trace_debug ("Stopping the trace because of a tstop command");
- tracing_stop_reason = "tstop";
- }
- stopping_tracepoint = NULL;
- error_tracepoint = NULL;
- /* Clear out the tracepoints. */
- clear_installed_tracepoints ();
- if (agent_loaded_p ())
- {
- /* Pull in fast tracepoint trace frames from the inferior lib
- buffer into our buffer, even if our buffer is already full,
- because we want to present the full number of created frames
- in addition to what fit in the trace buffer. */
- upload_fast_traceframes ();
- }
- if (stop_tracing_bkpt != NULL)
- {
- delete_breakpoint (stop_tracing_bkpt);
- stop_tracing_bkpt = NULL;
- }
- if (flush_trace_buffer_bkpt != NULL)
- {
- delete_breakpoint (flush_trace_buffer_bkpt);
- flush_trace_buffer_bkpt = NULL;
- }
- target_unpause_all (true);
- }
- static int
- stop_tracing_handler (CORE_ADDR addr)
- {
- trace_debug ("lib hit stop_tracing");
- /* Don't actually handle it here. When we stop tracing we remove
- breakpoints from the inferior, and that is not allowed in a
- breakpoint handler (as the caller is walking the breakpoint
- list). */
- return 0;
- }
- static int
- flush_trace_buffer_handler (CORE_ADDR addr)
- {
- trace_debug ("lib hit flush_trace_buffer");
- return 0;
- }
- static void
- cmd_qtstop (char *packet)
- {
- stop_tracing ();
- write_ok (packet);
- }
- static void
- cmd_qtdisconnected (char *own_buf)
- {
- ULONGEST setting;
- char *packet = own_buf;
- packet += strlen ("QTDisconnected:");
- unpack_varlen_hex (packet, &setting);
- write_ok (own_buf);
- disconnected_tracing = setting;
- }
- static void
- cmd_qtframe (char *own_buf)
- {
- client_state &cs = get_client_state ();
- ULONGEST frame, pc, lo, hi, num;
- int tfnum, tpnum;
- struct traceframe *tframe;
- const char *packet = own_buf;
- packet += strlen ("QTFrame:");
- if (startswith (packet, "pc:"))
- {
- packet += strlen ("pc:");
- unpack_varlen_hex (packet, &pc);
- trace_debug ("Want to find next traceframe at pc=0x%s", paddress (pc));
- tframe = find_next_traceframe_in_range (pc, pc, 1, &tfnum);
- }
- else if (startswith (packet, "range:"))
- {
- packet += strlen ("range:");
- packet = unpack_varlen_hex (packet, &lo);
- ++packet;
- unpack_varlen_hex (packet, &hi);
- trace_debug ("Want to find next traceframe in the range 0x%s to 0x%s",
- paddress (lo), paddress (hi));
- tframe = find_next_traceframe_in_range (lo, hi, 1, &tfnum);
- }
- else if (startswith (packet, "outside:"))
- {
- packet += strlen ("outside:");
- packet = unpack_varlen_hex (packet, &lo);
- ++packet;
- unpack_varlen_hex (packet, &hi);
- trace_debug ("Want to find next traceframe "
- "outside the range 0x%s to 0x%s",
- paddress (lo), paddress (hi));
- tframe = find_next_traceframe_in_range (lo, hi, 0, &tfnum);
- }
- else if (startswith (packet, "tdp:"))
- {
- packet += strlen ("tdp:");
- unpack_varlen_hex (packet, &num);
- tpnum = (int) num;
- trace_debug ("Want to find next traceframe for tracepoint %d", tpnum);
- tframe = find_next_traceframe_by_tracepoint (tpnum, &tfnum);
- }
- else
- {
- unpack_varlen_hex (packet, &frame);
- tfnum = (int) frame;
- if (tfnum == -1)
- {
- trace_debug ("Want to stop looking at traceframes");
- cs.current_traceframe = -1;
- write_ok (own_buf);
- return;
- }
- trace_debug ("Want to look at traceframe %d", tfnum);
- tframe = find_traceframe (tfnum);
- }
- if (tframe)
- {
- cs.current_traceframe = tfnum;
- sprintf (own_buf, "F%xT%x", tfnum, tframe->tpnum);
- }
- else
- sprintf (own_buf, "F-1");
- }
- static void
- cmd_qtstatus (char *packet)
- {
- char *stop_reason_rsp = NULL;
- char *buf1, *buf2, *buf3;
- const char *str;
- int slen;
- /* Translate the plain text of the notes back into hex for
- transmission. */
- str = (tracing_user_name ? tracing_user_name : "");
- slen = strlen (str);
- buf1 = (char *) alloca (slen * 2 + 1);
- bin2hex ((gdb_byte *) str, buf1, slen);
- str = (tracing_notes ? tracing_notes : "");
- slen = strlen (str);
- buf2 = (char *) alloca (slen * 2 + 1);
- bin2hex ((gdb_byte *) str, buf2, slen);
- str = (tracing_stop_note ? tracing_stop_note : "");
- slen = strlen (str);
- buf3 = (char *) alloca (slen * 2 + 1);
- bin2hex ((gdb_byte *) str, buf3, slen);
- trace_debug ("Returning trace status as %d, stop reason %s",
- tracing, tracing_stop_reason);
- if (agent_loaded_p ())
- {
- target_pause_all (true);
- upload_fast_traceframes ();
- target_unpause_all (true);
- }
- stop_reason_rsp = (char *) tracing_stop_reason;
- /* The user visible error string in terror needs to be hex encoded.
- We leave it as plain string in `tracing_stop_reason' to ease
- debugging. */
- if (startswith (stop_reason_rsp, "terror:"))
- {
- const char *result_name;
- int hexstr_len;
- char *p;
- result_name = stop_reason_rsp + strlen ("terror:");
- hexstr_len = strlen (result_name) * 2;
- p = stop_reason_rsp
- = (char *) alloca (strlen ("terror:") + hexstr_len + 1);
- strcpy (p, "terror:");
- p += strlen (p);
- bin2hex ((gdb_byte *) result_name, p, strlen (result_name));
- }
- /* If this was a forced stop, include any stop note that was supplied. */
- if (strcmp (stop_reason_rsp, "tstop") == 0)
- {
- stop_reason_rsp = (char *) alloca (strlen ("tstop:") + strlen (buf3) + 1);
- strcpy (stop_reason_rsp, "tstop:");
- strcat (stop_reason_rsp, buf3);
- }
- sprintf (packet,
- "T%d;"
- "%s:%x;"
- "tframes:%x;tcreated:%x;"
- "tfree:%x;tsize:%s;"
- "circular:%d;"
- "disconn:%d;"
- "starttime:%s;stoptime:%s;"
- "username:%s;notes:%s:",
- tracing ? 1 : 0,
- stop_reason_rsp, tracing_stop_tpnum,
- traceframe_count, traceframes_created,
- free_space (), phex_nz (trace_buffer_hi - trace_buffer_lo, 0),
- circular_trace_buffer,
- disconnected_tracing,
- phex_nz (tracing_start_time, sizeof (tracing_start_time)),
- phex_nz (tracing_stop_time, sizeof (tracing_stop_time)),
- buf1, buf2);
- }
- static void
- cmd_qtp (char *own_buf)
- {
- ULONGEST num, addr;
- struct tracepoint *tpoint;
- const char *packet = own_buf;
- packet += strlen ("qTP:");
- packet = unpack_varlen_hex (packet, &num);
- ++packet; /* skip a colon */
- packet = unpack_varlen_hex (packet, &addr);
- /* See if we already have this tracepoint. */
- tpoint = find_tracepoint (num, addr);
- if (!tpoint)
- {
- trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found",
- (int) num, paddress (addr));
- write_enn (own_buf);
- return;
- }
- sprintf (own_buf, "V%" PRIu64 ":%" PRIu64 "", tpoint->hit_count,
- tpoint->traceframe_usage);
- }
- /* State variables to help return all the tracepoint bits. */
- static struct tracepoint *cur_tpoint;
- static unsigned int cur_action;
- static unsigned int cur_step_action;
- static struct source_string *cur_source_string;
- static struct trace_state_variable *cur_tsv;
- /* Compose a response that is an imitation of the syntax by which the
- tracepoint was originally downloaded. */
- static void
- response_tracepoint (char *packet, struct tracepoint *tpoint)
- {
- char *buf;
- sprintf (packet, "T%x:%s:%c:%" PRIx64 ":%" PRIx64, tpoint->number,
- paddress (tpoint->address),
- (tpoint->enabled ? 'E' : 'D'), tpoint->step_count,
- tpoint->pass_count);
- if (tpoint->type == fast_tracepoint)
- sprintf (packet + strlen (packet), ":F%x", tpoint->orig_size);
- else if (tpoint->type == static_tracepoint)
- sprintf (packet + strlen (packet), ":S");
- if (tpoint->cond)
- {
- buf = gdb_unparse_agent_expr (tpoint->cond);
- sprintf (packet + strlen (packet), ":X%x,%s",
- tpoint->cond->length, buf);
- free (buf);
- }
- }
- /* Compose a response that is an imitation of the syntax by which the
- tracepoint action was originally downloaded (with the difference
- that due to the way we store the actions, this will output a packet
- per action, while GDB could have combined more than one action
- per-packet. */
- static void
- response_action (char *packet, struct tracepoint *tpoint,
- char *taction, int step)
- {
- sprintf (packet, "%c%x:%s:%s",
- (step ? 'S' : 'A'), tpoint->number, paddress (tpoint->address),
- taction);
- }
- /* Compose a response that is an imitation of the syntax by which the
- tracepoint source piece was originally downloaded. */
- static void
- response_source (char *packet,
- struct tracepoint *tpoint, struct source_string *src)
- {
- char *buf;
- int len;
- len = strlen (src->str);
- buf = (char *) alloca (len * 2 + 1);
- bin2hex ((gdb_byte *) src->str, buf, len);
- sprintf (packet, "Z%x:%s:%s:%x:%x:%s",
- tpoint->number, paddress (tpoint->address),
- src->type, 0, len, buf);
- }
- /* Return the first piece of tracepoint definition, and initialize the
- state machine that will iterate through all the tracepoint
- bits. */
- static void
- cmd_qtfp (char *packet)
- {
- trace_debug ("Returning first tracepoint definition piece");
- cur_tpoint = tracepoints;
- cur_action = cur_step_action = 0;
- cur_source_string = NULL;
- if (cur_tpoint)
- response_tracepoint (packet, cur_tpoint);
- else
- strcpy (packet, "l");
- }
- /* Return additional pieces of tracepoint definition. Each action and
- stepping action must go into its own packet, because of packet size
- limits, and so we use state variables to deliver one piece at a
- time. */
- static void
- cmd_qtsp (char *packet)
- {
- trace_debug ("Returning subsequent tracepoint definition piece");
- if (!cur_tpoint)
- {
- /* This case would normally never occur, but be prepared for
- GDB misbehavior. */
- strcpy (packet, "l");
- }
- else if (cur_action < cur_tpoint->numactions)
- {
- response_action (packet, cur_tpoint,
- cur_tpoint->actions_str[cur_action], 0);
- ++cur_action;
- }
- else if (cur_step_action < cur_tpoint->num_step_actions)
- {
- response_action (packet, cur_tpoint,
- cur_tpoint->step_actions_str[cur_step_action], 1);
- ++cur_step_action;
- }
- else if ((cur_source_string
- ? cur_source_string->next
- : cur_tpoint->source_strings))
- {
- if (cur_source_string)
- cur_source_string = cur_source_string->next;
- else
- cur_source_string = cur_tpoint->source_strings;
- response_source (packet, cur_tpoint, cur_source_string);
- }
- else
- {
- cur_tpoint = cur_tpoint->next;
- cur_action = cur_step_action = 0;
- cur_source_string = NULL;
- if (cur_tpoint)
- response_tracepoint (packet, cur_tpoint);
- else
- strcpy (packet, "l");
- }
- }
- /* Compose a response that is an imitation of the syntax by which the
- trace state variable was originally downloaded. */
- static void
- response_tsv (char *packet, struct trace_state_variable *tsv)
- {
- char *buf = (char *) "";
- int namelen;
- if (tsv->name)
- {
- namelen = strlen (tsv->name);
- buf = (char *) alloca (namelen * 2 + 1);
- bin2hex ((gdb_byte *) tsv->name, buf, namelen);
- }
- sprintf (packet, "%x:%s:%x:%s", tsv->number, phex_nz (tsv->initial_value, 0),
- tsv->getter ? 1 : 0, buf);
- }
- /* Return the first trace state variable definition, and initialize
- the state machine that will iterate through all the tsv bits. */
- static void
- cmd_qtfv (char *packet)
- {
- trace_debug ("Returning first trace state variable definition");
- cur_tsv = trace_state_variables;
- if (cur_tsv)
- response_tsv (packet, cur_tsv);
- else
- strcpy (packet, "l");
- }
- /* Return additional trace state variable definitions. */
- static void
- cmd_qtsv (char *packet)
- {
- trace_debug ("Returning additional trace state variable definition");
- if (cur_tsv)
- {
- cur_tsv = cur_tsv->next;
- if (cur_tsv)
- response_tsv (packet, cur_tsv);
- else
- strcpy (packet, "l");
- }
- else
- strcpy (packet, "l");
- }
- /* Return the first static tracepoint marker, and initialize the state
- machine that will iterate through all the static tracepoints
- markers. */
- static void
- cmd_qtfstm (char *packet)
- {
- if (!maybe_write_ipa_ust_not_loaded (packet))
- run_inferior_command (packet, strlen (packet) + 1);
- }
- /* Return additional static tracepoints markers. */
- static void
- cmd_qtsstm (char *packet)
- {
- if (!maybe_write_ipa_ust_not_loaded (packet))
- run_inferior_command (packet, strlen (packet) + 1);
- }
- /* Return the definition of the static tracepoint at a given address.
- Result packet is the same as qTsST's. */
- static void
- cmd_qtstmat (char *packet)
- {
- if (!maybe_write_ipa_ust_not_loaded (packet))
- run_inferior_command (packet, strlen (packet) + 1);
- }
- /* Sent the agent a command to close it. */
- void
- gdb_agent_about_to_close (int pid)
- {
- char buf[IPA_CMD_BUF_SIZE];
- if (!maybe_write_ipa_not_loaded (buf))
- {
- scoped_restore_current_thread restore_thread;
- /* Find any thread which belongs to process PID. */
- switch_to_thread (find_any_thread_of_pid (pid));
- strcpy (buf, "close");
- run_inferior_command (buf, strlen (buf) + 1);
- }
- }
- /* Return the minimum instruction size needed for fast tracepoints as a
- hexadecimal number. */
- static void
- cmd_qtminftpilen (char *packet)
- {
- if (current_thread == NULL)
- {
- /* Indicate that the minimum length is currently unknown. */
- strcpy (packet, "0");
- return;
- }
- sprintf (packet, "%x", target_get_min_fast_tracepoint_insn_len ());
- }
- /* Respond to qTBuffer packet with a block of raw data from the trace
- buffer. GDB may ask for a lot, but we are allowed to reply with
- only as much as will fit within packet limits or whatever. */
- static void
- cmd_qtbuffer (char *own_buf)
- {
- ULONGEST offset, num, tot;
- unsigned char *tbp;
- const char *packet = own_buf;
- packet += strlen ("qTBuffer:");
- packet = unpack_varlen_hex (packet, &offset);
- ++packet; /* skip a comma */
- unpack_varlen_hex (packet, &num);
- trace_debug ("Want to get trace buffer, %d bytes at offset 0x%s",
- (int) num, phex_nz (offset, 0));
- tot = (trace_buffer_hi - trace_buffer_lo) - free_space ();
- /* If we're right at the end, reply specially that we're done. */
- if (offset == tot)
- {
- strcpy (own_buf, "l");
- return;
- }
- /* Object to any other out-of-bounds request. */
- if (offset > tot)
- {
- write_enn (own_buf);
- return;
- }
- /* Compute the pointer corresponding to the given offset, accounting
- for wraparound. */
- tbp = trace_buffer_start + offset;
- if (tbp >= trace_buffer_wrap)
- tbp -= (trace_buffer_wrap - trace_buffer_lo);
- /* Trim to the remaining bytes if we're close to the end. */
- if (num > tot - offset)
- num = tot - offset;
- /* Trim to available packet size. */
- if (num >= (PBUFSIZ - 16) / 2 )
- num = (PBUFSIZ - 16) / 2;
- bin2hex (tbp, own_buf, num);
- }
- static void
- cmd_bigqtbuffer_circular (char *own_buf)
- {
- ULONGEST val;
- char *packet = own_buf;
- packet += strlen ("QTBuffer:circular:");
- unpack_varlen_hex (packet, &val);
- circular_trace_buffer = val;
- trace_debug ("Trace buffer is now %s",
- circular_trace_buffer ? "circular" : "linear");
- write_ok (own_buf);
- }
- static void
- cmd_bigqtbuffer_size (char *own_buf)
- {
- ULONGEST val;
- LONGEST sval;
- char *packet = own_buf;
- /* Can't change the size during a tracing run. */
- if (tracing)
- {
- write_enn (own_buf);
- return;
- }
- packet += strlen ("QTBuffer:size:");
- /* -1 is sent as literal "-1". */
- if (strcmp (packet, "-1") == 0)
- sval = DEFAULT_TRACE_BUFFER_SIZE;
- else
- {
- unpack_varlen_hex (packet, &val);
- sval = (LONGEST) val;
- }
- init_trace_buffer (sval);
- trace_debug ("Trace buffer is now %s bytes",
- plongest (trace_buffer_size));
- write_ok (own_buf);
- }
- static void
- cmd_qtnotes (char *own_buf)
- {
- size_t nbytes;
- char *saved, *user, *notes, *stopnote;
- char *packet = own_buf;
- packet += strlen ("QTNotes:");
- while (*packet)
- {
- if (startswith (packet, "user:"))
- {
- packet += strlen ("user:");
- saved = packet;
- packet = strchr (packet, ';');
- nbytes = (packet - saved) / 2;
- user = (char *) xmalloc (nbytes + 1);
- nbytes = hex2bin (saved, (gdb_byte *) user, nbytes);
- user[nbytes] = '\0';
- ++packet; /* skip the semicolon */
- trace_debug ("User is '%s'", user);
- xfree (tracing_user_name);
- tracing_user_name = user;
- }
- else if (startswith (packet, "notes:"))
- {
- packet += strlen ("notes:");
- saved = packet;
- packet = strchr (packet, ';');
- nbytes = (packet - saved) / 2;
- notes = (char *) xmalloc (nbytes + 1);
- nbytes = hex2bin (saved, (gdb_byte *) notes, nbytes);
- notes[nbytes] = '\0';
- ++packet; /* skip the semicolon */
- trace_debug ("Notes is '%s'", notes);
- xfree (tracing_notes);
- tracing_notes = notes;
- }
- else if (startswith (packet, "tstop:"))
- {
- packet += strlen ("tstop:");
- saved = packet;
- packet = strchr (packet, ';');
- nbytes = (packet - saved) / 2;
- stopnote = (char *) xmalloc (nbytes + 1);
- nbytes = hex2bin (saved, (gdb_byte *) stopnote, nbytes);
- stopnote[nbytes] = '\0';
- ++packet; /* skip the semicolon */
- trace_debug ("tstop note is '%s'", stopnote);
- xfree (tracing_stop_note);
- tracing_stop_note = stopnote;
- }
- else
- break;
- }
- write_ok (own_buf);
- }
- int
- handle_tracepoint_general_set (char *packet)
- {
- if (strcmp ("QTinit", packet) == 0)
- {
- cmd_qtinit (packet);
- return 1;
- }
- else if (startswith (packet, "QTDP:"))
- {
- cmd_qtdp (packet);
- return 1;
- }
- else if (startswith (packet, "QTDPsrc:"))
- {
- cmd_qtdpsrc (packet);
- return 1;
- }
- else if (startswith (packet, "QTEnable:"))
- {
- cmd_qtenable_disable (packet, 1);
- return 1;
- }
- else if (startswith (packet, "QTDisable:"))
- {
- cmd_qtenable_disable (packet, 0);
- return 1;
- }
- else if (startswith (packet, "QTDV:"))
- {
- cmd_qtdv (packet);
- return 1;
- }
- else if (startswith (packet, "QTro:"))
- {
- cmd_qtro (packet);
- return 1;
- }
- else if (strcmp ("QTStart", packet) == 0)
- {
- cmd_qtstart (packet);
- return 1;
- }
- else if (strcmp ("QTStop", packet) == 0)
- {
- cmd_qtstop (packet);
- return 1;
- }
- else if (startswith (packet, "QTDisconnected:"))
- {
- cmd_qtdisconnected (packet);
- return 1;
- }
- else if (startswith (packet, "QTFrame:"))
- {
- cmd_qtframe (packet);
- return 1;
- }
- else if (startswith (packet, "QTBuffer:circular:"))
- {
- cmd_bigqtbuffer_circular (packet);
- return 1;
- }
- else if (startswith (packet, "QTBuffer:size:"))
- {
- cmd_bigqtbuffer_size (packet);
- return 1;
- }
- else if (startswith (packet, "QTNotes:"))
- {
- cmd_qtnotes (packet);
- return 1;
- }
- return 0;
- }
- int
- handle_tracepoint_query (char *packet)
- {
- if (strcmp ("qTStatus", packet) == 0)
- {
- cmd_qtstatus (packet);
- return 1;
- }
- else if (startswith (packet, "qTP:"))
- {
- cmd_qtp (packet);
- return 1;
- }
- else if (strcmp ("qTfP", packet) == 0)
- {
- cmd_qtfp (packet);
- return 1;
- }
- else if (strcmp ("qTsP", packet) == 0)
- {
- cmd_qtsp (packet);
- return 1;
- }
- else if (strcmp ("qTfV", packet) == 0)
- {
- cmd_qtfv (packet);
- return 1;
- }
- else if (strcmp ("qTsV", packet) == 0)
- {
- cmd_qtsv (packet);
- return 1;
- }
- else if (startswith (packet, "qTV:"))
- {
- cmd_qtv (packet);
- return 1;
- }
- else if (startswith (packet, "qTBuffer:"))
- {
- cmd_qtbuffer (packet);
- return 1;
- }
- else if (strcmp ("qTfSTM", packet) == 0)
- {
- cmd_qtfstm (packet);
- return 1;
- }
- else if (strcmp ("qTsSTM", packet) == 0)
- {
- cmd_qtsstm (packet);
- return 1;
- }
- else if (startswith (packet, "qTSTMat:"))
- {
- cmd_qtstmat (packet);
- return 1;
- }
- else if (strcmp ("qTMinFTPILen", packet) == 0)
- {
- cmd_qtminftpilen (packet);
- return 1;
- }
- return 0;
- }
- #endif
- #ifndef IN_PROCESS_AGENT
- /* Call this when thread TINFO has hit the tracepoint defined by
- TP_NUMBER and TP_ADDRESS, and that tracepoint has a while-stepping
- action. This adds a while-stepping collecting state item to the
- threads' collecting state list, so that we can keep track of
- multiple simultaneous while-stepping actions being collected by the
- same thread. This can happen in cases like:
- ff0001 INSN1 <-- TP1, while-stepping 10 collect $regs
- ff0002 INSN2
- ff0003 INSN3 <-- TP2, collect $regs
- ff0004 INSN4 <-- TP3, while-stepping 10 collect $regs
- ff0005 INSN5
- Notice that when instruction INSN5 is reached, the while-stepping
- actions of both TP1 and TP3 are still being collected, and that TP2
- had been collected meanwhile. The whole range of ff0001-ff0005
- should be single-stepped, due to at least TP1's while-stepping
- action covering the whole range. */
- static void
- add_while_stepping_state (struct thread_info *tinfo,
- int tp_number, CORE_ADDR tp_address)
- {
- struct wstep_state *wstep = XNEW (struct wstep_state);
- wstep->next = tinfo->while_stepping;
- wstep->tp_number = tp_number;
- wstep->tp_address = tp_address;
- wstep->current_step = 0;
- tinfo->while_stepping = wstep;
- }
- /* Release the while-stepping collecting state WSTEP. */
- static void
- release_while_stepping_state (struct wstep_state *wstep)
- {
- free (wstep);
- }
- /* Release all while-stepping collecting states currently associated
- with thread TINFO. */
- void
- release_while_stepping_state_list (struct thread_info *tinfo)
- {
- struct wstep_state *head;
- while (tinfo->while_stepping)
- {
- head = tinfo->while_stepping;
- tinfo->while_stepping = head->next;
- release_while_stepping_state (head);
- }
- }
- /* If TINFO was handling a 'while-stepping' action, the step has
- finished, so collect any step data needed, and check if any more
- steps are required. Return true if the thread was indeed
- collecting tracepoint data, false otherwise. */
- int
- tracepoint_finished_step (struct thread_info *tinfo, CORE_ADDR stop_pc)
- {
- struct tracepoint *tpoint;
- struct wstep_state *wstep;
- struct wstep_state **wstep_link;
- struct trap_tracepoint_ctx ctx;
- /* Pull in fast tracepoint trace frames from the inferior lib buffer into
- our buffer. */
- if (agent_loaded_p ())
- upload_fast_traceframes ();
- /* Check if we were indeed collecting data for one of more
- tracepoints with a 'while-stepping' count. */
- if (tinfo->while_stepping == NULL)
- return 0;
- if (!tracing)
- {
- /* We're not even tracing anymore. Stop this thread from
- collecting. */
- release_while_stepping_state_list (tinfo);
- /* The thread had stopped due to a single-step request indeed
- explained by a tracepoint. */
- return 1;
- }
- wstep = tinfo->while_stepping;
- wstep_link = &tinfo->while_stepping;
- trace_debug ("Thread %s finished a single-step for tracepoint %d at 0x%s",
- target_pid_to_str (tinfo->id).c_str (),
- wstep->tp_number, paddress (wstep->tp_address));
- ctx.base.type = trap_tracepoint;
- ctx.regcache = get_thread_regcache (tinfo, 1);
- while (wstep != NULL)
- {
- tpoint = find_tracepoint (wstep->tp_number, wstep->tp_address);
- if (tpoint == NULL)
- {
- trace_debug ("NO TRACEPOINT %d at 0x%s FOR THREAD %s!",
- wstep->tp_number, paddress (wstep->tp_address),
- target_pid_to_str (tinfo->id).c_str ());
- /* Unlink. */
- *wstep_link = wstep->next;
- release_while_stepping_state (wstep);
- wstep = *wstep_link;
- continue;
- }
- /* We've just finished one step. */
- ++wstep->current_step;
- /* Collect data. */
- collect_data_at_step ((struct tracepoint_hit_ctx *) &ctx,
- stop_pc, tpoint, wstep->current_step);
- if (wstep->current_step >= tpoint->step_count)
- {
- /* The requested numbers of steps have occurred. */
- trace_debug ("Thread %s done stepping for tracepoint %d at 0x%s",
- target_pid_to_str (tinfo->id).c_str (),
- wstep->tp_number, paddress (wstep->tp_address));
- /* Unlink the wstep. */
- *wstep_link = wstep->next;
- release_while_stepping_state (wstep);
- wstep = *wstep_link;
- /* Only check the hit count now, which ensure that we do all
- our stepping before stopping the run. */
- if (tpoint->pass_count > 0
- && tpoint->hit_count >= tpoint->pass_count
- && stopping_tracepoint == NULL)
- stopping_tracepoint = tpoint;
- }
- else
- {
- /* Keep single-stepping until the requested numbers of steps
- have occurred. */
- wstep_link = &wstep->next;
- wstep = *wstep_link;
- }
- if (stopping_tracepoint
- || trace_buffer_is_full
- || expr_eval_result != expr_eval_no_error)
- {
- stop_tracing ();
- break;
- }
- }
- return 1;
- }
- /* Handle any internal tracing control breakpoint hits. That means,
- pull traceframes from the IPA to our buffer, and syncing both
- tracing agents when the IPA's tracing stops for some reason. */
- int
- handle_tracepoint_bkpts (struct thread_info *tinfo, CORE_ADDR stop_pc)
- {
- /* Pull in fast tracepoint trace frames from the inferior in-process
- agent's buffer into our buffer. */
- if (!agent_loaded_p ())
- return 0;
- upload_fast_traceframes ();
- /* Check if the in-process agent had decided we should stop
- tracing. */
- if (stop_pc == ipa_sym_addrs.addr_stop_tracing)
- {
- int ipa_trace_buffer_is_full;
- CORE_ADDR ipa_stopping_tracepoint;
- int ipa_expr_eval_result;
- CORE_ADDR ipa_error_tracepoint;
- trace_debug ("lib stopped at stop_tracing");
- read_inferior_integer (ipa_sym_addrs.addr_trace_buffer_is_full,
- &ipa_trace_buffer_is_full);
- read_inferior_data_pointer (ipa_sym_addrs.addr_stopping_tracepoint,
- &ipa_stopping_tracepoint);
- write_inferior_data_pointer (ipa_sym_addrs.addr_stopping_tracepoint, 0);
- read_inferior_data_pointer (ipa_sym_addrs.addr_error_tracepoint,
- &ipa_error_tracepoint);
- write_inferior_data_pointer (ipa_sym_addrs.addr_error_tracepoint, 0);
- read_inferior_integer (ipa_sym_addrs.addr_expr_eval_result,
- &ipa_expr_eval_result);
- write_inferior_integer (ipa_sym_addrs.addr_expr_eval_result, 0);
- trace_debug ("lib: trace_buffer_is_full: %d, "
- "stopping_tracepoint: %s, "
- "ipa_expr_eval_result: %d, "
- "error_tracepoint: %s, ",
- ipa_trace_buffer_is_full,
- paddress (ipa_stopping_tracepoint),
- ipa_expr_eval_result,
- paddress (ipa_error_tracepoint));
- if (ipa_trace_buffer_is_full)
- trace_debug ("lib stopped due to full buffer.");
- if (ipa_stopping_tracepoint)
- trace_debug ("lib stopped due to tpoint");
- if (ipa_error_tracepoint)
- trace_debug ("lib stopped due to error");
- if (ipa_stopping_tracepoint != 0)
- {
- stopping_tracepoint
- = fast_tracepoint_from_ipa_tpoint_address (ipa_stopping_tracepoint);
- }
- else if (ipa_expr_eval_result != expr_eval_no_error)
- {
- expr_eval_result = ipa_expr_eval_result;
- error_tracepoint
- = fast_tracepoint_from_ipa_tpoint_address (ipa_error_tracepoint);
- }
- stop_tracing ();
- return 1;
- }
- else if (stop_pc == ipa_sym_addrs.addr_flush_trace_buffer)
- {
- trace_debug ("lib stopped at flush_trace_buffer");
- return 1;
- }
- return 0;
- }
- /* Return true if TINFO just hit a tracepoint. Collect data if
- so. */
- int
- tracepoint_was_hit (struct thread_info *tinfo, CORE_ADDR stop_pc)
- {
- struct tracepoint *tpoint;
- int ret = 0;
- struct trap_tracepoint_ctx ctx;
- /* Not tracing, don't handle. */
- if (!tracing)
- return 0;
- ctx.base.type = trap_tracepoint;
- ctx.regcache = get_thread_regcache (tinfo, 1);
- for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
- {
- /* Note that we collect fast tracepoints here as well. We'll
- step over the fast tracepoint jump later, which avoids the
- double collect. However, we don't collect for static
- tracepoints here, because UST markers are compiled in program,
- and probes will be executed in program. So static tracepoints
- are collected there. */
- if (tpoint->enabled && stop_pc == tpoint->address
- && tpoint->type != static_tracepoint)
- {
- trace_debug ("Thread %s at address of tracepoint %d at 0x%s",
- target_pid_to_str (tinfo->id).c_str (),
- tpoint->number, paddress (tpoint->address));
- /* Test the condition if present, and collect if true. */
- if (!tpoint->cond
- || (condition_true_at_tracepoint
- ((struct tracepoint_hit_ctx *) &ctx, tpoint)))
- collect_data_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx,
- stop_pc, tpoint);
- if (stopping_tracepoint
- || trace_buffer_is_full
- || expr_eval_result != expr_eval_no_error)
- {
- stop_tracing ();
- }
- /* If the tracepoint had a 'while-stepping' action, then set
- the thread to collect this tracepoint on the following
- single-steps. */
- else if (tpoint->step_count > 0)
- {
- add_while_stepping_state (tinfo,
- tpoint->number, tpoint->address);
- }
- ret = 1;
- }
- }
- return ret;
- }
- #endif
- #if defined IN_PROCESS_AGENT && defined HAVE_UST
- struct ust_marker_data;
- static void collect_ust_data_at_tracepoint (struct tracepoint_hit_ctx *ctx,
- struct traceframe *tframe);
- #endif
- /* Create a trace frame for the hit of the given tracepoint in the
- given thread. */
- static void
- collect_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, CORE_ADDR stop_pc,
- struct tracepoint *tpoint)
- {
- struct traceframe *tframe;
- int acti;
- /* Only count it as a hit when we actually collect data. */
- tpoint->hit_count++;
- /* If we've exceeded a defined pass count, record the event for
- later, and finish the collection for this hit. This test is only
- for nonstepping tracepoints, stepping tracepoints test at the end
- of their while-stepping loop. */
- if (tpoint->pass_count > 0
- && tpoint->hit_count >= tpoint->pass_count
- && tpoint->step_count == 0
- && stopping_tracepoint == NULL)
- stopping_tracepoint = tpoint;
- trace_debug ("Making new traceframe for tracepoint %d at 0x%s, hit %" PRIu64,
- tpoint->number, paddress (tpoint->address), tpoint->hit_count);
- tframe = add_traceframe (tpoint);
- if (tframe)
- {
- for (acti = 0; acti < tpoint->numactions; ++acti)
- {
- #ifndef IN_PROCESS_AGENT
- trace_debug ("Tracepoint %d at 0x%s about to do action '%s'",
- tpoint->number, paddress (tpoint->address),
- tpoint->actions_str[acti]);
- #endif
- do_action_at_tracepoint (ctx, stop_pc, tpoint, tframe,
- tpoint->actions[acti]);
- }
- finish_traceframe (tframe);
- }
- if (tframe == NULL && tracing)
- trace_buffer_is_full = 1;
- }
- #ifndef IN_PROCESS_AGENT
- static void
- collect_data_at_step (struct tracepoint_hit_ctx *ctx,
- CORE_ADDR stop_pc,
- struct tracepoint *tpoint, int current_step)
- {
- struct traceframe *tframe;
- int acti;
- trace_debug ("Making new step traceframe for "
- "tracepoint %d at 0x%s, step %d of %" PRIu64 ", hit %" PRIu64,
- tpoint->number, paddress (tpoint->address),
- current_step, tpoint->step_count,
- tpoint->hit_count);
- tframe = add_traceframe (tpoint);
- if (tframe)
- {
- for (acti = 0; acti < tpoint->num_step_actions; ++acti)
- {
- trace_debug ("Tracepoint %d at 0x%s about to do step action '%s'",
- tpoint->number, paddress (tpoint->address),
- tpoint->step_actions_str[acti]);
- do_action_at_tracepoint (ctx, stop_pc, tpoint, tframe,
- tpoint->step_actions[acti]);
- }
- finish_traceframe (tframe);
- }
- if (tframe == NULL && tracing)
- trace_buffer_is_full = 1;
- }
- #endif
- #ifdef IN_PROCESS_AGENT
- /* The target description index for IPA. Passed from gdbserver, used
- to select ipa_tdesc. */
- EXTERN_C_PUSH
- IP_AGENT_EXPORT_VAR int ipa_tdesc_idx;
- EXTERN_C_POP
- #endif
- static struct regcache *
- get_context_regcache (struct tracepoint_hit_ctx *ctx)
- {
- struct regcache *regcache = NULL;
- #ifdef IN_PROCESS_AGENT
- const struct target_desc *ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx);
- if (ctx->type == fast_tracepoint)
- {
- struct fast_tracepoint_ctx *fctx = (struct fast_tracepoint_ctx *) ctx;
- if (!fctx->regcache_initted)
- {
- fctx->regcache_initted = 1;
- init_register_cache (&fctx->regcache, ipa_tdesc, fctx->regspace);
- supply_regblock (&fctx->regcache, NULL);
- supply_fast_tracepoint_registers (&fctx->regcache, fctx->regs);
- }
- regcache = &fctx->regcache;
- }
- #ifdef HAVE_UST
- if (ctx->type == static_tracepoint)
- {
- struct static_tracepoint_ctx *sctx
- = (struct static_tracepoint_ctx *) ctx;
- if (!sctx->regcache_initted)
- {
- sctx->regcache_initted = 1;
- init_register_cache (&sctx->regcache, ipa_tdesc, sctx->regspace);
- supply_regblock (&sctx->regcache, NULL);
- /* Pass down the tracepoint address, because REGS doesn't
- include the PC, but we know what it must have been. */
- supply_static_tracepoint_registers (&sctx->regcache,
- (const unsigned char *)
- sctx->regs,
- sctx->tpoint->address);
- }
- regcache = &sctx->regcache;
- }
- #endif
- #else
- if (ctx->type == trap_tracepoint)
- {
- struct trap_tracepoint_ctx *tctx = (struct trap_tracepoint_ctx *) ctx;
- regcache = tctx->regcache;
- }
- #endif
- gdb_assert (regcache != NULL);
- return regcache;
- }
- static void
- do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
- CORE_ADDR stop_pc,
- struct tracepoint *tpoint,
- struct traceframe *tframe,
- struct tracepoint_action *taction)
- {
- enum eval_result_type err;
- switch (taction->type)
- {
- case 'M':
- {
- struct collect_memory_action *maction;
- struct eval_agent_expr_context ax_ctx;
- maction = (struct collect_memory_action *) taction;
- ax_ctx.regcache = NULL;
- ax_ctx.tframe = tframe;
- ax_ctx.tpoint = tpoint;
- trace_debug ("Want to collect %s bytes at 0x%s (basereg %d)",
- pulongest (maction->len),
- paddress (maction->addr), maction->basereg);
- /* (should use basereg) */
- agent_mem_read (&ax_ctx, NULL, (CORE_ADDR) maction->addr,
- maction->len);
- break;
- }
- case 'R':
- {
- unsigned char *regspace;
- struct regcache tregcache;
- struct regcache *context_regcache;
- int regcache_size;
- trace_debug ("Want to collect registers");
- context_regcache = get_context_regcache (ctx);
- regcache_size = register_cache_size (context_regcache->tdesc);
- /* Collect all registers for now. */
- regspace = add_traceframe_block (tframe, tpoint, 1 + regcache_size);
- if (regspace == NULL)
- {
- trace_debug ("Trace buffer block allocation failed, skipping");
- break;
- }
- /* Identify a register block. */
- *regspace = 'R';
- /* Wrap the regblock in a register cache (in the stack, we
- don't want to malloc here). */
- init_register_cache (&tregcache, context_regcache->tdesc,
- regspace + 1);
- /* Copy the register data to the regblock. */
- regcache_cpy (&tregcache, context_regcache);
- #ifndef IN_PROCESS_AGENT
- /* On some platforms, trap-based tracepoints will have the PC
- pointing to the next instruction after the trap, but we
- don't want the user or GDB trying to guess whether the
- saved PC needs adjusting; so always record the adjusted
- stop_pc. Note that we can't use tpoint->address instead,
- since it will be wrong for while-stepping actions. This
- adjustment is a nop for fast tracepoints collected from the
- in-process lib (but not if GDBserver is collecting one
- preemptively), since the PC had already been adjusted to
- contain the tracepoint's address by the jump pad. */
- trace_debug ("Storing stop pc (0x%s) in regblock",
- paddress (stop_pc));
- /* This changes the regblock, not the thread's
- regcache. */
- regcache_write_pc (&tregcache, stop_pc);
- #endif
- }
- break;
- case 'X':
- {
- struct eval_expr_action *eaction;
- struct eval_agent_expr_context ax_ctx;
- eaction = (struct eval_expr_action *) taction;
- ax_ctx.regcache = get_context_regcache (ctx);
- ax_ctx.tframe = tframe;
- ax_ctx.tpoint = tpoint;
- trace_debug ("Want to evaluate expression");
- err = gdb_eval_agent_expr (&ax_ctx, eaction->expr, NULL);
- if (err != expr_eval_no_error)
- {
- record_tracepoint_error (tpoint, "action expression", err);
- return;
- }
- }
- break;
- case 'L':
- {
- #if defined IN_PROCESS_AGENT && defined HAVE_UST
- trace_debug ("Want to collect static trace data");
- collect_ust_data_at_tracepoint (ctx, tframe);
- #else
- trace_debug ("warning: collecting static trace data, "
- "but static tracepoints are not supported");
- #endif
- }
- break;
- default:
- trace_debug ("unknown trace action '%c', ignoring", taction->type);
- break;
- }
- }
- static int
- condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx,
- struct tracepoint *tpoint)
- {
- ULONGEST value = 0;
- enum eval_result_type err;
- /* Presently, gdbserver doesn't run compiled conditions, only the
- IPA does. If the program stops at a fast tracepoint's address
- (e.g., due to a breakpoint, trap tracepoint, or stepping),
- gdbserver preemptively collect the fast tracepoint. Later, on
- resume, gdbserver steps over the fast tracepoint like it steps
- over breakpoints, so that the IPA doesn't see that fast
- tracepoint. This avoids double collects of fast tracepoints in
- that stopping scenario. Having gdbserver itself handle the fast
- tracepoint gives the user a consistent view of when fast or trap
- tracepoints are collected, compared to an alternative where only
- trap tracepoints are collected on stop, and fast tracepoints on
- resume. When a fast tracepoint is being processed by gdbserver,
- it is always the non-compiled condition expression that is
- used. */
- #ifdef IN_PROCESS_AGENT
- if (tpoint->compiled_cond)
- {
- struct fast_tracepoint_ctx *fctx = (struct fast_tracepoint_ctx *) ctx;
- err = ((condfn) (uintptr_t) (tpoint->compiled_cond)) (fctx->regs, &value);
- }
- else
- #endif
- {
- struct eval_agent_expr_context ax_ctx;
- ax_ctx.regcache = get_context_regcache (ctx);
- ax_ctx.tframe = NULL;
- ax_ctx.tpoint = tpoint;
- err = gdb_eval_agent_expr (&ax_ctx, tpoint->cond, &value);
- }
- if (err != expr_eval_no_error)
- {
- record_tracepoint_error (tpoint, "condition", err);
- /* The error case must return false. */
- return 0;
- }
- trace_debug ("Tracepoint %d at 0x%s condition evals to %s",
- tpoint->number, paddress (tpoint->address),
- pulongest (value));
- return (value ? 1 : 0);
- }
- /* Do memory copies for bytecodes. */
- /* Do the recording of memory blocks for actions and bytecodes. */
- int
- agent_mem_read (struct eval_agent_expr_context *ctx,
- unsigned char *to, CORE_ADDR from, ULONGEST len)
- {
- unsigned char *mspace;
- ULONGEST remaining = len;
- unsigned short blocklen;
- /* If a 'to' buffer is specified, use it. */
- if (to != NULL)
- {
- read_inferior_memory (from, to, len);
- return 0;
- }
- /* Otherwise, create a new memory block in the trace buffer. */
- while (remaining > 0)
- {
- size_t sp;
- blocklen = (remaining > 65535 ? 65535 : remaining);
- sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen;
- mspace = add_traceframe_block (ctx->tframe, ctx->tpoint, sp);
- if (mspace == NULL)
- return 1;
- /* Identify block as a memory block. */
- *mspace = 'M';
- ++mspace;
- /* Record address and size. */
- memcpy (mspace, &from, sizeof (from));
- mspace += sizeof (from);
- memcpy (mspace, &blocklen, sizeof (blocklen));
- mspace += sizeof (blocklen);
- /* Record the memory block proper. */
- read_inferior_memory (from, mspace, blocklen);
- trace_debug ("%d bytes recorded", blocklen);
- remaining -= blocklen;
- from += blocklen;
- }
- return 0;
- }
- int
- agent_mem_read_string (struct eval_agent_expr_context *ctx,
- unsigned char *to, CORE_ADDR from, ULONGEST len)
- {
- unsigned char *buf, *mspace;
- ULONGEST remaining = len;
- unsigned short blocklen, i;
- /* To save a bit of space, block lengths are 16-bit, so break large
- requests into multiple blocks. Bordering on overkill for strings,
- but it could happen that someone specifies a large max length. */
- while (remaining > 0)
- {
- size_t sp;
- blocklen = (remaining > 65535 ? 65535 : remaining);
- /* We want working space to accumulate nonzero bytes, since
- traceframes must have a predecided size (otherwise it gets
- harder to wrap correctly for the circular case, etc). */
- buf = (unsigned char *) xmalloc (blocklen + 1);
- for (i = 0; i < blocklen; ++i)
- {
- /* Read the string one byte at a time, in case the string is
- at the end of a valid memory area - we don't want a
- correctly-terminated string to engender segvio
- complaints. */
- read_inferior_memory (from + i, buf + i, 1);
- if (buf[i] == '\0')
- {
- blocklen = i + 1;
- /* Make sure outer loop stops now too. */
- remaining = blocklen;
- break;
- }
- }
- sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen;
- mspace = add_traceframe_block (ctx->tframe, ctx->tpoint, sp);
- if (mspace == NULL)
- {
- xfree (buf);
- return 1;
- }
- /* Identify block as a memory block. */
- *mspace = 'M';
- ++mspace;
- /* Record address and size. */
- memcpy ((void *) mspace, (void *) &from, sizeof (from));
- mspace += sizeof (from);
- memcpy ((void *) mspace, (void *) &blocklen, sizeof (blocklen));
- mspace += sizeof (blocklen);
- /* Copy the string contents. */
- memcpy ((void *) mspace, (void *) buf, blocklen);
- remaining -= blocklen;
- from += blocklen;
- xfree (buf);
- }
- return 0;
- }
- /* Record the value of a trace state variable. */
- int
- agent_tsv_read (struct eval_agent_expr_context *ctx, int n)
- {
- unsigned char *vspace;
- LONGEST val;
- vspace = add_traceframe_block (ctx->tframe, ctx->tpoint,
- 1 + sizeof (n) + sizeof (LONGEST));
- if (vspace == NULL)
- return 1;
- /* Identify block as a variable. */
- *vspace = 'V';
- /* Record variable's number and value. */
- memcpy (vspace + 1, &n, sizeof (n));
- val = get_trace_state_variable_value (n);
- memcpy (vspace + 1 + sizeof (n), &val, sizeof (val));
- trace_debug ("Variable %d recorded", n);
- return 0;
- }
- #ifndef IN_PROCESS_AGENT
- /* Callback for traceframe_walk_blocks, used to find a given block
- type in a traceframe. */
- static int
- match_blocktype (char blocktype, unsigned char *dataptr, void *data)
- {
- char *wantedp = (char *) data;
- if (*wantedp == blocktype)
- return 1;
- return 0;
- }
- /* Walk over all traceframe blocks of the traceframe buffer starting
- at DATABASE, of DATASIZE bytes long, and call CALLBACK for each
- block found, passing in DATA unmodified. If CALLBACK returns true,
- this returns a pointer to where the block is found. Returns NULL
- if no callback call returned true, indicating that all blocks have
- been walked. */
- static unsigned char *
- traceframe_walk_blocks (unsigned char *database, unsigned int datasize,
- int tfnum,
- int (*callback) (char blocktype,
- unsigned char *dataptr,
- void *data),
- void *data)
- {
- unsigned char *dataptr;
- if (datasize == 0)
- {
- trace_debug ("traceframe %d has no data", tfnum);
- return NULL;
- }
- /* Iterate through a traceframe's blocks, looking for a block of the
- requested type. */
- for (dataptr = database;
- dataptr < database + datasize;
- /* nothing */)
- {
- char blocktype;
- unsigned short mlen;
- if (dataptr == trace_buffer_wrap)
- {
- /* Adjust to reflect wrapping part of the frame around to
- the beginning. */
- datasize = dataptr - database;
- dataptr = database = trace_buffer_lo;
- }
- blocktype = *dataptr++;
- if ((*callback) (blocktype, dataptr, data))
- return dataptr;
- switch (blocktype)
- {
- case 'R':
- /* Skip over the registers block. */
- dataptr += current_target_desc ()->registers_size;
- break;
- case 'M':
- /* Skip over the memory block. */
- dataptr += sizeof (CORE_ADDR);
- memcpy (&mlen, dataptr, sizeof (mlen));
- dataptr += (sizeof (mlen) + mlen);
- break;
- case 'V':
- /* Skip over the TSV block. */
- dataptr += (sizeof (int) + sizeof (LONGEST));
- break;
- case 'S':
- /* Skip over the static trace data block. */
- memcpy (&mlen, dataptr, sizeof (mlen));
- dataptr += (sizeof (mlen) + mlen);
- break;
- default:
- trace_debug ("traceframe %d has unknown block type 0x%x",
- tfnum, blocktype);
- return NULL;
- }
- }
- return NULL;
- }
- /* Look for the block of type TYPE_WANTED in the traceframe starting
- at DATABASE of DATASIZE bytes long. TFNUM is the traceframe
- number. */
- static unsigned char *
- traceframe_find_block_type (unsigned char *database, unsigned int datasize,
- int tfnum, char type_wanted)
- {
- return traceframe_walk_blocks (database, datasize, tfnum,
- match_blocktype, &type_wanted);
- }
- static unsigned char *
- traceframe_find_regblock (struct traceframe *tframe, int tfnum)
- {
- unsigned char *regblock;
- regblock = traceframe_find_block_type (tframe->data,
- tframe->data_size,
- tfnum, 'R');
- if (regblock == NULL)
- trace_debug ("traceframe %d has no register data", tfnum);
- return regblock;
- }
- /* Get registers from a traceframe. */
- int
- fetch_traceframe_registers (int tfnum, struct regcache *regcache, int regnum)
- {
- unsigned char *dataptr;
- struct tracepoint *tpoint;
- struct traceframe *tframe;
- tframe = find_traceframe (tfnum);
- if (tframe == NULL)
- {
- trace_debug ("traceframe %d not found", tfnum);
- return 1;
- }
- dataptr = traceframe_find_regblock (tframe, tfnum);
- if (dataptr == NULL)
- {
- /* Mark registers unavailable. */
- supply_regblock (regcache, NULL);
- /* We can generally guess at a PC, although this will be
- misleading for while-stepping frames and multi-location
- tracepoints. */
- tpoint = find_next_tracepoint_by_number (NULL, tframe->tpnum);
- if (tpoint != NULL)
- regcache_write_pc (regcache, tpoint->address);
- }
- else
- supply_regblock (regcache, dataptr);
- return 0;
- }
- static CORE_ADDR
- traceframe_get_pc (struct traceframe *tframe)
- {
- struct regcache regcache;
- unsigned char *dataptr;
- const struct target_desc *tdesc = current_target_desc ();
- dataptr = traceframe_find_regblock (tframe, -1);
- if (dataptr == NULL)
- return 0;
- init_register_cache (®cache, tdesc, dataptr);
- return regcache_read_pc (®cache);
- }
- /* Read a requested block of memory from a trace frame. */
- int
- traceframe_read_mem (int tfnum, CORE_ADDR addr,
- unsigned char *buf, ULONGEST length,
- ULONGEST *nbytes)
- {
- struct traceframe *tframe;
- unsigned char *database, *dataptr;
- unsigned int datasize;
- CORE_ADDR maddr;
- unsigned short mlen;
- trace_debug ("traceframe_read_mem");
- tframe = find_traceframe (tfnum);
- if (!tframe)
- {
- trace_debug ("traceframe %d not found", tfnum);
- return 1;
- }
- datasize = tframe->data_size;
- database = dataptr = &tframe->data[0];
- /* Iterate through a traceframe's blocks, looking for memory. */
- while ((dataptr = traceframe_find_block_type (dataptr,
- datasize
- - (dataptr - database),
- tfnum, 'M')) != NULL)
- {
- memcpy (&maddr, dataptr, sizeof (maddr));
- dataptr += sizeof (maddr);
- memcpy (&mlen, dataptr, sizeof (mlen));
- dataptr += sizeof (mlen);
- trace_debug ("traceframe %d has %d bytes at %s",
- tfnum, mlen, paddress (maddr));
- /* If the block includes the first part of the desired range,
- return as much it has; GDB will re-request the remainder,
- which might be in a different block of this trace frame. */
- if (maddr <= addr && addr < (maddr + mlen))
- {
- ULONGEST amt = (maddr + mlen) - addr;
- if (amt > length)
- amt = length;
- memcpy (buf, dataptr + (addr - maddr), amt);
- *nbytes = amt;
- return 0;
- }
- /* Skip over this block. */
- dataptr += mlen;
- }
- trace_debug ("traceframe %d has no memory data for the desired region",
- tfnum);
- *nbytes = 0;
- return 0;
- }
- static int
- traceframe_read_tsv (int tsvnum, LONGEST *val)
- {
- client_state &cs = get_client_state ();
- int tfnum;
- struct traceframe *tframe;
- unsigned char *database, *dataptr;
- unsigned int datasize;
- int vnum;
- int found = 0;
- trace_debug ("traceframe_read_tsv");
- tfnum = cs.current_traceframe;
- if (tfnum < 0)
- {
- trace_debug ("no current traceframe");
- return 1;
- }
- tframe = find_traceframe (tfnum);
- if (tframe == NULL)
- {
- trace_debug ("traceframe %d not found", tfnum);
- return 1;
- }
- datasize = tframe->data_size;
- database = dataptr = &tframe->data[0];
- /* Iterate through a traceframe's blocks, looking for the last
- matched tsv. */
- while ((dataptr = traceframe_find_block_type (dataptr,
- datasize
- - (dataptr - database),
- tfnum, 'V')) != NULL)
- {
- memcpy (&vnum, dataptr, sizeof (vnum));
- dataptr += sizeof (vnum);
- trace_debug ("traceframe %d has variable %d", tfnum, vnum);
- /* Check that this is the variable we want. */
- if (tsvnum == vnum)
- {
- memcpy (val, dataptr, sizeof (*val));
- found = 1;
- }
- /* Skip over this block. */
- dataptr += sizeof (LONGEST);
- }
- if (!found)
- trace_debug ("traceframe %d has no data for variable %d",
- tfnum, tsvnum);
- return !found;
- }
- /* Read a requested block of static tracepoint data from a trace
- frame. */
- int
- traceframe_read_sdata (int tfnum, ULONGEST offset,
- unsigned char *buf, ULONGEST length,
- ULONGEST *nbytes)
- {
- struct traceframe *tframe;
- unsigned char *database, *dataptr;
- unsigned int datasize;
- unsigned short mlen;
- trace_debug ("traceframe_read_sdata");
- tframe = find_traceframe (tfnum);
- if (!tframe)
- {
- trace_debug ("traceframe %d not found", tfnum);
- return 1;
- }
- datasize = tframe->data_size;
- database = &tframe->data[0];
- /* Iterate through a traceframe's blocks, looking for static
- tracepoint data. */
- dataptr = traceframe_find_block_type (database, datasize,
- tfnum, 'S');
- if (dataptr != NULL)
- {
- memcpy (&mlen, dataptr, sizeof (mlen));
- dataptr += sizeof (mlen);
- if (offset < mlen)
- {
- if (offset + length > mlen)
- length = mlen - offset;
- memcpy (buf, dataptr, length);
- *nbytes = length;
- }
- else
- *nbytes = 0;
- return 0;
- }
- trace_debug ("traceframe %d has no static trace data", tfnum);
- *nbytes = 0;
- return 0;
- }
- /* Callback for traceframe_walk_blocks. Builds a traceframe-info
- object. DATA is pointer to a struct buffer holding the
- traceframe-info object being built. */
- static int
- build_traceframe_info_xml (char blocktype, unsigned char *dataptr, void *data)
- {
- struct buffer *buffer = (struct buffer *) data;
- switch (blocktype)
- {
- case 'M':
- {
- unsigned short mlen;
- CORE_ADDR maddr;
- memcpy (&maddr, dataptr, sizeof (maddr));
- dataptr += sizeof (maddr);
- memcpy (&mlen, dataptr, sizeof (mlen));
- dataptr += sizeof (mlen);
- buffer_xml_printf (buffer,
- "<memory start=\"0x%s\" length=\"0x%s\"/>\n",
- paddress (maddr), phex_nz (mlen, sizeof (mlen)));
- break;
- }
- case 'V':
- {
- int vnum;
- memcpy (&vnum, dataptr, sizeof (vnum));
- buffer_xml_printf (buffer, "<tvar id=\"%d\"/>\n", vnum);
- break;
- }
- case 'R':
- case 'S':
- {
- break;
- }
- default:
- warning ("Unhandled trace block type (%d) '%c ' "
- "while building trace frame info.",
- blocktype, blocktype);
- break;
- }
- return 0;
- }
- /* Build a traceframe-info object for traceframe number TFNUM into
- BUFFER. */
- int
- traceframe_read_info (int tfnum, struct buffer *buffer)
- {
- struct traceframe *tframe;
- trace_debug ("traceframe_read_info");
- tframe = find_traceframe (tfnum);
- if (!tframe)
- {
- trace_debug ("traceframe %d not found", tfnum);
- return 1;
- }
- buffer_grow_str (buffer, "<traceframe-info>\n");
- traceframe_walk_blocks (tframe->data, tframe->data_size,
- tfnum, build_traceframe_info_xml, buffer);
- buffer_grow_str0 (buffer, "</traceframe-info>\n");
- return 0;
- }
- /* Return the first fast tracepoint whose jump pad contains PC. */
- static struct tracepoint *
- fast_tracepoint_from_jump_pad_address (CORE_ADDR pc)
- {
- struct tracepoint *tpoint;
- for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
- if (tpoint->type == fast_tracepoint)
- if (tpoint->jump_pad <= pc && pc < tpoint->jump_pad_end)
- return tpoint;
- return NULL;
- }
- /* Return the first fast tracepoint whose trampoline contains PC. */
- static struct tracepoint *
- fast_tracepoint_from_trampoline_address (CORE_ADDR pc)
- {
- struct tracepoint *tpoint;
- for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
- {
- if (tpoint->type == fast_tracepoint
- && tpoint->trampoline <= pc && pc < tpoint->trampoline_end)
- return tpoint;
- }
- return NULL;
- }
- /* Return GDBserver's tracepoint that matches the IP Agent's
- tracepoint object that lives at IPA_TPOINT_OBJ in the IP Agent's
- address space. */
- static struct tracepoint *
- fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR ipa_tpoint_obj)
- {
- struct tracepoint *tpoint;
- for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
- if (tpoint->type == fast_tracepoint)
- if (tpoint->obj_addr_on_target == ipa_tpoint_obj)
- return tpoint;
- return NULL;
- }
- #endif
- /* The type of the object that is used to synchronize fast tracepoint
- collection. */
- typedef struct collecting_t
- {
- /* The fast tracepoint number currently collecting. */
- uintptr_t tpoint;
- /* A number that GDBserver can use to identify the thread that is
- presently holding the collect lock. This need not (and usually
- is not) the thread id, as getting the current thread ID usually
- requires a system call, which we want to avoid like the plague.
- Usually this is thread's TCB, found in the TLS (pseudo-)
- register, which is readable with a single insn on several
- architectures. */
- uintptr_t thread_area;
- } collecting_t;
- #ifndef IN_PROCESS_AGENT
- void
- force_unlock_trace_buffer (void)
- {
- write_inferior_data_pointer (ipa_sym_addrs.addr_collecting, 0);
- }
- /* Check if the thread identified by THREAD_AREA which is stopped at
- STOP_PC, is presently locking the fast tracepoint collection, and
- if so, gather some status of said collection. Returns 0 if the
- thread isn't collecting or in the jump pad at all. 1, if in the
- jump pad (or within gdb_collect) and hasn't executed the adjusted
- original insn yet (can set a breakpoint there and run to it). 2,
- if presently executing the adjusted original insn --- in which
- case, if we want to move the thread out of the jump pad, we need to
- single-step it until this function returns 0. */
- fast_tpoint_collect_result
- fast_tracepoint_collecting (CORE_ADDR thread_area,
- CORE_ADDR stop_pc,
- struct fast_tpoint_collect_status *status)
- {
- CORE_ADDR ipa_collecting;
- CORE_ADDR ipa_gdb_jump_pad_buffer, ipa_gdb_jump_pad_buffer_end;
- CORE_ADDR ipa_gdb_trampoline_buffer;
- CORE_ADDR ipa_gdb_trampoline_buffer_end;
- struct tracepoint *tpoint;
- int needs_breakpoint;
- /* The thread THREAD_AREA is either:
- 0. not collecting at all, not within the jump pad, or within
- gdb_collect or one of its callees.
- 1. in the jump pad and haven't reached gdb_collect
- 2. within gdb_collect (out of the jump pad) (collect is set)
- 3. we're in the jump pad, after gdb_collect having returned,
- possibly executing the adjusted insns.
- For cases 1 and 3, `collecting' may or not be set. The jump pad
- doesn't have any complicated jump logic, so we can tell if the
- thread is executing the adjust original insn or not by just
- matching STOP_PC with known jump pad addresses. If we it isn't
- yet executing the original insn, set a breakpoint there, and let
- the thread run to it, so to quickly step over a possible (many
- insns) gdb_collect call. Otherwise, or when the breakpoint is
- hit, only a few (small number of) insns are left to be executed
- in the jump pad. Single-step the thread until it leaves the
- jump pad. */
- again:
- tpoint = NULL;
- needs_breakpoint = 0;
- trace_debug ("fast_tracepoint_collecting");
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer,
- &ipa_gdb_jump_pad_buffer))
- {
- internal_error (__FILE__, __LINE__,
- "error extracting `gdb_jump_pad_buffer'");
- }
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer_end,
- &ipa_gdb_jump_pad_buffer_end))
- {
- internal_error (__FILE__, __LINE__,
- "error extracting `gdb_jump_pad_buffer_end'");
- }
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer,
- &ipa_gdb_trampoline_buffer))
- {
- internal_error (__FILE__, __LINE__,
- "error extracting `gdb_trampoline_buffer'");
- }
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end,
- &ipa_gdb_trampoline_buffer_end))
- {
- internal_error (__FILE__, __LINE__,
- "error extracting `gdb_trampoline_buffer_end'");
- }
- if (ipa_gdb_jump_pad_buffer <= stop_pc
- && stop_pc < ipa_gdb_jump_pad_buffer_end)
- {
- /* We can tell which tracepoint(s) the thread is collecting by
- matching the jump pad address back to the tracepoint. */
- tpoint = fast_tracepoint_from_jump_pad_address (stop_pc);
- if (tpoint == NULL)
- {
- warning ("in jump pad, but no matching tpoint?");
- return fast_tpoint_collect_result::not_collecting;
- }
- else
- {
- trace_debug ("in jump pad of tpoint (%d, %s); jump_pad(%s, %s); "
- "adj_insn(%s, %s)",
- tpoint->number, paddress (tpoint->address),
- paddress (tpoint->jump_pad),
- paddress (tpoint->jump_pad_end),
- paddress (tpoint->adjusted_insn_addr),
- paddress (tpoint->adjusted_insn_addr_end));
- }
- /* Definitely in the jump pad. May or may not need
- fast-exit-jump-pad breakpoint. */
- if (tpoint->jump_pad <= stop_pc
- && stop_pc < tpoint->adjusted_insn_addr)
- needs_breakpoint = 1;
- }
- else if (ipa_gdb_trampoline_buffer <= stop_pc
- && stop_pc < ipa_gdb_trampoline_buffer_end)
- {
- /* We can tell which tracepoint(s) the thread is collecting by
- matching the trampoline address back to the tracepoint. */
- tpoint = fast_tracepoint_from_trampoline_address (stop_pc);
- if (tpoint == NULL)
- {
- warning ("in trampoline, but no matching tpoint?");
- return fast_tpoint_collect_result::not_collecting;
- }
- else
- {
- trace_debug ("in trampoline of tpoint (%d, %s); trampoline(%s, %s)",
- tpoint->number, paddress (tpoint->address),
- paddress (tpoint->trampoline),
- paddress (tpoint->trampoline_end));
- }
- /* Have not reached jump pad yet, but treat the trampoline as a
- part of the jump pad that is before the adjusted original
- instruction. */
- needs_breakpoint = 1;
- }
- else
- {
- collecting_t ipa_collecting_obj;
- /* If `collecting' is set/locked, then the THREAD_AREA thread
- may or not be the one holding the lock. We have to read the
- lock to find out. */
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_collecting,
- &ipa_collecting))
- {
- trace_debug ("fast_tracepoint_collecting:"
- " failed reading 'collecting' in the inferior");
- return fast_tpoint_collect_result::not_collecting;
- }
- if (!ipa_collecting)
- {
- trace_debug ("fast_tracepoint_collecting: not collecting"
- " (and nobody is).");
- return fast_tpoint_collect_result::not_collecting;
- }
- /* Some thread is collecting. Check which. */
- if (read_inferior_memory (ipa_collecting,
- (unsigned char *) &ipa_collecting_obj,
- sizeof (ipa_collecting_obj)) != 0)
- goto again;
- if (ipa_collecting_obj.thread_area != thread_area)
- {
- trace_debug ("fast_tracepoint_collecting: not collecting "
- "(another thread is)");
- return fast_tpoint_collect_result::not_collecting;
- }
- tpoint
- = fast_tracepoint_from_ipa_tpoint_address (ipa_collecting_obj.tpoint);
- if (tpoint == NULL)
- {
- warning ("fast_tracepoint_collecting: collecting, "
- "but tpoint %s not found?",
- paddress ((CORE_ADDR) ipa_collecting_obj.tpoint));
- return fast_tpoint_collect_result::not_collecting;
- }
- /* The thread is within `gdb_collect', skip over the rest of
- fast tracepoint collection quickly using a breakpoint. */
- needs_breakpoint = 1;
- }
- /* The caller wants a bit of status detail. */
- if (status != NULL)
- {
- status->tpoint_num = tpoint->number;
- status->tpoint_addr = tpoint->address;
- status->adjusted_insn_addr = tpoint->adjusted_insn_addr;
- status->adjusted_insn_addr_end = tpoint->adjusted_insn_addr_end;
- }
- if (needs_breakpoint)
- {
- /* Hasn't executed the original instruction yet. Set breakpoint
- there, and wait till it's hit, then single-step until exiting
- the jump pad. */
- trace_debug ("\
- fast_tracepoint_collecting, returning continue-until-break at %s",
- paddress (tpoint->adjusted_insn_addr));
- return fast_tpoint_collect_result::before_insn; /* continue */
- }
- else
- {
- /* Just single-step until exiting the jump pad. */
- trace_debug ("fast_tracepoint_collecting, returning "
- "need-single-step (%s-%s)",
- paddress (tpoint->adjusted_insn_addr),
- paddress (tpoint->adjusted_insn_addr_end));
- return fast_tpoint_collect_result::at_insn; /* single-step */
- }
- }
- #endif
- #ifdef IN_PROCESS_AGENT
- /* The global fast tracepoint collect lock. Points to a collecting_t
- object built on the stack by the jump pad, if presently locked;
- NULL if it isn't locked. Note that this lock *must* be set while
- executing any *function other than the jump pad. See
- fast_tracepoint_collecting. */
- EXTERN_C_PUSH
- IP_AGENT_EXPORT_VAR collecting_t *collecting;
- EXTERN_C_POP
- /* This is needed for -Wmissing-declarations. */
- IP_AGENT_EXPORT_FUNC void gdb_collect (struct tracepoint *tpoint,
- unsigned char *regs);
- /* This routine, called from the jump pad (in asm) is designed to be
- called from the jump pads of fast tracepoints, thus it is on the
- critical path. */
- IP_AGENT_EXPORT_FUNC void
- gdb_collect (struct tracepoint *tpoint, unsigned char *regs)
- {
- struct fast_tracepoint_ctx ctx;
- const struct target_desc *ipa_tdesc;
- /* Don't do anything until the trace run is completely set up. */
- if (!tracing)
- return;
- ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx);
- ctx.base.type = fast_tracepoint;
- ctx.regs = regs;
- ctx.regcache_initted = 0;
- /* Wrap the regblock in a register cache (in the stack, we don't
- want to malloc here). */
- ctx.regspace = (unsigned char *) alloca (ipa_tdesc->registers_size);
- if (ctx.regspace == NULL)
- {
- trace_debug ("Trace buffer block allocation failed, skipping");
- return;
- }
- for (ctx.tpoint = tpoint;
- ctx.tpoint != NULL && ctx.tpoint->address == tpoint->address;
- ctx.tpoint = ctx.tpoint->next)
- {
- if (!ctx.tpoint->enabled)
- continue;
- /* Multiple tracepoints of different types, such as fast tracepoint and
- static tracepoint, can be set at the same address. */
- if (ctx.tpoint->type != tpoint->type)
- continue;
- /* Test the condition if present, and collect if true. */
- if (ctx.tpoint->cond == NULL
- || condition_true_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx,
- ctx.tpoint))
- {
- collect_data_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx,
- ctx.tpoint->address, ctx.tpoint);
- /* Note that this will cause original insns to be written back
- to where we jumped from, but that's OK because we're jumping
- back to the next whole instruction. This will go badly if
- instruction restoration is not atomic though. */
- if (stopping_tracepoint
- || trace_buffer_is_full
- || expr_eval_result != expr_eval_no_error)
- {
- stop_tracing ();
- break;
- }
- }
- else
- {
- /* If there was a condition and it evaluated to false, the only
- way we would stop tracing is if there was an error during
- condition expression evaluation. */
- if (expr_eval_result != expr_eval_no_error)
- {
- stop_tracing ();
- break;
- }
- }
- }
- }
- /* These global variables points to the corresponding functions. This is
- necessary on powerpc64, where asking for function symbol address from gdb
- results in returning the actual code pointer, instead of the descriptor
- pointer. */
- typedef void (*gdb_collect_ptr_type) (struct tracepoint *, unsigned char *);
- typedef ULONGEST (*get_raw_reg_ptr_type) (const unsigned char *, int);
- typedef LONGEST (*get_trace_state_variable_value_ptr_type) (int);
- typedef void (*set_trace_state_variable_value_ptr_type) (int, LONGEST);
- EXTERN_C_PUSH
- IP_AGENT_EXPORT_VAR gdb_collect_ptr_type gdb_collect_ptr = gdb_collect;
- IP_AGENT_EXPORT_VAR get_raw_reg_ptr_type get_raw_reg_ptr = get_raw_reg;
- IP_AGENT_EXPORT_VAR get_trace_state_variable_value_ptr_type
- get_trace_state_variable_value_ptr = get_trace_state_variable_value;
- IP_AGENT_EXPORT_VAR set_trace_state_variable_value_ptr_type
- set_trace_state_variable_value_ptr = set_trace_state_variable_value;
- EXTERN_C_POP
- #endif
- #ifndef IN_PROCESS_AGENT
- CORE_ADDR
- get_raw_reg_func_addr (void)
- {
- CORE_ADDR res;
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_get_raw_reg_ptr, &res))
- {
- error ("error extracting get_raw_reg_ptr");
- return 0;
- }
- return res;
- }
- CORE_ADDR
- get_get_tsv_func_addr (void)
- {
- CORE_ADDR res;
- if (read_inferior_data_pointer (
- ipa_sym_addrs.addr_get_trace_state_variable_value_ptr, &res))
- {
- error ("error extracting get_trace_state_variable_value_ptr");
- return 0;
- }
- return res;
- }
- CORE_ADDR
- get_set_tsv_func_addr (void)
- {
- CORE_ADDR res;
- if (read_inferior_data_pointer (
- ipa_sym_addrs.addr_set_trace_state_variable_value_ptr, &res))
- {
- error ("error extracting set_trace_state_variable_value_ptr");
- return 0;
- }
- return res;
- }
- static void
- compile_tracepoint_condition (struct tracepoint *tpoint,
- CORE_ADDR *jump_entry)
- {
- CORE_ADDR entry_point = *jump_entry;
- enum eval_result_type err;
- trace_debug ("Starting condition compilation for tracepoint %d\n",
- tpoint->number);
- /* Initialize the global pointer to the code being built. */
- current_insn_ptr = *jump_entry;
- emit_prologue ();
- err = compile_bytecodes (tpoint->cond);
- if (err == expr_eval_no_error)
- {
- emit_epilogue ();
- /* Record the beginning of the compiled code. */
- tpoint->compiled_cond = entry_point;
- trace_debug ("Condition compilation for tracepoint %d complete\n",
- tpoint->number);
- }
- else
- {
- /* Leave the unfinished code in situ, but don't point to it. */
- tpoint->compiled_cond = 0;
- trace_debug ("Condition compilation for tracepoint %d failed, "
- "error code %d",
- tpoint->number, err);
- }
- /* Update the code pointer passed in. Note that we do this even if
- the compile fails, so that we can look at the partial results
- instead of letting them be overwritten. */
- *jump_entry = current_insn_ptr;
- /* Leave a gap, to aid dump decipherment. */
- *jump_entry += 16;
- }
- /* The base pointer of the IPA's heap. This is the only memory the
- IPA is allowed to use. The IPA should _not_ call the inferior's
- `malloc' during operation. That'd be slow, and, most importantly,
- it may not be safe. We may be collecting a tracepoint in a signal
- handler, for example. */
- static CORE_ADDR target_tp_heap;
- /* Allocate at least SIZE bytes of memory from the IPA heap, aligned
- to 8 bytes. */
- static CORE_ADDR
- target_malloc (ULONGEST size)
- {
- CORE_ADDR ptr;
- if (target_tp_heap == 0)
- {
- /* We have the pointer *address*, need what it points to. */
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_tp_heap_buffer,
- &target_tp_heap))
- {
- internal_error (__FILE__, __LINE__,
- "couldn't get target heap head pointer");
- }
- }
- ptr = target_tp_heap;
- target_tp_heap += size;
- /* Pad to 8-byte alignment. */
- target_tp_heap = ((target_tp_heap + 7) & ~0x7);
- return ptr;
- }
- static CORE_ADDR
- download_agent_expr (struct agent_expr *expr)
- {
- CORE_ADDR expr_addr;
- CORE_ADDR expr_bytes;
- expr_addr = target_malloc (sizeof (*expr));
- target_write_memory (expr_addr, (unsigned char *) expr, sizeof (*expr));
- expr_bytes = target_malloc (expr->length);
- write_inferior_data_pointer (expr_addr + offsetof (struct agent_expr, bytes),
- expr_bytes);
- target_write_memory (expr_bytes, expr->bytes, expr->length);
- return expr_addr;
- }
- /* Align V up to N bits. */
- #define UALIGN(V, N) (((V) + ((N) - 1)) & ~((N) - 1))
- /* Sync tracepoint with IPA, but leave maintenance of linked list to caller. */
- static void
- download_tracepoint_1 (struct tracepoint *tpoint)
- {
- struct tracepoint target_tracepoint;
- CORE_ADDR tpptr = 0;
- gdb_assert (tpoint->type == fast_tracepoint
- || tpoint->type == static_tracepoint);
- if (tpoint->cond != NULL && target_emit_ops () != NULL)
- {
- CORE_ADDR jentry, jump_entry;
- jentry = jump_entry = get_jump_space_head ();
- if (tpoint->cond != NULL)
- {
- /* Pad to 8-byte alignment. (needed?) */
- /* Actually this should be left for the target to
- decide. */
- jentry = UALIGN (jentry, 8);
- compile_tracepoint_condition (tpoint, &jentry);
- }
- /* Pad to 8-byte alignment. */
- jentry = UALIGN (jentry, 8);
- claim_jump_space (jentry - jump_entry);
- }
- target_tracepoint = *tpoint;
- tpptr = target_malloc (sizeof (*tpoint));
- tpoint->obj_addr_on_target = tpptr;
- /* Write the whole object. We'll fix up its pointers in a bit.
- Assume no next for now. This is fixed up above on the next
- iteration, if there's any. */
- target_tracepoint.next = NULL;
- /* Need to clear this here too, since we're downloading the
- tracepoints before clearing our own copy. */
- target_tracepoint.hit_count = 0;
- target_write_memory (tpptr, (unsigned char *) &target_tracepoint,
- sizeof (target_tracepoint));
- if (tpoint->cond)
- write_inferior_data_pointer (tpptr
- + offsetof (struct tracepoint, cond),
- download_agent_expr (tpoint->cond));
- if (tpoint->numactions)
- {
- int i;
- CORE_ADDR actions_array;
- /* The pointers array. */
- actions_array
- = target_malloc (sizeof (*tpoint->actions) * tpoint->numactions);
- write_inferior_data_pointer (tpptr + offsetof (struct tracepoint,
- actions),
- actions_array);
- /* Now for each pointer, download the action. */
- for (i = 0; i < tpoint->numactions; i++)
- {
- struct tracepoint_action *action = tpoint->actions[i];
- CORE_ADDR ipa_action = tracepoint_action_download (action);
- if (ipa_action != 0)
- write_inferior_data_pointer (actions_array
- + i * sizeof (*tpoint->actions),
- ipa_action);
- }
- }
- }
- #define IPA_PROTO_FAST_TRACE_FLAG 0
- #define IPA_PROTO_FAST_TRACE_ADDR_ON_TARGET 2
- #define IPA_PROTO_FAST_TRACE_JUMP_PAD 10
- #define IPA_PROTO_FAST_TRACE_FJUMP_SIZE 18
- #define IPA_PROTO_FAST_TRACE_FJUMP_INSN 22
- /* Send a command to agent to download and install tracepoint TPOINT. */
- static int
- tracepoint_send_agent (struct tracepoint *tpoint)
- {
- char buf[IPA_CMD_BUF_SIZE];
- char *p;
- int i, ret;
- p = buf;
- strcpy (p, "FastTrace:");
- p += 10;
- COPY_FIELD_TO_BUF (p, tpoint, number);
- COPY_FIELD_TO_BUF (p, tpoint, address);
- COPY_FIELD_TO_BUF (p, tpoint, type);
- COPY_FIELD_TO_BUF (p, tpoint, enabled);
- COPY_FIELD_TO_BUF (p, tpoint, step_count);
- COPY_FIELD_TO_BUF (p, tpoint, pass_count);
- COPY_FIELD_TO_BUF (p, tpoint, numactions);
- COPY_FIELD_TO_BUF (p, tpoint, hit_count);
- COPY_FIELD_TO_BUF (p, tpoint, traceframe_usage);
- COPY_FIELD_TO_BUF (p, tpoint, compiled_cond);
- COPY_FIELD_TO_BUF (p, tpoint, orig_size);
- /* condition */
- p = agent_expr_send (p, tpoint->cond);
- /* tracepoint_action */
- for (i = 0; i < tpoint->numactions; i++)
- {
- struct tracepoint_action *action = tpoint->actions[i];
- p[0] = action->type;
- p = tracepoint_action_send (&p[1], action);
- }
- get_jump_space_head ();
- /* Copy the value of GDB_JUMP_PAD_HEAD to command buffer, so that
- agent can use jump pad from it. */
- if (tpoint->type == fast_tracepoint)
- {
- memcpy (p, &gdb_jump_pad_head, 8);
- p += 8;
- }
- ret = run_inferior_command (buf, (int) (ptrdiff_t) (p - buf));
- if (ret)
- return ret;
- if (!startswith (buf, "OK"))
- return 1;
- /* The value of tracepoint's target address is stored in BUF. */
- memcpy (&tpoint->obj_addr_on_target,
- &buf[IPA_PROTO_FAST_TRACE_ADDR_ON_TARGET], 8);
- if (tpoint->type == fast_tracepoint)
- {
- unsigned char *insn
- = (unsigned char *) &buf[IPA_PROTO_FAST_TRACE_FJUMP_INSN];
- int fjump_size;
- trace_debug ("agent: read from cmd_buf 0x%x 0x%x\n",
- (unsigned int) tpoint->obj_addr_on_target,
- (unsigned int) gdb_jump_pad_head);
- memcpy (&gdb_jump_pad_head, &buf[IPA_PROTO_FAST_TRACE_JUMP_PAD], 8);
- /* This has been done in agent. We should also set up record for it. */
- memcpy (&fjump_size, &buf[IPA_PROTO_FAST_TRACE_FJUMP_SIZE], 4);
- /* Wire it in. */
- tpoint->handle
- = set_fast_tracepoint_jump (tpoint->address, insn, fjump_size);
- }
- return 0;
- }
- static void
- download_tracepoint (struct tracepoint *tpoint)
- {
- struct tracepoint *tp, *tp_prev;
- if (tpoint->type != fast_tracepoint
- && tpoint->type != static_tracepoint)
- return;
- download_tracepoint_1 (tpoint);
- /* Find the previous entry of TPOINT, which is fast tracepoint or
- static tracepoint. */
- tp_prev = NULL;
- for (tp = tracepoints; tp != tpoint; tp = tp->next)
- {
- if (tp->type == fast_tracepoint || tp->type == static_tracepoint)
- tp_prev = tp;
- }
- if (tp_prev)
- {
- CORE_ADDR tp_prev_target_next_addr;
- /* Insert TPOINT after TP_PREV in IPA. */
- if (read_inferior_data_pointer (tp_prev->obj_addr_on_target
- + offsetof (struct tracepoint, next),
- &tp_prev_target_next_addr))
- {
- internal_error (__FILE__, __LINE__,
- "error reading `tp_prev->next'");
- }
- /* tpoint->next = tp_prev->next */
- write_inferior_data_pointer (tpoint->obj_addr_on_target
- + offsetof (struct tracepoint, next),
- tp_prev_target_next_addr);
- /* tp_prev->next = tpoint */
- write_inferior_data_pointer (tp_prev->obj_addr_on_target
- + offsetof (struct tracepoint, next),
- tpoint->obj_addr_on_target);
- }
- else
- /* First object in list, set the head pointer in the
- inferior. */
- write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints,
- tpoint->obj_addr_on_target);
- }
- static void
- download_trace_state_variables (void)
- {
- CORE_ADDR ptr = 0, prev_ptr = 0;
- struct trace_state_variable *tsv;
- /* Start out empty. */
- write_inferior_data_pointer (ipa_sym_addrs.addr_trace_state_variables, 0);
- for (tsv = trace_state_variables; tsv != NULL; tsv = tsv->next)
- {
- struct trace_state_variable target_tsv;
- /* TSV's with a getter have been initialized equally in both the
- inferior and GDBserver. Skip them. */
- if (tsv->getter != NULL)
- continue;
- target_tsv = *tsv;
- prev_ptr = ptr;
- ptr = target_malloc (sizeof (*tsv));
- if (tsv == trace_state_variables)
- {
- /* First object in list, set the head pointer in the
- inferior. */
- write_inferior_data_pointer (ipa_sym_addrs.addr_trace_state_variables,
- ptr);
- }
- else
- {
- write_inferior_data_pointer (prev_ptr
- + offsetof (struct trace_state_variable,
- next),
- ptr);
- }
- /* Write the whole object. We'll fix up its pointers in a bit.
- Assume no next, fixup when needed. */
- target_tsv.next = NULL;
- target_write_memory (ptr, (unsigned char *) &target_tsv,
- sizeof (target_tsv));
- if (tsv->name != NULL)
- {
- size_t size = strlen (tsv->name) + 1;
- CORE_ADDR name_addr = target_malloc (size);
- target_write_memory (name_addr,
- (unsigned char *) tsv->name, size);
- write_inferior_data_pointer (ptr
- + offsetof (struct trace_state_variable,
- name),
- name_addr);
- }
- gdb_assert (tsv->getter == NULL);
- }
- if (prev_ptr != 0)
- {
- /* Fixup the next pointer in the last item in the list. */
- write_inferior_data_pointer (prev_ptr
- + offsetof (struct trace_state_variable,
- next), 0);
- }
- }
- /* Upload complete trace frames out of the IP Agent's trace buffer
- into GDBserver's trace buffer. This always uploads either all or
- no trace frames. This is the counter part of
- `trace_alloc_trace_buffer'. See its description of the atomic
- syncing mechanism. */
- static void
- upload_fast_traceframes (void)
- {
- unsigned int ipa_traceframe_read_count, ipa_traceframe_write_count;
- unsigned int ipa_traceframe_read_count_racy, ipa_traceframe_write_count_racy;
- CORE_ADDR tf;
- struct ipa_trace_buffer_control ipa_trace_buffer_ctrl;
- unsigned int curr_tbctrl_idx;
- unsigned int ipa_trace_buffer_ctrl_curr;
- unsigned int ipa_trace_buffer_ctrl_curr_old;
- CORE_ADDR ipa_trace_buffer_ctrl_addr;
- struct breakpoint *about_to_request_buffer_space_bkpt;
- CORE_ADDR ipa_trace_buffer_lo;
- CORE_ADDR ipa_trace_buffer_hi;
- if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count,
- &ipa_traceframe_read_count_racy))
- {
- /* This will happen in most targets if the current thread is
- running. */
- return;
- }
- if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count,
- &ipa_traceframe_write_count_racy))
- return;
- trace_debug ("ipa_traceframe_count (racy area): %d (w=%d, r=%d)",
- ipa_traceframe_write_count_racy
- - ipa_traceframe_read_count_racy,
- ipa_traceframe_write_count_racy,
- ipa_traceframe_read_count_racy);
- if (ipa_traceframe_write_count_racy == ipa_traceframe_read_count_racy)
- return;
- about_to_request_buffer_space_bkpt
- = set_breakpoint_at (ipa_sym_addrs.addr_about_to_request_buffer_space,
- NULL);
- if (read_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr,
- &ipa_trace_buffer_ctrl_curr))
- return;
- ipa_trace_buffer_ctrl_curr_old = ipa_trace_buffer_ctrl_curr;
- curr_tbctrl_idx = ipa_trace_buffer_ctrl_curr & ~GDBSERVER_FLUSH_COUNT_MASK;
- {
- unsigned int prev, counter;
- /* Update the token, with new counters, and the GDBserver stamp
- bit. Alway reuse the current TBC index. */
- prev = ipa_trace_buffer_ctrl_curr & GDBSERVER_FLUSH_COUNT_MASK_CURR;
- counter = (prev + 0x100) & GDBSERVER_FLUSH_COUNT_MASK_CURR;
- ipa_trace_buffer_ctrl_curr = (GDBSERVER_UPDATED_FLUSH_COUNT_BIT
- | (prev << 12)
- | counter
- | curr_tbctrl_idx);
- }
- if (write_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr,
- ipa_trace_buffer_ctrl_curr))
- return;
- trace_debug ("Lib: Committed %08x -> %08x",
- ipa_trace_buffer_ctrl_curr_old,
- ipa_trace_buffer_ctrl_curr);
- /* Re-read these, now that we've installed the
- `about_to_request_buffer_space' breakpoint/lock. A thread could
- have finished a traceframe between the last read of these
- counters and setting the breakpoint above. If we start
- uploading, we never want to leave this function with
- traceframe_read_count != 0, otherwise, GDBserver could end up
- incrementing the counter tokens more than once (due to event loop
- nesting), which would break the IP agent's "effective" detection
- (see trace_alloc_trace_buffer). */
- if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count,
- &ipa_traceframe_read_count))
- return;
- if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count,
- &ipa_traceframe_write_count))
- return;
- if (debug_threads)
- {
- trace_debug ("ipa_traceframe_count (blocked area): %d (w=%d, r=%d)",
- ipa_traceframe_write_count - ipa_traceframe_read_count,
- ipa_traceframe_write_count, ipa_traceframe_read_count);
- if (ipa_traceframe_write_count != ipa_traceframe_write_count_racy
- || ipa_traceframe_read_count != ipa_traceframe_read_count_racy)
- trace_debug ("note that ipa_traceframe_count's parts changed");
- }
- /* Get the address of the current TBC object (the IP agent has an
- array of 3 such objects). The index is stored in the TBC
- token. */
- ipa_trace_buffer_ctrl_addr = ipa_sym_addrs.addr_trace_buffer_ctrl;
- ipa_trace_buffer_ctrl_addr
- += sizeof (struct ipa_trace_buffer_control) * curr_tbctrl_idx;
- if (read_inferior_memory (ipa_trace_buffer_ctrl_addr,
- (unsigned char *) &ipa_trace_buffer_ctrl,
- sizeof (struct ipa_trace_buffer_control)))
- return;
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_lo,
- &ipa_trace_buffer_lo))
- return;
- if (read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_hi,
- &ipa_trace_buffer_hi))
- return;
- /* Offsets are easier to grok for debugging than raw addresses,
- especially for the small trace buffer sizes that are useful for
- testing. */
- trace_debug ("Lib: Trace buffer [%d] start=%d free=%d "
- "endfree=%d wrap=%d hi=%d",
- curr_tbctrl_idx,
- (int) (ipa_trace_buffer_ctrl.start - ipa_trace_buffer_lo),
- (int) (ipa_trace_buffer_ctrl.free - ipa_trace_buffer_lo),
- (int) (ipa_trace_buffer_ctrl.end_free - ipa_trace_buffer_lo),
- (int) (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo),
- (int) (ipa_trace_buffer_hi - ipa_trace_buffer_lo));
- /* Note that the IPA's buffer is always circular. */
- #define IPA_FIRST_TRACEFRAME() (ipa_trace_buffer_ctrl.start)
- #define IPA_NEXT_TRACEFRAME_1(TF, TFOBJ) \
- ((TF) + sizeof (struct traceframe) + (TFOBJ)->data_size)
- #define IPA_NEXT_TRACEFRAME(TF, TFOBJ) \
- (IPA_NEXT_TRACEFRAME_1 (TF, TFOBJ) \
- - ((IPA_NEXT_TRACEFRAME_1 (TF, TFOBJ) >= ipa_trace_buffer_ctrl.wrap) \
- ? (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo) \
- : 0))
- tf = IPA_FIRST_TRACEFRAME ();
- while (ipa_traceframe_write_count - ipa_traceframe_read_count)
- {
- struct tracepoint *tpoint;
- struct traceframe *tframe;
- unsigned char *block;
- struct traceframe ipa_tframe;
- if (read_inferior_memory (tf, (unsigned char *) &ipa_tframe,
- offsetof (struct traceframe, data)))
- error ("Uploading: couldn't read traceframe at %s\n", paddress (tf));
- if (ipa_tframe.tpnum == 0)
- {
- internal_error (__FILE__, __LINE__,
- "Uploading: No (more) fast traceframes, but"
- " ipa_traceframe_count == %u??\n",
- ipa_traceframe_write_count
- - ipa_traceframe_read_count);
- }
- /* Note that this will be incorrect for multi-location
- tracepoints... */
- tpoint = find_next_tracepoint_by_number (NULL, ipa_tframe.tpnum);
- tframe = add_traceframe (tpoint);
- if (tframe == NULL)
- {
- trace_buffer_is_full = 1;
- trace_debug ("Uploading: trace buffer is full");
- }
- else
- {
- /* Copy the whole set of blocks in one go for now. FIXME:
- split this in smaller blocks. */
- block = add_traceframe_block (tframe, tpoint,
- ipa_tframe.data_size);
- if (block != NULL)
- {
- if (read_inferior_memory (tf
- + offsetof (struct traceframe, data),
- block, ipa_tframe.data_size))
- error ("Uploading: Couldn't read traceframe data at %s\n",
- paddress (tf + offsetof (struct traceframe, data)));
- }
- trace_debug ("Uploading: traceframe didn't fit");
- finish_traceframe (tframe);
- }
- tf = IPA_NEXT_TRACEFRAME (tf, &ipa_tframe);
- /* If we freed the traceframe that wrapped around, go back
- to the non-wrap case. */
- if (tf < ipa_trace_buffer_ctrl.start)
- {
- trace_debug ("Lib: Discarding past the wraparound");
- ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi;
- }
- ipa_trace_buffer_ctrl.start = tf;
- ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_ctrl.start;
- ++ipa_traceframe_read_count;
- if (ipa_trace_buffer_ctrl.start == ipa_trace_buffer_ctrl.free
- && ipa_trace_buffer_ctrl.start == ipa_trace_buffer_ctrl.end_free)
- {
- trace_debug ("Lib: buffer is fully empty. "
- "Trace buffer [%d] start=%d free=%d endfree=%d",
- curr_tbctrl_idx,
- (int) (ipa_trace_buffer_ctrl.start
- - ipa_trace_buffer_lo),
- (int) (ipa_trace_buffer_ctrl.free
- - ipa_trace_buffer_lo),
- (int) (ipa_trace_buffer_ctrl.end_free
- - ipa_trace_buffer_lo));
- ipa_trace_buffer_ctrl.start = ipa_trace_buffer_lo;
- ipa_trace_buffer_ctrl.free = ipa_trace_buffer_lo;
- ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_hi;
- ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi;
- }
- trace_debug ("Uploaded a traceframe\n"
- "Lib: Trace buffer [%d] start=%d free=%d "
- "endfree=%d wrap=%d hi=%d",
- curr_tbctrl_idx,
- (int) (ipa_trace_buffer_ctrl.start - ipa_trace_buffer_lo),
- (int) (ipa_trace_buffer_ctrl.free - ipa_trace_buffer_lo),
- (int) (ipa_trace_buffer_ctrl.end_free
- - ipa_trace_buffer_lo),
- (int) (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo),
- (int) (ipa_trace_buffer_hi - ipa_trace_buffer_lo));
- }
- if (target_write_memory (ipa_trace_buffer_ctrl_addr,
- (unsigned char *) &ipa_trace_buffer_ctrl,
- sizeof (struct ipa_trace_buffer_control)))
- return;
- write_inferior_integer (ipa_sym_addrs.addr_traceframe_read_count,
- ipa_traceframe_read_count);
- trace_debug ("Done uploading traceframes [%d]\n", curr_tbctrl_idx);
- target_pause_all (true);
- delete_breakpoint (about_to_request_buffer_space_bkpt);
- about_to_request_buffer_space_bkpt = NULL;
- target_unpause_all (true);
- if (trace_buffer_is_full)
- stop_tracing ();
- }
- #endif
- #ifdef IN_PROCESS_AGENT
- IP_AGENT_EXPORT_VAR int ust_loaded;
- IP_AGENT_EXPORT_VAR char cmd_buf[IPA_CMD_BUF_SIZE];
- #ifdef HAVE_UST
- /* Static tracepoints. */
- /* UST puts a "struct tracepoint" in the global namespace, which
- conflicts with our tracepoint. Arguably, being a library, it
- shouldn't take ownership of such a generic name. We work around it
- here. */
- #define tracepoint ust_tracepoint
- #include <ust/ust.h>
- #undef tracepoint
- extern int serialize_to_text (char *outbuf, int bufsize,
- const char *fmt, va_list ap);
- #define GDB_PROBE_NAME "gdb"
- /* We dynamically search for the UST symbols instead of linking them
- in. This lets the user decide if the application uses static
- tracepoints, instead of always pulling libust.so in. This vector
- holds pointers to all functions we care about. */
- static struct
- {
- int (*serialize_to_text) (char *outbuf, int bufsize,
- const char *fmt, va_list ap);
- int (*ltt_probe_register) (struct ltt_available_probe *pdata);
- int (*ltt_probe_unregister) (struct ltt_available_probe *pdata);
- int (*ltt_marker_connect) (const char *channel, const char *mname,
- const char *pname);
- int (*ltt_marker_disconnect) (const char *channel, const char *mname,
- const char *pname);
- void (*marker_iter_start) (struct marker_iter *iter);
- void (*marker_iter_next) (struct marker_iter *iter);
- void (*marker_iter_stop) (struct marker_iter *iter);
- void (*marker_iter_reset) (struct marker_iter *iter);
- } ust_ops;
- #include <dlfcn.h>
- /* Cast through typeof to catch incompatible API changes. Since UST
- only builds with gcc, we can freely use gcc extensions here
- too. */
- #define GET_UST_SYM(SYM) \
- do \
- { \
- if (ust_ops.SYM == NULL) \
- ust_ops.SYM = (typeof (&SYM)) dlsym (RTLD_DEFAULT, #SYM); \
- if (ust_ops.SYM == NULL) \
- return 0; \
- } while (0)
- #define USTF(SYM) ust_ops.SYM
- /* Get pointers to all libust.so functions we care about. */
- static int
- dlsym_ust (void)
- {
- GET_UST_SYM (serialize_to_text);
- GET_UST_SYM (ltt_probe_register);
- GET_UST_SYM (ltt_probe_unregister);
- GET_UST_SYM (ltt_marker_connect);
- GET_UST_SYM (ltt_marker_disconnect);
- GET_UST_SYM (marker_iter_start);
- GET_UST_SYM (marker_iter_next);
- GET_UST_SYM (marker_iter_stop);
- GET_UST_SYM (marker_iter_reset);
- ust_loaded = 1;
- return 1;
- }
- /* Given an UST marker, return the matching gdb static tracepoint.
- The match is done by address. */
- static struct tracepoint *
- ust_marker_to_static_tracepoint (const struct marker *mdata)
- {
- struct tracepoint *tpoint;
- for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
- {
- if (tpoint->type != static_tracepoint)
- continue;
- if (tpoint->address == (uintptr_t) mdata->location)
- return tpoint;
- }
- return NULL;
- }
- /* The probe function we install on lttng/ust markers. Whenever a
- probed ust marker is hit, this function is called. This is similar
- to gdb_collect, only for static tracepoints, instead of fast
- tracepoints. */
- static void
- gdb_probe (const struct marker *mdata, void *probe_private,
- struct registers *regs, void *call_private,
- const char *fmt, va_list *args)
- {
- struct tracepoint *tpoint;
- struct static_tracepoint_ctx ctx;
- const struct target_desc *ipa_tdesc;
- /* Don't do anything until the trace run is completely set up. */
- if (!tracing)
- {
- trace_debug ("gdb_probe: not tracing\n");
- return;
- }
- ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx);
- ctx.base.type = static_tracepoint;
- ctx.regcache_initted = 0;
- ctx.regs = regs;
- ctx.fmt = fmt;
- ctx.args = args;
- /* Wrap the regblock in a register cache (in the stack, we don't
- want to malloc here). */
- ctx.regspace = alloca (ipa_tdesc->registers_size);
- if (ctx.regspace == NULL)
- {
- trace_debug ("Trace buffer block allocation failed, skipping");
- return;
- }
- tpoint = ust_marker_to_static_tracepoint (mdata);
- if (tpoint == NULL)
- {
- trace_debug ("gdb_probe: marker not known: "
- "loc:0x%p, ch:\"%s\",n:\"%s\",f:\"%s\"",
- mdata->location, mdata->channel,
- mdata->name, mdata->format);
- return;
- }
- if (!tpoint->enabled)
- {
- trace_debug ("gdb_probe: tracepoint disabled");
- return;
- }
- ctx.tpoint = tpoint;
- trace_debug ("gdb_probe: collecting marker: "
- "loc:0x%p, ch:\"%s\",n:\"%s\",f:\"%s\"",
- mdata->location, mdata->channel,
- mdata->name, mdata->format);
- /* Test the condition if present, and collect if true. */
- if (tpoint->cond == NULL
- || condition_true_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx,
- tpoint))
- {
- collect_data_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx,
- tpoint->address, tpoint);
- if (stopping_tracepoint
- || trace_buffer_is_full
- || expr_eval_result != expr_eval_no_error)
- stop_tracing ();
- }
- else
- {
- /* If there was a condition and it evaluated to false, the only
- way we would stop tracing is if there was an error during
- condition expression evaluation. */
- if (expr_eval_result != expr_eval_no_error)
- stop_tracing ();
- }
- }
- /* Called if the gdb static tracepoint requested collecting "$_sdata",
- static tracepoint string data. This is a string passed to the
- tracing library by the user, at the time of the tracepoint marker
- call. E.g., in the UST marker call:
- trace_mark (ust, bar33, "str %s", "FOOBAZ");
- the collected data is "str FOOBAZ".
- */
- static void
- collect_ust_data_at_tracepoint (struct tracepoint_hit_ctx *ctx,
- struct traceframe *tframe)
- {
- struct static_tracepoint_ctx *umd = (struct static_tracepoint_ctx *) ctx;
- unsigned char *bufspace;
- int size;
- va_list copy;
- unsigned short blocklen;
- if (umd == NULL)
- {
- trace_debug ("Wanted to collect static trace data, "
- "but there's no static trace data");
- return;
- }
- va_copy (copy, *umd->args);
- size = USTF(serialize_to_text) (NULL, 0, umd->fmt, copy);
- va_end (copy);
- trace_debug ("Want to collect ust data");
- /* 'S' + size + string */
- bufspace = add_traceframe_block (tframe, umd->tpoint,
- 1 + sizeof (blocklen) + size + 1);
- if (bufspace == NULL)
- {
- trace_debug ("Trace buffer block allocation failed, skipping");
- return;
- }
- /* Identify a static trace data block. */
- *bufspace = 'S';
- blocklen = size + 1;
- memcpy (bufspace + 1, &blocklen, sizeof (blocklen));
- va_copy (copy, *umd->args);
- USTF(serialize_to_text) ((char *) bufspace + 1 + sizeof (blocklen),
- size + 1, umd->fmt, copy);
- va_end (copy);
- trace_debug ("Storing static tracepoint data in regblock: %s",
- bufspace + 1 + sizeof (blocklen));
- }
- /* The probe to register with lttng/ust. */
- static struct ltt_available_probe gdb_ust_probe =
- {
- GDB_PROBE_NAME,
- NULL,
- gdb_probe,
- };
- #endif /* HAVE_UST */
- #endif /* IN_PROCESS_AGENT */
- #ifndef IN_PROCESS_AGENT
- /* Ask the in-process agent to run a command. Since we don't want to
- have to handle the IPA hitting breakpoints while running the
- command, we pause all threads, remove all breakpoints, and then set
- the helper thread re-running. We communicate with the helper
- thread by means of direct memory xfering, and a socket for
- synchronization. */
- static int
- run_inferior_command (char *cmd, int len)
- {
- int err = -1;
- int pid = current_ptid.pid ();
- trace_debug ("run_inferior_command: running: %s", cmd);
- target_pause_all (false);
- uninsert_all_breakpoints ();
- err = agent_run_command (pid, (const char *) cmd, len);
- reinsert_all_breakpoints ();
- target_unpause_all (false);
- return err;
- }
- #else /* !IN_PROCESS_AGENT */
- #include <sys/socket.h>
- #include <sys/un.h>
- #ifndef UNIX_PATH_MAX
- #define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path)
- #endif
- /* Where we put the socked used for synchronization. */
- #define SOCK_DIR P_tmpdir
- /* Thread ID of the helper thread. GDBserver reads this to know which
- is the help thread. This is an LWP id on Linux. */
- EXTERN_C_PUSH
- IP_AGENT_EXPORT_VAR int helper_thread_id;
- EXTERN_C_POP
- static int
- init_named_socket (const char *name)
- {
- int result, fd;
- struct sockaddr_un addr;
- result = fd = socket (PF_UNIX, SOCK_STREAM, 0);
- if (result == -1)
- {
- warning ("socket creation failed: %s", safe_strerror (errno));
- return -1;
- }
- addr.sun_family = AF_UNIX;
- if (strlen (name) >= ARRAY_SIZE (addr.sun_path))
- {
- warning ("socket name too long for sockaddr_un::sun_path field: %s", name);
- return -1;
- }
- strcpy (addr.sun_path, name);
- result = access (name, F_OK);
- if (result == 0)
- {
- /* File exists. */
- result = unlink (name);
- if (result == -1)
- {
- warning ("unlink failed: %s", safe_strerror (errno));
- close (fd);
- return -1;
- }
- warning ("socket %s already exists; overwriting", name);
- }
- result = bind (fd, (struct sockaddr *) &addr, sizeof (addr));
- if (result == -1)
- {
- warning ("bind failed: %s", safe_strerror (errno));
- close (fd);
- return -1;
- }
- result = listen (fd, 1);
- if (result == -1)
- {
- warning ("listen: %s", safe_strerror (errno));
- close (fd);
- return -1;
- }
- return fd;
- }
- static char agent_socket_name[UNIX_PATH_MAX];
- static int
- gdb_agent_socket_init (void)
- {
- int result, fd;
- result = snprintf (agent_socket_name, UNIX_PATH_MAX, "%s/gdb_ust%d",
- SOCK_DIR, getpid ());
- if (result >= UNIX_PATH_MAX)
- {
- trace_debug ("string overflow allocating socket name");
- return -1;
- }
- fd = init_named_socket (agent_socket_name);
- if (fd < 0)
- warning ("Error initializing named socket (%s) for communication with the "
- "ust helper thread. Check that directory exists and that it "
- "is writable.", agent_socket_name);
- return fd;
- }
- #ifdef HAVE_UST
- /* The next marker to be returned on a qTsSTM command. */
- static const struct marker *next_st;
- /* Returns the first known marker. */
- struct marker *
- first_marker (void)
- {
- struct marker_iter iter;
- USTF(marker_iter_reset) (&iter);
- USTF(marker_iter_start) (&iter);
- return iter.marker;
- }
- /* Returns the marker following M. */
- const struct marker *
- next_marker (const struct marker *m)
- {
- struct marker_iter iter;
- USTF(marker_iter_reset) (&iter);
- USTF(marker_iter_start) (&iter);
- for (; iter.marker != NULL; USTF(marker_iter_next) (&iter))
- {
- if (iter.marker == m)
- {
- USTF(marker_iter_next) (&iter);
- return iter.marker;
- }
- }
- return NULL;
- }
- /* Return an hexstr version of the STR C string, fit for sending to
- GDB. */
- static char *
- cstr_to_hexstr (const char *str)
- {
- int len = strlen (str);
- char *hexstr = xmalloc (len * 2 + 1);
- bin2hex ((gdb_byte *) str, hexstr, len);
- return hexstr;
- }
- /* Compose packet that is the response to the qTsSTM/qTfSTM/qTSTMat
- packets. */
- static void
- response_ust_marker (char *packet, const struct marker *st)
- {
- char *strid, *format, *tmp;
- next_st = next_marker (st);
- tmp = xmalloc (strlen (st->channel) + 1 +
- strlen (st->name) + 1);
- sprintf (tmp, "%s/%s", st->channel, st->name);
- strid = cstr_to_hexstr (tmp);
- free (tmp);
- format = cstr_to_hexstr (st->format);
- sprintf (packet, "m%s:%s:%s",
- paddress ((uintptr_t) st->location),
- strid,
- format);
- free (strid);
- free (format);
- }
- /* Return the first static tracepoint, and initialize the state
- machine that will iterate through all the static tracepoints. */
- static void
- cmd_qtfstm (char *packet)
- {
- trace_debug ("Returning first trace state variable definition");
- if (first_marker ())
- response_ust_marker (packet, first_marker ());
- else
- strcpy (packet, "l");
- }
- /* Return additional trace state variable definitions. */
- static void
- cmd_qtsstm (char *packet)
- {
- trace_debug ("Returning static tracepoint");
- if (next_st)
- response_ust_marker (packet, next_st);
- else
- strcpy (packet, "l");
- }
- /* Disconnect the GDB probe from a marker at a given address. */
- static void
- unprobe_marker_at (char *packet)
- {
- char *p = packet;
- ULONGEST address;
- struct marker_iter iter;
- p += sizeof ("unprobe_marker_at:") - 1;
- p = unpack_varlen_hex (p, &address);
- USTF(marker_iter_reset) (&iter);
- USTF(marker_iter_start) (&iter);
- for (; iter.marker != NULL; USTF(marker_iter_next) (&iter))
- if ((uintptr_t ) iter.marker->location == address)
- {
- int result;
- result = USTF(ltt_marker_disconnect) (iter.marker->channel,
- iter.marker->name,
- GDB_PROBE_NAME);
- if (result < 0)
- warning ("could not disable marker %s/%s",
- iter.marker->channel, iter.marker->name);
- break;
- }
- }
- /* Connect the GDB probe to a marker at a given address. */
- static int
- probe_marker_at (char *packet)
- {
- char *p = packet;
- ULONGEST address;
- struct marker_iter iter;
- struct marker *m;
- p += sizeof ("probe_marker_at:") - 1;
- p = unpack_varlen_hex (p, &address);
- USTF(marker_iter_reset) (&iter);
- for (USTF(marker_iter_start) (&iter), m = iter.marker;
- m != NULL;
- USTF(marker_iter_next) (&iter), m = iter.marker)
- if ((uintptr_t ) m->location == address)
- {
- int result;
- trace_debug ("found marker for address. "
- "ltt_marker_connect (marker = %s/%s)",
- m->channel, m->name);
- result = USTF(ltt_marker_connect) (m->channel, m->name,
- GDB_PROBE_NAME);
- if (result && result != -EEXIST)
- trace_debug ("ltt_marker_connect (marker = %s/%s, errno = %d)",
- m->channel, m->name, -result);
- if (result < 0)
- {
- sprintf (packet, "E.could not connect marker: channel=%s, name=%s",
- m->channel, m->name);
- return -1;
- }
- strcpy (packet, "OK");
- return 0;
- }
- sprintf (packet, "E.no marker found at 0x%s", paddress (address));
- return -1;
- }
- static int
- cmd_qtstmat (char *packet)
- {
- char *p = packet;
- ULONGEST address;
- struct marker_iter iter;
- struct marker *m;
- p += sizeof ("qTSTMat:") - 1;
- p = unpack_varlen_hex (p, &address);
- USTF(marker_iter_reset) (&iter);
- for (USTF(marker_iter_start) (&iter), m = iter.marker;
- m != NULL;
- USTF(marker_iter_next) (&iter), m = iter.marker)
- if ((uintptr_t ) m->location == address)
- {
- response_ust_marker (packet, m);
- return 0;
- }
- strcpy (packet, "l");
- return -1;
- }
- static void
- gdb_ust_init (void)
- {
- if (!dlsym_ust ())
- return;
- USTF(ltt_probe_register) (&gdb_ust_probe);
- }
- #endif /* HAVE_UST */
- #include <sys/syscall.h>
- static void
- gdb_agent_remove_socket (void)
- {
- unlink (agent_socket_name);
- }
- /* Helper thread of agent. */
- static void *
- gdb_agent_helper_thread (void *arg)
- {
- int listen_fd;
- atexit (gdb_agent_remove_socket);
- while (1)
- {
- listen_fd = gdb_agent_socket_init ();
- if (helper_thread_id == 0)
- helper_thread_id = syscall (SYS_gettid);
- if (listen_fd == -1)
- {
- warning ("could not create sync socket");
- break;
- }
- while (1)
- {
- socklen_t tmp;
- struct sockaddr_un sockaddr;
- int fd;
- char buf[1];
- int ret;
- int stop_loop = 0;
- tmp = sizeof (sockaddr);
- do
- {
- fd = accept (listen_fd, (struct sockaddr *) &sockaddr, &tmp);
- }
- /* It seems an ERESTARTSYS can escape out of accept. */
- while (fd == -512 || (fd == -1 && errno == EINTR));
- if (fd < 0)
- {
- warning ("Accept returned %d, error: %s",
- fd, safe_strerror (errno));
- break;
- }
- do
- {
- ret = read (fd, buf, 1);
- } while (ret == -1 && errno == EINTR);
- if (ret == -1)
- {
- warning ("reading socket (fd=%d) failed with %s",
- fd, safe_strerror (errno));
- close (fd);
- break;
- }
- if (cmd_buf[0])
- {
- if (startswith (cmd_buf, "close"))
- {
- stop_loop = 1;
- }
- #ifdef HAVE_UST
- else if (strcmp ("qTfSTM", cmd_buf) == 0)
- {
- cmd_qtfstm (cmd_buf);
- }
- else if (strcmp ("qTsSTM", cmd_buf) == 0)
- {
- cmd_qtsstm (cmd_buf);
- }
- else if (startswith (cmd_buf, "unprobe_marker_at:"))
- {
- unprobe_marker_at (cmd_buf);
- }
- else if (startswith (cmd_buf, "probe_marker_at:"))
- {
- probe_marker_at (cmd_buf);
- }
- else if (startswith (cmd_buf, "qTSTMat:"))
- {
- cmd_qtstmat (cmd_buf);
- }
- #endif /* HAVE_UST */
- }
- /* Fix compiler's warning: ignoring return value of 'write'. */
- ret = write (fd, buf, 1);
- close (fd);
- if (stop_loop)
- {
- close (listen_fd);
- unlink (agent_socket_name);
- /* Sleep endlessly to wait the whole inferior stops. This
- thread can not exit because GDB or GDBserver may still need
- 'current_thread' (representing this thread) to access
- inferior memory. Otherwise, this thread exits earlier than
- other threads, and 'current_thread' is set to NULL. */
- while (1)
- sleep (10);
- }
- }
- }
- return NULL;
- }
- #include <signal.h>
- #include <pthread.h>
- EXTERN_C_PUSH
- IP_AGENT_EXPORT_VAR int gdb_agent_capability = AGENT_CAPA_STATIC_TRACE;
- EXTERN_C_POP
- static void
- gdb_agent_init (void)
- {
- int res;
- pthread_t thread;
- sigset_t new_mask;
- sigset_t orig_mask;
- /* We want the helper thread to be as transparent as possible, so
- have it inherit an all-signals-blocked mask. */
- sigfillset (&new_mask);
- res = pthread_sigmask (SIG_SETMASK, &new_mask, &orig_mask);
- if (res)
- perror_with_name ("pthread_sigmask (1)");
- res = pthread_create (&thread,
- NULL,
- gdb_agent_helper_thread,
- NULL);
- res = pthread_sigmask (SIG_SETMASK, &orig_mask, NULL);
- if (res)
- perror_with_name ("pthread_sigmask (2)");
- while (helper_thread_id == 0)
- usleep (1);
- #ifdef HAVE_UST
- gdb_ust_init ();
- #endif
- }
- #include <sys/mman.h>
- IP_AGENT_EXPORT_VAR char *gdb_tp_heap_buffer;
- IP_AGENT_EXPORT_VAR char *gdb_jump_pad_buffer;
- IP_AGENT_EXPORT_VAR char *gdb_jump_pad_buffer_end;
- IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer;
- IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer_end;
- IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer_error;
- /* Record the result of getting buffer space for fast tracepoint
- trampolines. Any error message is copied, since caller may not be
- using persistent storage. */
- void
- set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end, char *errmsg)
- {
- gdb_trampoline_buffer = (char *) (uintptr_t) begin;
- gdb_trampoline_buffer_end = (char *) (uintptr_t) end;
- if (errmsg)
- strncpy (gdb_trampoline_buffer_error, errmsg, 99);
- else
- strcpy (gdb_trampoline_buffer_error, "no buffer passed");
- }
- static void __attribute__ ((constructor))
- initialize_tracepoint_ftlib (void)
- {
- initialize_tracepoint ();
- gdb_agent_init ();
- }
- #ifndef HAVE_GETAUXVAL
- /* Retrieve the value of TYPE from the auxiliary vector. If TYPE is not
- found, 0 is returned. This function is provided if glibc is too old. */
- unsigned long
- getauxval (unsigned long type)
- {
- unsigned long data[2];
- FILE *f = fopen ("/proc/self/auxv", "r");
- unsigned long value = 0;
- if (f == NULL)
- return 0;
- while (fread (data, sizeof (data), 1, f) > 0)
- {
- if (data[0] == type)
- {
- value = data[1];
- break;
- }
- }
- fclose (f);
- return value;
- }
- #endif
- #endif /* IN_PROCESS_AGENT */
- /* Return a timestamp, expressed as microseconds of the usual Unix
- time. (As the result is a 64-bit number, it will not overflow any
- time soon.) */
- static LONGEST
- get_timestamp (void)
- {
- using namespace std::chrono;
- steady_clock::time_point now = steady_clock::now ();
- return duration_cast<microseconds> (now.time_since_epoch ()).count ();
- }
- void
- initialize_tracepoint (void)
- {
- /* Start with the default size. */
- init_trace_buffer (DEFAULT_TRACE_BUFFER_SIZE);
- /* Wire trace state variable 1 to be the timestamp. This will be
- uploaded to GDB upon connection and become one of its trace state
- variables. (In case you're wondering, if GDB already has a trace
- variable numbered 1, it will be renumbered.) */
- create_trace_state_variable (1, 0);
- set_trace_state_variable_name (1, "trace_timestamp");
- set_trace_state_variable_getter (1, get_timestamp);
- #ifdef IN_PROCESS_AGENT
- {
- int pagesize;
- size_t jump_pad_size;
- pagesize = sysconf (_SC_PAGE_SIZE);
- if (pagesize == -1)
- perror_with_name ("sysconf");
- #define SCRATCH_BUFFER_NPAGES 20
- jump_pad_size = pagesize * SCRATCH_BUFFER_NPAGES;
- gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024);
- gdb_jump_pad_buffer = (char *) alloc_jump_pad_buffer (jump_pad_size);
- if (gdb_jump_pad_buffer == NULL)
- perror_with_name ("mmap");
- gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + jump_pad_size;
- }
- gdb_trampoline_buffer = gdb_trampoline_buffer_end = 0;
- /* It's not a fatal error for something to go wrong with trampoline
- buffer setup, but it can be mysterious, so create a channel to
- report back on what went wrong, using a fixed size since we may
- not be able to allocate space later when the problem occurs. */
- gdb_trampoline_buffer_error = (char *) xmalloc (IPA_BUFSIZ);
- strcpy (gdb_trampoline_buffer_error, "No errors reported");
- initialize_low_tracepoint ();
- #endif
- }
|