Ai
1 Star 0 Fork 0

phy0292/cheat-engine

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
symbolhandler.pas 174.29 KB
一键复制 编辑 原始数据 按行查看 历史
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055
unit symbolhandler;
{$MODE Delphi}
interface
{$ifdef jni}
uses unixporthelper, Classes, sysutils, NewKernelHandler, syncobjs, SymbolListHandler,
fgl, typinfo, cvconst, DotNetPipe, DotNetTypes, commonTypeDefs, math;
{$else}
uses
{$ifdef darwin}
macport, coresymbolication,
{$endif}
{$ifdef windows}
jwawindows, windows,
{$endif}
classes,LCLIntf{$ifdef windows},imagehlp{$endif},sysutils, CEFuncProc,
NewKernelHandler,syncobjs, SymbolListHandler, fgl, typinfo, cvconst, PEInfoFunctions,
DotNetPipe, DotNetTypes, commonTypeDefs, math, LazUTF8, contnrs, LazFileUtils,
db, sqldb, sqlite3dyn, sqlite3conn, registry, symbolhandlerstructs, forms, controls,
AvgLvlTree
{$ifdef darwin}
,macportdefines
{$endif};
{$endif}
{$ifdef windows}
Procedure Free (P : pointer); cdecl; external 'msvcrt' name 'free';
{$endif}
{$ifdef autoassemblerdll}
var
processid: dword;
processhandle: thandle;
Type TMemoryRegion = record
BaseAddress: ptrUint;
MemorySize: Dword;
IsChild: boolean;
startaddress: pointer;
end;
type TMemoryregions = array of tmemoryregion;
{$endif}
type TUserdefinedSymbolCallback=procedure;
type
TSymHandlerTokenType=(ttByte, ttWord, ttDword, ttQword, ttShortInt, ttSmallint, ttLongint, ttInt64);
TSymHandler=class;
TSymbolLoaderThreadEvent=class(tobject)
private
done: TEvent;
ownersymhandler: TSymHandler;
public
symbolname: string;
address: ptruint;
abandoned: boolean;
procedure waittilldone;
constructor create(sh: TSymHandler);
destructor destroy; override;
end;
TGetAddressFromSymbolThreadEvent=class(TSymbolLoaderThreadEvent);
TGetSymbolFromAddressThreadEvent=class(TSymbolLoaderThreadEvent);
TGetStructureFromNameThreadEvent=class(TSymbolLoaderThreadEvent)
public
//symbolname is structname in this case
structure: TStringList;
end;
TGetStructureListThreadEvent=class(TSymbolLoaderThreadEvent)
public
list: TStringList;
end;
TModuleInfoArray=array of TModuleInfo;
TSymbolloaderthread=class(tthread)
private
targetself: boolean;
owner: Tsymhandler;
thisprocesshandle: thandle;
thisprocessid: dword;
SymbolDataBasePath: string;
currentSymbolDataBase: TSQLite3Connection;
currentSymbolDataBaseTransaction: TSQLTransaction;
currentSymbolDataBaseQueryObject: TSQLQuery;
currentmoduleid: integer;
currentModuleName: string;
currentModuleIsNotStandard: boolean;
extraSymbolData: TExtraSymbolData;
//highestsymboladdress: ptruint;
// highestsymbol: string;
fprogress: integer;
modulecount: integer;
enumeratedModules: integer;
symbolloaderthreadeventevent: TEvent;
symbolloaderthreadeventqueue: Tlist;
symbolloaderthreadeventqueueCS: TCriticalSection;
skipList: TStringMap;
notfoundlist: TStringMap;
{$ifdef windows}
modulelist: record
withdebuginfo: array of {$ifdef cpu32}IMAGEHLP_MODULE{$else}IMAGEHLP_MODULE64{$endif};
withoutdebuginfo: array of {$ifdef cpu32}IMAGEHLP_MODULE{$else}IMAGEHLP_MODULE64{$endif};
end;
{$endif}
symbolscleaned: boolean;
pdbonly: boolean; //tells enummodules to skip modules without pdb info
searchpdb: boolean;
structureList: TStringList;
amodulebase: pointer;
{$ifdef darwin}
function loadSymbolsWithSymbolicator: boolean;
{$endif}
procedure teGetStructureList(list: Tstringlist); //handles TGetStructureListThreadEvent
procedure teGetStructureFromName(name: string; structure: TStringList);
procedure processThreadEvents; //in case another thread is in a hurry and doesn't want to wait
{$IFDEF windows}
procedure EnumerateStructures;
{$ENDIF}
procedure EnumerateExtendedDebugSymbols;
procedure LoadDriverSymbols(loadpdb: boolean);
procedure LoadDLLSymbols(loadpdb: boolean; loadmodule: boolean);
procedure finishedLoadingSymbols;
function NetworkES(modulename: string; symbolname: string; address: ptruint; size: integer; secondary: boolean): boolean;
public
isloading: boolean;
sectionsloaded: boolean;
apisymbolsloaded: boolean;
pdbsymbolsloaded: boolean;
dotnetsymbolsloaded: boolean;
hasEnumeratedAllStructures: boolean;
error: boolean;
symbolsloaded: boolean;
DLLSymbolsLoaded: boolean;
kernelsymbols: boolean;
dllsymbols: boolean;
searchpath: string;
{$ifdef darwin}
cs: CSSymbolicatorRef;
{$endif}
symbollist: TSymbolListHandler;
debugpart: integer;
ExtendedDebugSymbolProgress: integer;
skipAllSymbols: Boolean;
skipAddressToSymbol: boolean;
driverlistMREW: TMultiReadExclusiveWriteSynchronizer;
driverlistpos: integer;
driverlist: TModuleInfoArray;
function getAddressFromSymbol(symbol: string): ptruint;
function getSymbolFromAddress(address: ptruint): string;
procedure getStructureFromName(structname: string; elements: tstringlist);
procedure getStructureList(l: Tstringlist);
procedure execute; override;
constructor create(owner: TSymhandler; targetself, CreateSuspended: boolean);
destructor destroy; override;
property progress: integer read fProgress;
end;
TTokens=array of string;
PBoolean=^boolean;
TDotNetModuleSymbols=record
modulename: string; //for debugging
modulebase: qword; //unique identifier
symbollist: TSymbolListHandler;
end;
TSymHandler=class
private
symbolloaderthread: TSymbolloaderthread;
modulelistpos: integer;
modulelist: TModuleInfoArray;
symbolloadervalid: TMultiReadExclusiveWriteSynchronizer;
modulelistMREW: TMultiReadExclusiveWriteSynchronizer;
userdefinedsymbolspos: integer;
userdefinedsymbols: array of TUserdefinedsymbol;
userdefinedsymbolsCS: TCriticalSection; //not actively used and needs reentry which isn't implemented in the MREW
fshowmodules: boolean; //--determines what is returned by getnamefromaddress
fshowsymbols: boolean; ///
fshowsections: boolean; ///
UserdefinedSymbolCallback: TUserdefinedSymbolCallback;
searchpath: string;
globalalloc: pointer; //if set it hold a pointer to the last free memory that was allocated.
globalallocsizeleft: integer; //defines how much memory was left
globalallocpid: integer; //the processid this alloc belongs to
commonModuleList: tstringlist;
symbollist: TSymbolListHandler;
symbollists: array of TSymbolListHandler;
symbollistsMREW: TMultiReadExclusiveWriteSynchronizer;
SymbolsLoadedNotification: array of TNotifyEvent;
{$ifdef windows}
dotNetDataCollector: TDotNetPipe;
dotnetModuleSymbolList: array of TDotNetModuleSymbols;
dotnetModuleSymbolListMREW: TMultiReadExclusiveWriteSynchronizer; //MREW for adding/removing modules to the list
symbolDataBase: TSQLite3Connection;
{$endif}
function OpenDatabaseIfNeeded:boolean;
function getusedprocesshandle :thandle;
function getusedprocessid:dword;
function getisloaded:boolean;
function geterror:boolean;
function getProgress:integer;
function getExtendedDataProgress: integer;
function getDotNetAccess: boolean;
function GetUserdefinedSymbolByNameIndex(symbolname:string):integer;
function GetUserdefinedSymbolByAddressIndex(address: ptruint):integer;
function areSymbolsLoadedForModule(symbolname: string): boolean;
procedure markModuleAsLoaded(address: ptruint); //called by the symbolhandlerthread
procedure setshowmodules(x: boolean); //todo: Move this to the disassembler and let that decide
procedure setshowsections(x: boolean);
procedure setshowsymbols(x: boolean);
procedure tokenize(s: string; var tokens: TTokens);
function isTypeToken(token: string; var nextTokenType: TSymHandlerTokenType): boolean;
function isParsingStructures: boolean;
function isloadingExtendedData: boolean;
public
kernelsymbols: boolean;
dllsymbols: boolean;
locked: boolean;
targetself: boolean;
ExceptionOnLuaLookup: boolean;
property showmodules: boolean read fshowmodules write setshowmodules;
property showsections: boolean read fshowsections write setshowsections;
property showsymbols: boolean read fshowsymbols write setshowsymbols;
property usedprocesshandle: thandle read getusedprocesshandle;
property usedprocessid: dword read getusedprocessid;
property isloaded: boolean read getisloaded;
property hasError: boolean read geterror;
property hasDotNetAccess: boolean read getDotNetAccess;
property progress: integer read getProgress;
property extendedDataProgess: integer read getExtendedDataProgress;
property parsingStructures: boolean read isParsingStructures;
property loadingExtendedData: boolean read isloadingExtendedData;
procedure waitforsymbolsloaded(apisymbolsonly: boolean=false; specificmodule: string='');
procedure waitForSections;
procedure waitForExports;
procedure waitForDotNet;
procedure waitForPDB;
procedure searchPDBWhileLoading(state: boolean);
procedure EnumDotNetModule(m: TdotNetmodule; symbolhandler: TSymbolListHandler);
procedure reinitializeDotNetSymbols(modulename: string='');
procedure reinitialize(force: boolean=false);
function loadmodulelist: boolean; //returns true if a change was detected from the previous list
procedure ReinitializeUserdefinedSymbolList;
procedure fillMemoryRegionsWithModuleData(var mr: TMemoryregions; startaddress: ptruint; size: dword);
procedure getModuleList(list: tstrings);
procedure GetSymbolList(address: ptruint; list: tstrings);
function getmodulebyaddress(address: ptrUint; var mi: TModuleInfo):BOOLEAN;
function getmodulebyname(modulename: string; var mi: TModuleInfo):BOOLEAN;
function inModule(address: ptrUint): BOOLEAN; //returns true if the given address is part of a module
function inSystemModule(address: ptrUint): BOOLEAN;
function getNameFromAddress(address:ptrUint):string; overload;
function getNameFromAddress(address:ptrUint; var found: boolean; hexcharsize: integer=8):string; overload;
function getNameFromAddress(address:ptrUint;symbols,modules, sections: boolean; baseaddress: PUINT64=nil; found: PBoolean=nil; hexcharsize: integer=8; important: boolean=true):string; overload;
function getExtraDataFromSymbolAtAddress(address: ptruint): TExtraSymbolData;
function getAddressFromNameL(name: string; waitforsymbols: boolean=true):ptrUint; //Called by lua. Looks at ExceptionOnLookup
function getAddressFromName(name: string):ptrUint; overload;
function getAddressFromName(name: string; waitforsymbols: boolean):ptrUint; overload;
function getAddressFromName(name: string; waitforsymbols: boolean; out haserror: boolean):ptrUint; overload;
function getAddressFromName(name: string; waitforsymbols: boolean; out haserror: boolean; context: PContext; shallow: boolean=false):ptrUint; overload;
function getAddressFromNameShallow(name: string; waitforsymbols: boolean; out haserror: boolean):ptrUint;
function getDotNetDataCollector: TDotNetPipe;
function getDotNetObjectList: TDOTNETObjectList;
procedure freeDotNetObjectList(list: TDOTNETObjectList);
function getSymbolInfo(name: string; var syminfo: TCESymbolInfo): boolean;
function getStructureList(list: TStringList; max: integer=-1): integer;
procedure getStructureElements(callbackid: integer; moduleid: integer; typeid: integer; list: TStringList);
procedure getStructureElementsFromName(name: string; list: TStringList);
function hasDefinedStructures:boolean;
function GetLayoutFromAddress(address: ptruint; var addressdata: TAddressData): boolean; //for .net only
function getsearchpath:string;
procedure setsearchpath(path:string);
//userdefined symbols
function DeleteUserdefinedSymbol(symbolname:string):boolean;
function GetUserdefinedSymbolByName(symbolname:string):ptrUint;
function SetUserdefinedSymbolAllocSize(symbolname:string; size: dword; preferedaddress: ptruint=0): boolean;
function GetUserdefinedSymbolByAddress(address:ptrUint):string;
procedure AddUserdefinedSymbol(addressstring: string; symbolname: string; donotsave: boolean=false);
procedure EnumerateUserdefinedSymbols(list:tstrings);
function ParseAsPointer(s: string; list:tstrings): boolean;
function ParseRange(s: string; var start: QWORD; var stop: QWORD): boolean;
function GetAddressFromPointer(s: string; var error: boolean):ptrUint;
function LookupStructureOffset(s: string; out offset: integer): boolean;
procedure loadCommonModuleList;
function getCommonModuleList: Tstringlist;
procedure RegisterUserdefinedSymbolCallback(callback: TUserdefinedSymbolCallback);
procedure RemoveFinishedLoadingSymbolsNotification(n: TNotifyEvent);
procedure AddFinishedLoadingSymbolsNotification(n: TNotifyEvent);
procedure AddSymbolList(sl: TSymbolListHandler);
procedure RemoveSymbolList(sl: TSymbolListHandler);
procedure NotifyFinishedLoadingSymbols; //go through the list of functions to call when the symbollist has finished loading
constructor create;
destructor destroy; override;
end;
var symhandler: TSymhandler=nil;
selfsymhandler: TSymhandler=nil; //symhandler object for CE itself
type TSymbolLookupCallbackPoint=(
slStart=0, //The very start of a symbol lookup. Before tokenization
slNotInt=1, //Called when it has been determined it's not a hexadecimal only string. Before tokenization
slNotModule=2, //Called when it has been determined the current token is not a modulename
slNotUserdefinedSymbol=3, //Called when it has been determined it's not a userdefined symbol
slNotSymbol=4, //: Called when it has been determined it's not a symbol in the symbollist
slFailure=5 //: Called when it has no clue what the given string is
);
type TSymbolLookupCallback=function(s: string): PtrUInt of object;
type TAddressLookupCallback=function(address: ptruint): string of object;
type TStructureListCallback=function(callback: integer; list: tstringlist; max: integer=-1):boolean of object;
type TElementListCallback=function(moduleid: integer; typeid: integer; list: TStringlist): boolean of object;
function registerSymbolLookupCallback(callback: TSymbolLookupCallback; cbp: TSymbolLookupCallbackPoint): integer;
procedure unregisterSymbolLookupCallback(id: integer);
function registerAddressLookupCallback(callback: TAddressLookupCallback): integer;
procedure unregisterAddressLookupCallback(id: integer);
function registerStructureAndElementListCallback(scallback: TStructureListCallback; ecallback: TElementListCallback): integer;
procedure unregisterStructureAndElementListCallback(id: integer);
{$ifdef windows}
type TSTACKFRAME_EX = record
AddrPC : TADDRESS64;
AddrReturn : TADDRESS64;
AddrFrame : TADDRESS64;
AddrStack : TADDRESS64;
AddrBStore : TADDRESS64;
FuncTableEntry : POINTER;
Params : array[0..3] of DWORD64;
Far : BOOL;
Virtual : BOOL;
Reserved : array[0..2] of DWORD64;
KdHelp : TKDHELP64;
StackFrameSize: DWORD;
InlineFrameContext: DWORD;
end;
PStackframe_ex=^TSTACKFRAME_EX;
{$endif}
type
TSymFromName=function(hProcess: HANDLE; Name: LPSTR; Symbol: PSYMBOL_INFO): BOOL; stdcall;
TSymFromAddr=function(hProcess:THANDLE; Address:dword64; Displacement:PDWORD64; Symbol:PSYMBOL_INFO):BOOL;stdcall;
TSymEnumeratesymbolsCallback=function(pSymInfo: PSYMBOL_INFO; SymbolSize: ULONG; UserContext: Pointer): BOOL; stdcall;
TSymSearch=function(hProcess: THANDLE; BaseOfDLL: ULONG64; Index: DWORD; SymTag: DWORD; Mask: PCHAR; Address: DWORD64; callback: TSymEnumeratesymbolsCallback; userContext: pointer; Options: DWORD): BOOL; stdcall;
{$ifdef windows}
var SymFromName: TSymFromName;
SymFromAddr: TSymFromAddr;
SymSearch: TSymSearch;
StackWalkEx:function(MachineType:dword; hProcess:THANDLE; hThread:THANDLE; StackFrame:PStackframe_ex; ContextRecord:pointer; ReadMemoryRoutine:TREAD_PROCESS_MEMORY_ROUTINE64; FunctionTableAccessRoutine:TFUNCTION_TABLE_ACCESS_ROUTINE64; GetModuleBaseRoutine:TGET_MODULE_BASE_ROUTINE64; TranslateAddress:TTRANSLATE_ADDRESS_ROUTINE64; flags: dword):bool;stdcall;
SymLoadModuleEx:function(hProcess:THANDLE; hFile:THANDLE; ImageName:PSTR; ModuleName:PSTR; BaseOfDll:dword64; DllSize:dword; Data:pointer; Flags:dword):dword64;stdcall;
UnDecorateSymbolName:function(name: PCSTR; outputString: PSTR; maxStringLength: DWORD; flags: DWORD): DWORD; stdcall;
{$endif}
procedure symhandlerInitialize;
implementation
{$ifdef jni}
uses networkInterface, networkInterfaceApi, ProcessHandlerUnit, Globals, Parsers;
{$else}
uses Assemblerunit, driverlist, LuaHandler, lualib, lua, lauxlib,
disassemblerComments, StructuresFrm2, networkInterface, networkInterfaceApi,
ProcessHandlerUnit, Globals, Parsers, MemoryQuery, LuaCaller,
UnexpectedExceptionsHelper, frmSymbolEventTakingLongUnit, MainUnit, addresslist,
MemoryRecordUnit;
{$endif}
resourcestring
rsSymbolloaderthreadHasCrashed = 'Symbolloaderthread has crashed';
rsYouCanTChangeThisSettingAtTheMoment = 'You can''t change this setting at the moment';
rsPleaseProvideABiggerSize = 'Please provide a bigger size';
rsErrorAllocatingMemory = 'Error allocating memory';
rsTheSymbolNamedWasPreviouslyDeclared = 'The symbol named %s was previously declared with a size of %s instead of %s. all scripts that use this memory must give the same size. '
+'Adjust the size, or delete the old alloc from the userdefined symbol list';
rsAlreadyExists = 'already exists';
rsYouCanTAddASymbolWithAddress0 = 'You can''t add a symbol with address 0';
rsFailureDeterminingWhatMeans = 'Failure determining what %s means';
const
LIST_MODULES_DEFAULT=0;
LIST_MODULES_32BIT=1;
LIST_MODULES_64BIT=2;
LIST_MODULES_ALL=3;
SLMFLAG_NO_SYMBOLS=4;
{$IFNDEF JNI}
type TEnumProcessModulesEx=function(hProcess: HANDLE; lphModule: PHMODULE; cb: DWORD; var lpcbNeeded: DWORD; dwFilterFlag: DWORD): BOOL; stdcall;
type TEnumProcessModules=function(hProcess: HANDLE; lphModule: PHMODULE; cb: DWORD; var lpcbNeeded: DWORD): BOOL; stdcall;
type TGetModuleFileNameEx=function(hProcess: HANDLE; hModule: HMODULE; lpFilename: pchar; nSize: DWORD): DWORD; stdcall;
{$ENDIF}
var
{$IFNDEF JNI}
EnumProcessModulesEx: TEnumProcessModulesEx;
EnumProcessModules: TEnumProcessModules;
GetModuleFileNameEx: TGetModuleFilenameEx;
{$ENDIF}
SymbolLookupCallbacks: array [slStart..slFailure] of array of TSymbolLookupCallback;
AddressLookupCallbacks: array of TAddressLookupCallback;
StructureElementListCallbacks: array of record
StructureListCallback: TStructureListCallback;
ElementListCallback: TElementListCallback;
end;
databasepath: string;
symbolloaderthreadcs: TCriticalSection;
function registerSymbolLookupCallback(callback: TSymbolLookupCallback; cbp: TSymbolLookupCallbackPoint): integer;
var i: integer;
begin
//first check if there is an unassigned entry to use
for i:=0 to length(SymbolLookupCallbacks[cbp])-1 do
if not assigned(SymbolLookupCallbacks[cbp][i]) then
begin
result:=i;
SymbolLookupCallbacks[cbp][i]:=callback;
result:=result or (integer(cbp) shl 29); //last 3 bits of the ID specify the callbackpoint. sure, it limits the number of callbacks per point to only 536870911 but I don't care
exit;
end;
result:=length(SymbolLookupCallbacks[cbp]);
setlength(SymbolLookupCallbacks[cbp], result+1);
SymbolLookupCallbacks[cbp][result]:=callback;
result:=result or (integer(cbp) shl 29);
end;
procedure unregisterSymbolLookupCallback(id: integer);
var cbp: TSymbolLookupCallbackPoint;
begin
cbp:=TSymbolLookupCallbackPoint(id shr 29);
id:=id and $1FFFFFFF;
if id<length(SymbolLookupCallbacks[cbp]) then
begin
{$ifdef windows}
CleanupLuaCall(TMethod(SymbolLookupCallbacks[cbp][id]));
{$endif}
SymbolLookupCallbacks[cbp][id]:=nil;
end;
end;
function registerAddressLookupCallback(callback: TAddressLookupCallback): integer;
var i: integer;
begin
//first check if there is an unassigned entry to use
for i:=0 to length(AddressLookupCallbacks)-1 do
if not assigned(AddressLookupCallbacks[i]) then
begin
result:=i;
AddressLookupCallbacks[i]:=callback;
exit;
end;
result:=length(AddressLookupCallbacks);
setlength(AddressLookupCallbacks, result+1);
AddressLookupCallbacks[result]:=callback;
end;
procedure unregisterAddressLookupCallback(id: integer);
begin
if id<length(AddressLookupCallbacks) then
begin
{$ifdef windows}
CleanupLuaCall(TMethod(AddressLookupCallbacks[id]));
{$endif}
AddressLookupCallbacks[id]:=nil;
end;
end;
function registerStructureAndElementListCallback(scallback: TStructureListCallback; ecallback: TElementListCallback): integer;
var i: integer;
begin
//first check if there is an unassigned entry to use
for i:=0 to length(StructureElementListCallbacks)-1 do
if (not assigned(StructureElementListCallbacks[i].ElementListCallback)) and (not assigned(StructureElementListCallbacks[i].ElementListCallback)) then
begin
result:=i;
StructureElementListCallbacks[i].StructureListCallback:=scallback;
StructureElementListCallbacks[i].ElementListCallback:=ecallback;
exit;
end;
result:=length(StructureElementListCallbacks);
setlength(StructureElementListCallbacks, result+1);
StructureElementListCallbacks[result].StructureListCallback:=scallback;
StructureElementListCallbacks[result].ElementListCallback:=ecallback;
end;
procedure unregisterStructureAndElementListCallback(id: integer);
begin
if id<length(StructureElementListCallbacks) then
begin
{$ifdef windows}
CleanupLuaCall(TMethod(StructureElementListCallbacks[id].StructureListCallback));
CleanupLuaCall(TMethod(StructureElementListCallbacks[id].ElementListCallback));
{$endif}
StructureElementListCallbacks[id].StructureListCallback:=nil;
StructureElementListCallbacks[id].ElementListCallback:=nil;
end;
end;
procedure TSymbolLoaderThreadEvent.waittilldone;
var
waitingtime: dword;
begin
waitingtime:=0;
if waitingfrm<>nil then exit; //don't bother
while (ownersymhandler.symbolloaderthread<>nil) and (done.WaitFor(100)=wrTimeout) do
begin
if ((self is TGetAddressFromSymbolThreadEvent) or (self is TGetSymbolFromAddressThreadEvent)) and
(ownersymhandler.symbolloaderthread.isloading) then break;
if GetCurrentThreadId=MainThreadID then
begin
CheckSynchronize;
inc(waitingtime,100);
if waitingtime>2000 then
begin
//spawn a TfrmSymboleventtakinglong form that uses a timer to check the TSymbolLoaderThreadEvent event
waitingfrm:=TfrmSymbolEventTakingLong.Create(application);
waitingfrm.slevent:=self;
if self is TGetAddressFromSymbolThreadEvent then
begin
waitingfrm.lblType.Caption:='Symbol:';
waitingfrm.lblSymbol.caption:=symbolname;
end
else
if self is TGetSymbolFromAddressThreadEvent then
begin
waitingfrm.lblType.Caption:='Address:';
waitingfrm.lblSymbol.caption:=inttohex(address,8);
waitingfrm.cbSkipAllSymbols.visible:=false;
waitingfrm.cbSkipThisSymbol.visible:=false;
end
else
if self is TGetStructureFromNameThreadEvent then
begin
waitingfrm.Caption:='Retrieving structure data';
waitingfrm.Label1.Caption:='Currently fetching the structure data of:';
waitingfrm.lblType.Caption:=symbolname;
waitingfrm.lblSymbol.visible:=false;
waitingfrm.Button1.visible:=false;
waitingfrm.cbSkipThisSymbol.visible:=false;
waitingfrm.cbSkipAllSymbols.visible:=false;
end
else
if self is TGetStructureListThreadEvent then
begin
waitingfrm.Caption:='Retrieving structure list';
waitingfrm.Label1.Caption:='Currently fetching the structure list. Please stand by...';
waitingfrm.lblType.Caption:='Count: ';
waitingfrm.lblSymbol.Caption:=inttostr(TGetStructureListThreadEvent(Self).list.Count);
waitingfrm.Button1.visible:=false;
waitingfrm.cbSkipThisSymbol.visible:=false;
waitingfrm.cbSkipAllSymbols.visible:=false;
waitingfrm.list:=TGetStructureListThreadEvent(Self).list;
end;
waitingfrm.done:=done;
if waitingfrm.ShowModal<>mrok then
begin
if self is TGetSymbolFromAddressThreadEvent then
ownersymhandler.symbolloaderthread.skipAddressToSymbol:=true
else
if self is TGetAddressFromSymbolThreadEvent then
begin
if waitingfrm.cbSkipThisSymbol.checked then
begin
if ownersymhandler.symbolloaderthread.skipList=nil then
ownersymhandler.symbolloaderthread.skipList:=TStringMap.Create(false);
ownersymhandler.symbolloaderthread.skipList.Add(symbolname);
end;
if waitingfrm.cbSkipAllSymbols.checked then
ownersymhandler.symbolloaderthread.skipAllSymbols:=true;
abandoned:=true;
end;
break;
end;
end;
end;
end;
if waitingfrm<>nil then
freeandnil(waitingfrm);
end;
constructor TSymbolLoaderThreadEvent.create(sh: TSymhandler);
begin
ownersymhandler:=sh;
done:=tevent.Create(nil,true,false,'');
end;
destructor TSymbolLoaderThreadEvent.destroy;
begin
if done<>nil then
done.free;
inherited destroy;
end;
function EnumProcessModulesExNotImplemented(hProcess: HANDLE; lphModule: PHMODULE; cb: DWORD; var lpcbNeeded: DWORD; dwFilterFlag: DWORD): BOOL; stdcall;
begin
{$ifndef jni}
result:=EnumProcessModules(hProcess,lphModule,cb,lpcbNeeded);
{$else}
result:=false;
{$endif}
end;
procedure TSymbolloaderthread.LoadDLLSymbols(loadPDB: boolean; loadmodule: boolean);
{$IFDEF windows}
var need:dword;
x: PPointerArray;
i: integer;
count: integer;
modulename: pchar;
modulelisttype: integer;
mi: {$ifdef cpu32}IMAGEHLP_MODULE{$else}IMAGEHLP_MODULE64{$endif};
offset: integer;
path: pchar;
{$ENDIF}
begin
{$ifdef windows}
need:=0;
modulelisttype:=LIST_MODULES_ALL;
EnumProcessModulesEx(thisprocesshandle,nil,0,need, modulelisttype);
getmem(x,need);
try
if EnumProcessModulesEx(thisprocesshandle,@x[0],need,need, modulelisttype) then
begin
count:=need div sizeof(pointer);
getmem(modulename,1024);
try
if count>0 then
amodulebase:=x[0];
for i:=0 to count-1 do
begin
GetModuleFileNameEx(thisprocesshandle,ptrUint(x[i]),modulename,200);
if loadmodule then
begin
if assigned(SymLoadModuleEx) then
symLoadModuleEx(thisprocesshandle,0,pchar(modulename),nil,ptrUint(x[i]),0,nil,ifthen(loadpdb,0,SLMFLAG_NO_SYMBOLS))
else
SymLoadModule64(thisprocesshandle,0,pchar(modulename),nil,ptrUint(x[i]),0);
end;
mi.SizeOfStruct:=sizeof(mi);
if SymGetModuleInfo(thisprocesshandle, ptruint(x[i]), @mi) then
begin
if mi.SymType in [SymExport, SymNone] then
begin
setlength(modulelist.withoutdebuginfo,length(modulelist.withoutdebuginfo)+1);
modulelist.withoutdebuginfo[length(modulelist.withoutdebuginfo)-1]:=mi;
end
else
begin
setlength(modulelist.withdebuginfo,length(modulelist.withdebuginfo)+1);
modulelist.withdebuginfo[length(modulelist.withdebuginfo)-1]:=mi;
end;
end;
end;
finally
freememandnil(modulename);
end;
end;
finally
freememandnil(x);
end;
{$endif}
end;
procedure TSymbolloaderthread.LoadDriverSymbols(loadpdb: boolean);
{$IFDEF windows}
var need:dword;
x: PPointerArray;
i,c: integer;
count: integer;
drivername: pchar;
driverpath: string;
r: dword;
modulename: pchar;
modulelisttype: integer;
mi: {$ifdef cpu32}IMAGEHLP_MODULE{$else}IMAGEHLP_MODULE64{$endif};
offset: integer;
path: pchar;
size: dword;
is64bit: boolean;
{$ENDIF}
begin
{$IFDEF WINDOWS}
EnumDevicedrivers(nil,0,need);
getmem(x,need*2);
try
if enumDevicedrivers(@x[0],need*2,need) then
begin
count:=need div sizeof(pointer);
getmem(drivername,255);
try
for i:=0 to count-1 do
begin
c:=GetDeviceDriverFileNameA(x[i],drivername,200);
if c<>0 then
begin
drivername[c]:=#0;
driverpath:=drivername;
//add drive letter
driverpath:=StringReplace(driverpath,'\??\','',[]);
driverpath:=StringReplace(driverpath,'\SystemRoot\',systemroot,[rfIgnoreCase]);
if assigned(SymLoadModuleEx) then
r:=SymLoadModuleEx(thisprocesshandle,0,pchar(driverpath),pchar(extractfilename(driverpath)),ptrUint(x[i]),0,nil,ifthen(loadpdb,0, SLMFLAG_NO_SYMBOLS))
else
r:=SymLoadModule64(thisprocesshandle,0,pchar(driverpath),pchar(extractfilename(driverpath)),ptrUint(x[i]),0);
mi.SizeOfStruct:=sizeof(mi);
if SymGetModuleInfo(thisprocesshandle, ptruint(x[i]), @mi) then
begin
driverlistMREW.Beginwrite;
if driverlistpos>=length(driverlist) then
setlength(driverlist,length(driverlist)+64);
driverlist[driverlistpos].modulename:=extractfilename(driverpath);
driverlist[driverlistpos].modulepath:=driverpath;
driverlist[driverlistpos].isSystemModule:=true;
driverlist[driverlistpos].baseaddress:=qword(x[i]);
if peinfo_getimagesizefromfile(driverpath,size) then
driverlist[driverlistpos].basesize:=size
else
driverlist[driverlistpos].basesize:=4096;
driverlist[driverlistpos].is64bitmodule:=Is64bitOS;
inc(driverlistpos);
if driverlistpos>=length(driverlist) then
setlength(driverlist,length(driverlist)+64);
driverlistMREW.Endwrite;
//srv*c:\DownstreamStore*https://msdl.microsoft.com/download/symbols
if (mi.SymType in [SymExport, SymNone]) then
begin
setlength(modulelist.withoutdebuginfo,length(modulelist.withoutdebuginfo)+1);
modulelist.withoutdebuginfo[length(modulelist.withoutdebuginfo)-1]:=mi;
end
else
begin
setlength(modulelist.withdebuginfo,length(modulelist.withdebuginfo)+1);
modulelist.withdebuginfo[length(modulelist.withdebuginfo)-1]:=mi;
end;
end;
end;
end;
finally
freememandnil(drivername);
end;
end;
finally
freememandnil(x);
end;
{$ENDIF}
end;
procedure TSymbolloaderthread.finishedLoadingSymbols;
begin
//OutputDebugString('finishedLoadingSymbols called');
if (not targetself) and (symhandler<>nil) then symhandler.NotifyFinishedLoadingSymbols;
// OutputDebugString('exit finishedLoadingSymbols()');
end;
type
PIMAGEHLP_STACK_FRAME = ^TIMAGEHLP_STACK_FRAME;
TIMAGEHLP_STACK_FRAME = record
InstructionOffset : ULONG64;
ReturnOffset : ULONG64;
FrameOffset : ULONG64;
StackOffset : ULONG64;
BackingStoreOffset : ULONG64;
FuncTableEntry : ULONG64;
Params : array[0..3] of ULONG64;
Reserved : array[0..4] of ULONG64;
Virtual : BOOL;
Reserved2 : ULONG;
end;
IMAGEHLP_STACK_FRAME = TIMAGEHLP_STACK_FRAME;
LPIMAGEHLP_STACK_FRAME = PIMAGEHLP_STACK_FRAME;
function symflagsToString(symflags: dword): string;
var s: string;
begin
{$IFDEF WINDOWS}
s:='';
if (symFlags and SYMFLAG_VALUEPRESENT)>0 then
s:=s+'VALUEPRESENT ';
if (symFlags and SYMFLAG_REGISTER)>0 then
s:=s+'REGISTER ';
if (symflags and SYMFLAG_REGREL)>0 then
s:=s+'REGREL ';
if (symflags and SYMFLAG_FRAMEREL)>0 then
s:=s+'FRAMEREL ';
if (symflags and SYMFLAG_PARAMETER)>0 then
s:=s+'PARAMETER ';
if (symflags and SYMFLAG_LOCAL)>0 then
s:=s+'LOCAL ';
if (symflags and SYMFLAG_CONSTANT)>0 then
s:=s+'CONSTANT ';
if (symflags and SYMFLAG_EXPORT)>0 then
s:=s+'EXPORTED ';
if (symflags and SYMFLAG_FORWARDER)>0 then
s:=s+'FORWARDER ';
if (symflags and SYMFLAG_FUNCTION)>0 then
s:=s+'FUNCTION ';
if (symflags and SYMFLAG_VIRTUAL)>0 then
s:=s+'VIRTUAL ';
if (symflags and SYMFLAG_THUNK)>0 then
s:=s+'THUNK ';
if (symflags and SYMFLAG_TLSREL)>0 then
s:=s+'TLSREL ';
result:=s;
{$ENDIF}
end;
function GetTypeName(h: HANDLE; modbase: UINT64; index: integer; infinitycheck: integer=50): string;
var x: dword;
type_symtag: TSymTagEnum;
name: PWCHAR;
begin
{$IFDEF WINDOWS}
result:='';
if infinitycheck<0 then exit;
if SymGetTypeInfo(h, modbase, index, TI_GET_SYMTAG, @type_symtag) then
begin
case type_symtag of
SymTagBaseType:
begin
x:=0;
if SymGetTypeInfo(h, ModBase, index, TI_GET_BASETYPE, @x) then
begin
case TBasicType(x) of
btNoType: result:='NoType';
btVoid: result:='VOID';
btChar: result:='CHAR';
btWChar: result:='WCHAR';
btInt: result:='INT';
btUInt: result:='UINT';
btFloat: result:='FLOAT';
btBCD: result:='BCD';
btBool: result:='BOOL';
btLong: result:='LONG';
btULong: result:='ULONG';
btCurrency: result:='CURRENCY';
btDate: result:='DATE';
btVariant: result:='VARIANT';
btComplex: result:='COMPLEX';
btBit: result:='BIT';
btBSTR:result:='BTSTR';
btHresult: result:= 'HRESULT';
else
result:='BasicType'+inttostr(x);
end;
end;
end;
SymTagPointerType:
begin
if SymGetTypeInfo(h, ModBase, index, TI_GET_TYPEID, @x) then
result:=GetTypeName(h, modbase, x, infinitycheck-1)
end;
SymTagUDT:
begin
name:=nil;
if SymGetTypeInfo(h, ModBase, index, TI_GET_SYMNAME, @name) then
begin
result:=name;
LocalFree(PTRUINT(name));
end;
end;
SymTagArrayType:
begin
if SymGetTypeInfo(h, ModBase, index, TI_GET_ARRAYINDEXTYPEID, @x) then
result:=GetTypeName(h, modbase, x, infinitycheck-1)+'[]'
else
result:='[]';
end;
SymTagEnum:
begin
name:=nil;
if SymGetTypeInfo(h, ModBase, index, TI_GET_SYMNAME, @name) then
begin
result:='enum '+name;
LocalFree(PTRUINT(name));
end;
end;
SymTagFunctionType:
begin
result:='(function)';
end;
SymTagVTableShape:
begin
result:='<vtable>';
end;
else
begin
//something else
end;
end;
end;
{$ENDIF}
end;
function RegToString(reg: integer): string;
begin
result:='';
case reg of
CV_REG_NONE: result:='';
CV_ALLREG_ERR : result:='ERR';
CV_ALLREG_TEB : result:='TEB';
CV_ALLREG_TIMER : result:='TIMER';
CV_ALLREG_EFAD1 : result:='EFAD1';
CV_ALLREG_EFAD2 : result:='EFAD2';
CV_ALLREG_EFAD3 : result:='EFAD3';
CV_ALLREG_VFRAME: result:='VFRAME';
CV_ALLREG_HANDLE: result:='HANDLE';
CV_ALLREG_PARAMS: result:='PARAMS';
CV_ALLREG_LOCALS: result:='LOCALS';
CV_ALLREG_TID : result:='TID';
CV_ALLREG_ENV : result:='ENV';
CV_ALLREG_CMDLN : result:='CMDLN';
CV_AMD64_RAX : result:='RAX';
CV_AMD64_RCX : result:='RCX';
CV_AMD64_RDX : result:='RDX';
CV_AMD64_RBX : result:='RBX';
CV_AMD64_RSP : result:='RSP';
CV_AMD64_RBP : result:='RBP';
CV_AMD64_RSI : result:='RSI';
CV_AMD64_RDI : result:='RDI';
CV_AMD64_R8 : result:='R8';
CV_AMD64_R9 : result:='R9';
CV_AMD64_R10 : result:='R10';
CV_AMD64_R11 : result:='R11';
CV_AMD64_R12 : result:='R12';
CV_AMD64_R13 : result:='R13';
CV_AMD64_R14 : result:='R14';
CV_AMD64_R15 : result:='R15';
CV_REG_EAX : result:='EAX';
CV_REG_ECX : result:='ECX';
CV_REG_EDX : result:='EDX';
CV_REG_EBX : result:='EBX';
CV_REG_ESP : result:='ESP';
CV_REG_EBP : result:='EBP';
CV_REG_ESI : result:='ESI';
CV_REG_EDI : result:='EDI';
else
result:='?';
end;
end;
function getPositionFromSymInfo(pSymInfo:PSYMBOL_INFO): string;
var addressString: string;
begin
result:='';
{$IFDEF windows}
//try to figure out whee it is stored (register/ offset, etc...)
result:=RegToString(pSymInfo.reg);
if (pSymInfo.Address<>0) then
begin
addressString:=IntToHexSigned(LONG64(pSymInfo.Address),1);
if (result<>'') then
begin
//it's a reg+address notation
if LONG64(pSymInfo.Address)>0 then
result:=result+'+'+addressString
else
result:=result+addressString; //already has a - sign
end
else
result:=addressString;
end;
{$ENDIF}
end;
function ES2(pSymInfo:PSYMBOL_INFO; SymbolSize:ULONG; UserContext:pointer):BOOL;stdcall;
var
s: string;
slt: TSymbolloaderthread;
isparam: boolean;
esde: TExtraSymbolDataEntry;
begin
{$IFDEF WINDOWS}
result:=false;
if pSymInfo.NameLen=0 then
exit;
slt:=TSymbolloaderthread(UserContext);
if slt.terminated then exit;
isparam:=(pSymInfo.Flags and SYMFLAG_PARAMETER)>0;
s:=GetTypeName(slt.thisprocesshandle, pSymInfo.ModBase, pSymInfo.TypeIndex);
//add an extra symboldataentry
esde:=TExtraSymbolDataEntry.create;
esde.name:=pchar(@pSymInfo.Name);
esde.vtype:=s;
esde.position:=getPositionFromSymInfo(pSymInfo);
esde.syminfo:=pSymInfo^; //the name is known, so no need to do any fancy allocating
if isparam then
slt.extraSymbolData.parameters.Add(esde)
else
slt.extraSymbolData.locals.Add(esde);
slt.processThreadEvents;
result:=(slt.terminated=false);
{$ENDIF}
end;
var es2address: pointer=@es2;
//var SES:function;
{$IFDEF windows}
var SES:function(hProcess:THANDLE; BaseOfDll:ULONG64; Mask:LPCSTR; EnumSymbolsCallback:TSYM_ENUMERATESYMBOLS_CALLBACK; UserContext:pointer):BOOL;stdcall; //external External_library name 'SymEnumSymbols';
{$ENDIF}
procedure TSymbolloaderthread.EnumerateExtendedDebugSymbols;
var
i: integer;
max: integer;
c: PIMAGEHLP_STACK_FRAME;
esd: TExtraSymbolData;
d: hmodule;
begin
{$IFDEF WINDOWS}
if not assigned(ses) then
begin
d:=loadlibrary('dbghelp.dll');
ses:=getprocaddress(d,'SymEnumSymbols');
end;
max:=self.symbollist.ExtraSymbolDataList.Count;
for i:=0 to max-1 do
begin
debugpart:=40000+i;
ExtendedDebugSymbolProgress:=(i*100) div max;
esd:=TExtraSymbolData(self.symbollist.ExtraSymbolDataList[i]);
if (not esd.forwarder) and (not esd.filledin) and (esd.symboladdress<>0) then
begin
//get the data
if terminated then exit;
self.extraSymbolData:=esd;
getmem(c,sizeof(c)*2+1024);
ZeroMemory(c, sizeof(c)*2+1024);
c.InstructionOffset:=self.extraSymbolData.symboladdress;
SymSetContext(self.thisprocesshandle, IMAGEHLP.PIMAGEHLP_STACK_FRAME(c), nil);
SES(self.thisprocesshandle, 0, nil, es2address, self);
self.extraSymbolData.filledin:=true;
freemem(c);
end;
end;
{$ENDIF}
end;
{$ifdef windows}
function ES(pSymInfo:PSYMBOL_INFO; SymbolSize:ULONG; UserContext:pointer):BOOL;stdcall;
var
self: TSymbolloaderthread;
s: string;
sym: PCESymbolInfo;
ExtraSymbolData: TExtraSymbolData;
begin
if symbolsize>64*1024 then
symbolsize:=64*1024;
result:=true;
if pSymInfo.NameLen=0 then
exit;
s:=pchar(@pSymInfo.Name);
self:=TSymbolloaderthread(UserContext);
self.processThreadEvents;
if self.currentModuleIsNotStandard then
s:='_'+s;
if TSymTagEnum(pSymInfo.Tag)=SymTagFunction then
begin
extraSymbolData:=TExtraSymbolData.create;
self.symbollist.AddExtraSymbolData(extraSymbolData);
extraSymbolData.symboladdress:=pSymInfo.Address;
//fill the rest in later
end
else
extraSymbolData:=nil;
if (SYMFLAG_FORWARDER and pSymInfo.Flags)<>0 then
begin
extraSymbolData:=TExtraSymbolData.create;
self.symbollist.AddExtraSymbolData(extraSymbolData);
extraSymbolData.symboladdress:=pSymInfo.Address;
extraSymbolData.forwarder:=true;
end;
if self.pdbonly then
if self.symbollist.FindSymbol(self.currentModuleName+'.'+s)<>nil then
exit(not self.terminated);
sym:=self.symbollist.AddSymbol(self.currentModuleName, self.currentModuleName+'.'+s, pSymInfo.Address, symbolsize,false, extraSymbolData);
sym:=self.symbollist.AddSymbol(self.currentModuleName, s, pSymInfo.Address, symbolsize,true, extraSymbolData); //don't add it as a address->string lookup , (this way it always shows modulename+symbol)
result:=not self.terminated;
end;
function ET(pSymInfo:PSYMBOL_INFO; SymbolSize:ULONG; UserContext:pointer):BOOL;stdcall;
var s: string;
self: TSymbolloaderthread;
size: qword;
childrencount: integer;
fcp: PTiFindChildrenParams;
i: integer;
name: pwchar;
l: tstringlist;
q: TSQLQuery;
typetype: dword;
typename: string;
typeid: integer;
basetype: integer;
typesymtag: TSymTagEnum;
element: record
name: string;
basetype: DWORD;
typeid: dword;
offset: dword;
bitpos: dword;
tag: TSymTagEnum;
end;
begin
//todo: Add to structure dissect
self:=TSymbolloaderthread(UserContext);
if self.terminated then exit(false);
q:=self.currentSymbolDataBaseQueryObject;
typename:=pchar(@pSymInfo.Name);
typeid:=pSymInfo.TypeIndex;
if SymGetTypeInfo(self.thisprocesshandle, pSymInfo.ModBase, typeid, TI_GET_SYMTAG, @typesymtag) then
begin
case typesymtag of
symtagenum: exit(true);//todo: save the enum values. could be useful for something
symtagudt,SymTagBaseClass,SymTagFriend: ; //this is what we ar elooking for
else
exit(true);
end;
//save this all to a database file
childrencount:=0;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo.ModBase, pSymInfo.TypeIndex, TI_GET_CHILDRENCOUNT, @childrencount);
if childrencount>0 then
begin
size:=0;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo.ModBase, pSymInfo.TypeIndex, TI_GET_LENGTH, @size);
if size>0 then
begin
//children and size. it's a structure
q.sql.text:='select * from structures where moduleid=:moduleid and typeid=:typeid';
q.ParamByName('moduleid').AsInteger:=self.currentmoduleid;
q.ParamByName('typeid').AsInteger:=typeid;
q.Active:=true;
i:=q.RecordCount;
q.Active:=false;
if i>0 then exit(true); //it's possible the same object comes by more than once
q.SQL.Text:='insert into structures(moduleid, typeid, tablename, length) values(:moduleid, :typeid, :tablename, :length)';
q.ParamByName('moduleid').AsInteger:=self.currentmoduleid;
q.ParamByName('typeid').AsInteger:=typeid;
q.ParamByName('tablename').AsString:=typename;
q.ParamByName('length').AsInteger:=size;
q.Prepare;
q.ExecSQL;
fcp:=nil;
getmem(fcp, sizeof(TI_FINDCHILDREN_PARAMS)+childrencount*4);
try
zeromemory(fcp, sizeof(TI_FINDCHILDREN_PARAMS)+childrencount*4);
fcp.Count:=childrencount;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo.ModBase, pSymInfo.TypeIndex, TI_FINDCHILDREN, fcp);
for i:=0 to fcp.count-1 do
begin
name:=nil;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo.ModBase, fcp.ChildId[i], TI_GET_SYMNAME, @name);
if (name<>nil) then
begin
element.name:=name;
LocalFree(PTRUINT(name));
SymGetTypeInfo(self.thisprocesshandle, pSymInfo.ModBase, fcp.ChildId[i], TI_GET_BASETYPE, @element.basetype);
SymGetTypeInfo(self.thisprocesshandle, pSymInfo.ModBase, fcp.ChildId[i], TI_GET_OFFSET, @element.offset);
SymGetTypeInfo(self.thisprocesshandle, pSymInfo.ModBase, fcp.ChildId[i], TI_GET_BITPOSITION, @element.bitpos);
element.typeid:=0;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo.ModBase, fcp.ChildId[i], TI_GET_TYPEID, @element.typeid);
element.tag:=SymTagNull;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo.ModBase, element.typeid, TI_GET_SYMTAG, @element.tag);
q.SQL.Text:='insert into elements(moduleid, typeid, elementnr, elementname, offset, basetype, type, tag) values(:moduleid, :typeid, :elementnr, :elementname, :offset, :basetype, :type, :tag)';
q.ParamByName('moduleid').AsInteger:=self.currentmoduleid;
q.ParamByName('typeid').AsInteger:=typeid;
q.ParamByName('elementnr').AsInteger:=i;
q.ParamByName('elementname').AsString:=element.name;
q.ParamByName('offset').AsInteger:=element.offset;
q.ParamByName('basetype').AsInteger:=element.basetype;
q.ParamByName('type').AsInteger:=element.typeid;
q.ParamByName('tag').AsInteger:=dword(element.tag);
q.Prepare;
q.ExecSQL;
end;
end;
finally
if fcp<>nil then
freememandnil(fcp);
end;
end;
end;
self.processThreadEvents;
end;
result:=true;
end;
procedure TSymbolloaderthread.EnumerateStructures;
var
list: array of record
modulebase: uintptr;
modulepath: string;
modulename: string;
end;
i,j: integer;
usedtempdir: string;
symbolpath: string;
r: boolean;
l: tstringlist;
q: TSQLQuery=nil;
t: TSQLTransaction=nil;
ts: dword;
err: integer;
hasStructInfo: boolean;
begin
if istrainer then exit; //waste of time
if terminated then exit;
try
//structures are not accessed constantly, so instead of storing them in memory, store them in a file instead
symhandler.modulelistMREW.BeginRead;
setlength(list,symhandler.modulelistpos);
for i:=0 to symhandler.modulelistpos-1 do
begin
list[i].modulebase:=symhandler.modulelist[i].baseaddress;
list[i].modulepath:=symhandler.modulelist[i].modulepath;
list[i].modulename:=symhandler.modulelist[i].modulename;
end;
symhandler.modulelistMREW.EndRead;
driverlistmrew.Beginread;
j:=length(list);
setlength(list, length(list)+driverlistpos);
for i:=0 to driverlistpos-1 do
begin
list[j+i].modulebase:=driverlist[i].baseaddress;
list[j+i].modulepath:=driverlist[i].modulepath;
list[j+i].modulename:=driverlist[i].modulename;
end;
driverlistmrew.Endread;
if (length(trim(tempdiralternative))>2) and dontusetempdir then
usedtempdir:=trim(tempdiralternative)
else
usedtempdir:=GetTempDir;
symbolpath:=usedtempdir+'Cheat Engine Symbols'+pathdelim;
ForceDirectory(symbolpath);
InitializeSQLite;
if sqlite3_threadsafe()=0 then exit;
sqlite3_config(SQLITE_CONFIG_SERIALIZED);
SymbolDataBasePath:=symbolpath+'structures.sqlite';
currentSymbolDataBase:=TSQLite3Connection.Create(nil);
currentSymbolDataBase.DatabaseName:=SymbolDataBasePath;
t:=TSQLTransaction.Create(nil);
t.DataBase:=currentSymbolDataBase;
q:=TSQLQuery.Create(nil);
q.DataBase:=currentSymbolDataBase;
q.Transaction:=t;
try
currentSymbolDataBase.Connected:=true;
l:=nil;
try
t.StartTransaction;
l:=tstringlist.create;
currentSymbolDataBase.GetTableNames(l);
if (l.IndexOf('modules')=-1) then
begin
//create the modules table
q.SQL.Text:='create table modules(moduleid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, modulename varchar(255) NOT NULL, timestamp int NOT NULL, UNIQUE (modulename, timestamp))';
q.ExecSQL;
end;
if (l.IndexOf('structures')=-1) then
begin
//create the structures table
q.SQL.Text:='create table structures(moduleid INTEGER NOT NULL, typeid INTEGER NOT NULL, tablename varchar(255) NOT NULL, length INTEGER NOT NULL, PRIMARY KEY (moduleid, typeid))';
q.ExecSQL;
q.SQL.Text:='create index namelookup on structures(moduleid, tablename)';
q.ExecSQL;
end;
if (l.IndexOf('elements')=-1) then
begin
//create the structures table
q.SQL.Text:='create table elements(moduleid INTEGER NOT NULL, typeid INTEGER NOT NULL, elementnr INTEGER NOT NULL, elementname varchar(255) NOT NULL, offset INTEGER, basetype INTEGER, type INTEGER, tag INTEGER, PRIMARY KEY (moduleid, typeid, elementnr))';
q.ExecSQL;
end;
t.Action:=caCommit;
t.EndTransaction;
finally
if l<>nil then
freeandnil(l);
end;
currentSymbolDataBaseTransaction:=t;
currentSymbolDataBaseQueryObject:=q;
for i:=0 to length(list)-1 do
begin
processThreadEvents;
hasStructInfo:=false;
t.action:=caRollback;
t.StartTransaction;
//check if this module is in
ts:=FileAgeUTF8(list[i].modulepath);
q.SQL.Text:='select moduleid from modules where modulename=:modulename and timestamp=:ts';
q.ParamByName('modulename').AsString:=list[i].modulename;
q.ParamByName('ts').AsInteger:=ts;
q.Prepare;
q.Active:=true;
if q.RecordCount=0 then
begin
//add it to the list (if nothing, the rollback will undo this add)
q.Active:=false;
q.SQL.Clear;
q.SQL.text:='INSERT INTO modules (modulename, timestamp) VALUES (:modulename, :ts)';
q.Prepare;
q.ParamByName('modulename').AsString:=list[i].modulename;
q.ParamByName('ts').AsInteger:=ts;
q.ExecSQL;
currentmoduleid:=currentSymbolDataBase.GetInsertID;
r:=SymEnumTypes(self.thisprocesshandle, list[i].modulebase, @ET, self);
if r=true then
hasStructInfo:=true;
end
else
begin
r:=false; //already in the list
hasStructInfo:=true;
currentmoduleid:=q.FieldByName('moduleid').AsInteger;
end;
q.Active:=false;
if r then
t.Action:=caCommit
else
t.Action:=caRollback;
t.EndTransaction;
if terminated then exit;
if hasStructInfo then
begin
symhandler.modulelistMREW.BeginRead;
for j:=0 to symhandler.modulelistpos-1 do
begin
if symhandler.modulelist[j].baseaddress=list[i].modulebase then
begin
symhandler.modulelist[j].hasStructInfo:=true;
symhandler.modulelist[j].databaseModuleID:=currentmoduleid;
break;
end;
end;
symhandler.modulelistMREW.EndRead;
driverlistMREW.BeginRead;
for j:=0 to driverlistpos-1 do
begin
if driverlist[j].baseaddress=list[i].modulebase then
begin
driverlist[j].hasStructInfo:=true;
driverlist[j].databaseModuleID:=currentmoduleid;
break;
end;
end;
driverlistMREW.EndRead;
end;
end;
finally
if q<>nil then
freeandnil(q);
if t<>nil then
freeandnil(t);
if currentSymbolDataBase<>nil then
freeandnil(currentSymbolDataBase);
end;
except
on e: exception do
begin
outputdebugstring(pchar('TSymbolloaderthread.EnumerateStructures:'+e.message));
end;
end;
hasEnumeratedAllStructures:=true;
end;
function EM(ModuleName:PSTR; BaseOfDll:dword64; UserContext:pointer):bool;stdcall;
var
self: TSymbolloaderthread;
mi: tmoduleinfo;
i: integer;
begin
result:=false;
{$IFNDEF UNIX}
self:=TSymbolloaderthread(UserContext);
self.CurrentModulename:=ModuleName;
if symhandler.getmodulebyaddress(baseofdll, mi) then
self.currentModuleIsNotStandard:=ProcessHandler.is64Bit<>mi.is64bitmodule
else
self.currentModuleIsNotStandard:=false; //whatever...
//
self.processThreadEvents;
if self.pdbonly then //only files with a PDB
begin
for i:=0 to length(self.modulelist.withdebuginfo)-1 do
if self.ModuleList.withdebuginfo[i].BaseOfImage=baseofdll then
begin
result:=(self.terminated=false) and (SymEnumSymbols(self.thisprocesshandle, baseofdll, nil, @ES, self));
break;
end;
end
else
result:=(self.terminated=false) and (SymEnumSymbols(self.thisprocesshandle, baseofdll, nil, @ES, self));
//mark this module as loaded
self.processThreadEvents;
if self.terminated then exit;
if symhandler=nil then exit;
symhandler.markModuleAsLoaded(baseofdll);
inc(self.enumeratedModules);
self.fprogress:=ceil((self.enumeratedModules / self.modulecount) * 100);
{$ENDIF}
end;
{$endif}
function TSymbolloaderthread.NetworkES(modulename: string; symbolname: string; address: ptruint; size: integer; secondary: boolean): boolean;
begin
//if highestsymboladdress<address then
{
if symbolname='_end' then
begin
highestsymboladdress:=address;
highestsymbol:=symbolname;
end;
}
if (GetCurrentThreadID=MainThreadID) and (waitingfrm<>nil) then exit(false);
symbollist.AddSymbol(modulename, modulename+'.'+symbolname, Address, size, secondary);
symbollist.AddSymbol(modulename, symbolname, Address, size,true);
result:=not terminated;
end;
function TSymbolloaderthread.getAddressFromSymbol(symbol: string): ptruint;
//called from other threads, NOT the symbolloader thread
var afste: TGetAddressFromSymbolThreadEvent;
begin
if GetCurrentThreadId=self.ThreadID then raise exception.create('Do not call getAddressFromSymbol from inside the symbolloaderthread');
if skipAllSymbols then exit(0);
if (skipList<>nil) and (skipList.Values[symbol]) then exit(0);
if (GetCurrentThreadID=MainThreadID) and (waitingfrm<>nil) then exit(0);
if trim(symbol)='' then exit(0);
if (symbol[1] in ['#','(']) then exit(0);
if (pos(' ',symbol)>0) then exit(0);
if (symbol='DWORD') or (symbol='PTR') then exit(0);
//queue an getAddressFromSymbol event and wait for the result
afste:=TGetAddressFromSymbolThreadEvent.create(owner);
afste.symbolname:=symbol;
symbolloaderthreadeventqueueCS.enter;
symbolloaderthreadeventqueue.add(afste);
symbolloaderthreadeventqueueCS.leave;
symbolloaderthreadeventevent.SetEvent;
afste.waittilldone;
result:=afste.address;
if afste.abandoned=false then
begin
symbolloaderthreadeventqueueCS.enter;
symbolloaderthreadeventqueue.Remove(afste);
freeandnil(afste);
symbolloaderthreadeventqueueCS.leave;
end;
end;
function TSymbolloaderthread.getSymbolFromAddress(address: ptruint): string;
//called from other threads, NOT the symbolloader thread
var sfate: TGetSymbolFromAddressThreadEvent;
begin
if GetCurrentThreadId=self.ThreadID then raise exception.create('Do not call getAddressFromSymbol from inside the symbolloaderthread');
if skipAddressToSymbol then exit('');
if address<$10000 then exit('');
//queue an GetSymbolFromAddress event and wait for the result
sfate:=TGetSymbolFromAddressThreadEvent.create(owner);
sfate.address:=address;
symbolloaderthreadeventqueueCS.enter;
symbolloaderthreadeventqueue.add(sfate);
symbolloaderthreadeventqueueCS.leave;
symbolloaderthreadeventevent.SetEvent;
sfate.waittilldone;
result:=sfate.symbolname;
if sfate.abandoned=false then
begin
symbolloaderthreadeventqueueCS.enter;
symbolloaderthreadeventqueue.Remove(sfate);
freeandnil(sfate);
symbolloaderthreadeventqueueCS.leave;
end;
end;
procedure TSymbolloaderthread.getStructureFromName(structname: string; elements: tstringlist);
var gsfnte: TGetStructureFromNameThreadEvent;
begin
if GetCurrentThreadId=self.ThreadID then raise exception.create('Do not call getAddressFromSymbol from inside the symbolloaderthread');
if structname='' then exit;
if elements=nil then exit;
gsfnte:=TGetStructureFromNameThreadEvent.create(owner);
gsfnte.symbolname:=structname;
gsfnte.structure:=elements;
symbolloaderthreadeventqueueCS.enter;
symbolloaderthreadeventqueue.add(gsfnte);
symbolloaderthreadeventqueueCS.leave;
symbolloaderthreadeventevent.SetEvent;
gsfnte.waittilldone;
if gsfnte.abandoned=false then
begin
symbolloaderthreadeventqueueCS.enter;
symbolloaderthreadeventqueue.Remove(gsfnte);
freeandnil(gsfnte);
symbolloaderthreadeventqueueCS.leave;
end;
end;
procedure TSymbolloaderthread.getStructureList(l: Tstringlist);
var gslte: TGetStructureListThreadEvent;
begin
if GetCurrentThreadId=self.ThreadID then raise exception.create('Do not call getAddressFromSymbol from inside the symbolloaderthread');
if l=nil then exit;
gslte:=TGetStructureListThreadEvent.create(owner);
gslte.list:=l;
symbolloaderthreadeventqueueCS.enter;
symbolloaderthreadeventqueue.add(gslte);
symbolloaderthreadeventqueueCS.leave;
symbolloaderthreadeventevent.SetEvent;
gslte.waittilldone;
if gslte.abandoned=false then
begin
symbolloaderthreadeventqueueCS.enter;
symbolloaderthreadeventqueue.Remove(gslte);
freeandnil(gslte);
symbolloaderthreadeventqueueCS.leave;
end;
end;
{$ifdef windows}
function symbolsearch(pSymInfo: PSYMBOL_INFO; SymbolSize: ULONG; UserContext: Pointer): BOOL; stdcall;
begin
if (pSymInfo^.NameLen<>0) and (pSymInfo^.Address<>0) then
begin
pptruint(UserContext)^:=pSymInfo^.address;
result:=false;
end
else
result:=true;
end;
{$endif}
function GSLET(pSymInfo:PSYMBOL_INFO; SymbolSize:ULONG; UserContext:pointer):BOOL;stdcall;
var list: TStringlist;
begin
list:=TStringList(UserContext);
list.AddObject(pchar(@pSymInfo.Name[0]), tobject(psyminfo.TypeIndex));
result:=true;
end;
procedure TSymbolloaderthread.teGetStructureList(list: tstringlist);
var i: integer;
begin
//faster than waiting for all structures to get fully dissected
{$ifdef windows}
if structureList=nil then
begin
//get the list
structurelist:=tstringlist.create;
for i:=0 to length(modulelist.withdebuginfo)-1 do
begin
if SymEnumTypes(self.thisprocesshandle, modulelist.withdebuginfo[i].BaseOfImage, @GSLET, list) then //makes counting possible
asm
nop
end;
end;
structurelist.Assign(list);
end
else
list.assign(structurelist);
{$endif}
end;
procedure TSymbolloaderthread.teGetStructureFromName(name: string; structure: TStringList);
{$ifdef windows}
var
hasModuleSpecifier: boolean;
pSymInfo: PSYMBOL_INFO;
i,j: integer;
modulename: string;
err: integer;
base: qword;
pname: pchar;
typeid: ulong;
childrencount: dword;
size: ULONG64;
fcp: PTiFindChildrenParams;
ename: string;
wname: pwidechar;
element: TDBElementInfo;
{$endif}
begin
{$ifdef windows}
hasmodulespecifier:=false;
getmem(pSymInfo,sizeof(TSYMBOL_INFO)+100);
for i:=1 to length(name)-1 do
begin
if name[i]='.' then
begin
name[i]:='!';
hasModuleSpecifier:=true;
end;
end;
//exact name
if hasmodulespecifier then
begin
i:=pos('!',name);
modulename:=copy(name, 1,i-1);
name:=copy(name, i+1);
end;
for i:=0 to length(modulelist.withdebuginfo)-1 do
begin
if (hasmodulespecifier=false) or (modulelist.withdebuginfo[i].ModuleName=modulename) then
begin
base:=modulelist.withdebuginfo[i].BaseOfImage;
pname:=StrNew(pchar(name));
zeromemory(pSymInfo, sizeof(TSYMBOL_INFO)+100);
pSymInfo^.SizeOfStruct:=sizeof(TSYMBOL_INFO);
pSymInfo^.MaxNameLen:=99;
if SymGetTypeFromName(thisprocesshandle, base, pname, pointer(pSymInfo)) then
begin
typeid:=pSymInfo^.TypeIndex;
childrencount:=0;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo^.ModBase, pSymInfo^.TypeIndex, TI_GET_CHILDRENCOUNT, @childrencount);
if childrencount>0 then
begin
size:=0;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo^.ModBase, pSymInfo^.TypeIndex, TI_GET_LENGTH, @size);
if size>0 then
begin
getmem(fcp, sizeof(TI_FINDCHILDREN_PARAMS)+childrencount*4);
zeromemory(fcp, sizeof(TI_FINDCHILDREN_PARAMS)+childrencount*4);
fcp.Count:=childrencount;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo^.ModBase, pSymInfo^.TypeIndex, TI_FINDCHILDREN, fcp);
for j:=0 to fcp.count-1 do
begin
wname:=nil;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo^.ModBase, fcp.ChildId[j], TI_GET_SYMNAME, @wname);
if wname<>nil then
begin
ename:=wname;
LocalFree(PTRUINT(wname));
element:=TDBElementInfo.Create;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo^.ModBase, fcp.ChildId[j], TI_GET_BASETYPE, @element.basetype);
SymGetTypeInfo(self.thisprocesshandle, pSymInfo^.ModBase, fcp.ChildId[j], TI_GET_OFFSET, @element.offset);
element.typeid:=0;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo^.ModBase, fcp.ChildId[j], TI_GET_TYPEID, @element.typeid);
element.tag:=SymTagNull;
SymGetTypeInfo(self.thisprocesshandle, pSymInfo^.ModBase, element.typeid, TI_GET_SYMTAG, @element.tag);
if element.tag=SymTagPointerType then
element.vartype:=vtPointer
else
begin
case TBasicType(element.basetype) of
btChar: element.vartype:=vtString;
btWChar: element.vartype:=vtUnicodeString;
btInt: element.vartype:=vtDword;
btUInt: element.vartype:=vtDword;
btFloat: element.vartype:=vtSingle;
btBCD: element.vartype:=vtByte;
btBool: element.vartype:=vtByte;
btLong: element.vartype:=vtQword;
btULong: element.vartype:=vtQword;
btCurrency: element.vartype:=vtDword;
btDate: element.vartype:=vtDword;
btVariant: element.vartype:=vtDword;
btComplex: element.vartype:=vtDword;
btBit: element.vartype:=vtDword;
btBSTR:element.vartype:=vtString;
btHresult: element.vartype:=vtDword;
else
begin
element.vartype:=vtDword;
end;
end;
end;
structure.AddObject(ename, element);
end;
end;
freememandnil(fcp);
end;
end;
break;
end
else
begin
err:=getlasterror;
if err=0 then beep;
end;
end;
end;
freemem(pSymInfo);
{$endif}
end;
procedure TSymbolloaderthread.processThreadEvents;
var
te: TSymbolLoaderThreadEvent;
symbol: PSYMBOL_INFO;
i: integer;
disp: dword64;
a: ptruint;
mi: TModuleInfo;
queueindex: integer;
hasmodulespecifier: boolean;
modulename: string;
skip: boolean;
SearchResult: ptruint;
{$ifdef darwin}
sym: CSSymbolRef;
symname: pchar;
range: csRange;
{$endif}
begin
// sleep(5000);
if symbolloaderthreadeventqueue.count>0 then
begin
symbolloaderthreadeventqueueCS.enter;
try
if symbolloaderthreadeventqueue.Count>0 then
begin
te:=nil;
for i:=0 to symbolloaderthreadeventqueue.count-1 do
begin
if TSymbolLoaderThreadEvent(symbolloaderthreadeventqueue[i]) is TGetSymbolFromAddressThreadEvent then
begin
te:=TSymbolLoaderThreadEvent(symbolloaderthreadeventqueue[i]);
queueindex:=i;
break;
end;
end;
if te=nil then
begin
te:=TSymbolLoaderThreadEvent(symbolloaderthreadeventqueue[0]);
queueindex:=0;
end;
end;
finally
symbolloaderthreadeventqueueCS.leave;
end;
if te<>nil then
begin
getmem(symbol,sizeof(TSYMBOL_INFO)+256);
ZeroMemory(symbol, sizeof(TSYMBOL_INFO)+256);
symbol^.MaxNameLen:=255;
symbol^.SizeOfStruct:=sizeof(TSYMBOL_INFO);
//handle it based on the type
if te is TGetAddressFromSymbolThreadEvent then
begin
//address from symbol
skip:=length(te.symbolname)<=1;
hasmodulespecifier:=false;
for i:=1 to length(te.symbolname)-1 do
begin
if te.symbolname[i]='.' then
begin
te.symbolname[i]:='!';
hasModuleSpecifier:=true;
end;
if te.symbolname[i]=' ' then //invalid
skip:=true;
end;
if (skip=false) and (notfoundlist<>nil) then
skip:=notfoundlist.Values[te.symbolname];
if (not skip) then
begin
{$ifdef darwin}
if not CSIsNull(cs) then
begin
sym:=CSSymbolicatorGetSymbolWithNameAtTime(cs, pchar(te.symbolname),kCSNow);
if not CSIsNull(sym) then
begin
range:=CSSymbolGetRange(sym);
te.address:=range.location;
end;
end;
{$endif}
{$ifdef windows}
if assigned(symsearch) and (length(modulelist.withdebuginfo)+length(modulelist.withoutdebuginfo)>5) then
begin
searchresult:=0;
if hasModuleSpecifier then
symsearch(thisprocesshandle,0,0,0,pchar(te.symbolname),0,SymbolSearch,@searchresult,0)
else
begin
//scan modules without PDB's first
for i:=0 to length(modulelist.withoutdebuginfo)-1 do
begin
symsearch(thisprocesshandle, modulelist.withoutdebuginfo[i].BaseOfImage,0,0,pchar(te.symbolname),0,SymbolSearch,@searchresult,0);
if searchresult<>0 then break;
if te.abandoned then break;
end;
if (searchresult=0) and (searchpdb) then //try the ones with debug info
begin
for i:=0 to length(modulelist.withdebuginfo)-1 do
begin
symsearch(thisprocesshandle, modulelist.withdebuginfo[i].BaseOfImage,0,dword(SymTagFunction),pchar(te.symbolname),0,SymbolSearch,@searchresult,8);
if searchresult<>0 then break;
if te.abandoned then break;
end;
end;
end;
if searchresult<>0 then
te.address:=SearchResult
else
begin
if notfoundlist=nil then
notfoundlist:=TStringMap.create(false);
notfoundlist.add(te.symbolname);
end;
end
else
begin
if SymFromName(thisprocesshandle, pchar(te.symbolname), symbol) then
te.address:=symbol.Address;
end;
{$endif}
end;
end
else
if te is TGetSymbolFromAddressThreadEvent then
begin
//symbol from address
{$ifdef darwin}
if not CSIsNull(cs) then
begin
sym:=CSSymbolicatorGetSymbolWithAddressAtTime(cs, te.address,kCSNow);
if not CSIsNull(sym) then
begin
symname:=CSSymbolGetName(sym);
if (symname<>nil) and (symname[0]<>#0) then
begin
if symhandler.getmodulebyaddress(te.address,mi) then
te.symbolname:=ExtractFileNameOnly(mi.modulename)+'.';
te.symbolname:=te.symbolname+symname;
range:=CSSymbolGetRange(sym);
if range.location<te.address then
te.symbolname:=te.symbolname+'+'+inttohex(te.address-range.location,1);
end;
end;
end;
{$endif}
{$ifdef windows}
symbol.address:=te.address;
disp:=0;
if SymFromAddr(thisprocesshandle, te.address, @disp, symbol) then
if symbol^.NameLen>0 then
begin
if symhandler.getmodulebyaddress(te.address,mi) then
te.symbolname:=ExtractFileNameOnly(mi.modulename)+'.';
te.symbolname:=te.symbolname+pchar(@symbol^.Name);
if disp<>0 then
te.symbolname:=te.symbolname+'+'+inttohex(disp,1);
end;
{$endif}
end
else
if te is TGetStructureFromNameThreadEvent then
begin
teGetStructureFromName(te.symbolname, TGetStructureFromNameThreadEvent(te).structure);
end
else
if te is TGetStructureListThreadEvent then
teGetStructureList(TGetStructureListThreadEvent(te).list);
freemem(symbol);
symbolloaderthreadeventqueueCS.enter;
queueindex:=symbolloaderthreadeventqueue.IndexOf(te);
if queueindex<>-1 then
begin
symbolloaderthreadeventqueue.Delete(queueindex);
if te.abandoned then
te.free
else
te.done.SetEvent;
end;
symbolloaderthreadeventqueueCS.leave;
end;
end;
end;
{$ifdef darwin}
var count: integer;
function ES(si: CSSymbolIterator; sym: CSSymbolRef): integer; cdecl;
var
self: TSymbolloaderthread;
symname: pchar;
range: CSRange;
begin
self:=si.param;
symname:=CSSymbolGetName(sym);
if symname=nil then exit;
if symname[0]=#0 then exit;
range:=CSSymbolGetRange(sym);
self.symbollist.AddSymbol(self.currentModuleName, self.currentModuleName+'.'+symname, range.location, range.length);
self.symbollist.AddSymbol(self.currentModuleName, symname, range.location, range.length,true); //don't add it as a address->string lookup , (this way it always shows modulename.symbol)
result:=0;
self.processThreadEvents;
end;
function EM(mi: CSSymbolOwnerIterator; so: CSSymbolOwnerRef): integer; cdecl;
var
self: TSymbolloaderthread;
si: CSSymbolIterator;
begin
self:=mi.param;
self.currentModuleName:=CSSymbolOwnerGetName(so);
si:=createIterator(@es, self);
CSSymbolOwnerforEachSymbol(so, si);
freeIterator(si);
self.processThreadEvents;
result:=0;
end;
function TSymbolloaderthread.loadSymbolsWithSymbolicator: boolean;
var mi: CSSymbolOwnerIterator;
begin
result:=false;
cs:=CSSymbolicatorCreateWithPid(thisprocessid);
processThreadEvents;
if CSIsNull(cs)=false then
begin
mi:=createIterator(@em, self);
CSSymbolicatorForeachSymbolOwnerAtTime(cs, kCSNow, mi);
freeIterator(mi);
result:=true;
end;
end;
{$endif}
procedure TSymbolloaderthread.execute;
type
TModInfo=record
baseaddress: qword;
size: qword;
end;
PModInfo=^TModInfo;
var sp: pchar;
s: string;
temp: string;
c: TCEConnection;
mpl: Tstringlist;
i,j: integer;
dotNetdomains: TDotNetDomainArray;
dotNetmodules: TDotNetModuleArray;
d: dword;
modinfo: PModInfo;
needstoenumodules: boolean;
b: byte;
ar: ptruint;
begin
debugpart:=0;
try
try
c:=getConnection;
SymbolsLoaded:=false;
symbollist.clear;
//add the sections of modules to the symbollist as string to address lookup only
owner.modulelistMREW.Beginread;
for i:=0 to owner.modulelistpos-1 do
begin
for j:=0 to length(owner.modulelist[i].sections)-1 do
begin
s:=owner.modulelist[i].sections[j].name;
if s[1]<>'.' then
s:='.'+s;
symbollist.AddSymbol('',owner.modulelist[i].modulename+s, owner.modulelist[i].sections[j].address, owner.modulelist[i].sections[j].size,true);
end;
end;
owner.modulelistMREW.Endread;
sectionsLoaded:=true;
{$IFDEF windows}
owner.dotnetModuleSymbolListMREW.Beginwrite; //lock the list
try
for i:=0 to length(owner.dotnetModuleSymbolList)-1 do
owner.dotnetModuleSymbolList[i].symbollist.Free;
setlength(owner.dotnetModuleSymbolList,0);
finally
owner.dotnetModuleSymbolListMREW.Endwrite;
end;
if trim(searchpath)='' then
begin
s:='';
temp:=GetEnvironmentVariable('_NT_SYMBOL_PATH' );
if temp<>'' then
s:=temp+';';
temp:=GetEnvironmentVariable('_NT_ALTERNATE_SYMBOL_PATH' );
if temp<>'' then
s:=s+temp+';';
temp:=getProcessPathFromProcessID(thisprocessid);
if temp<>'' then
s:=s+ExtractFilePath(temp);
end
else
{$ENDIF}
s:=searchpath;
sp:=pchar(s);
if c=nil then //local
begin
{$IFDEF windows}
if thisprocessid<>GetCurrentProcessId then //I'm quite sure ce isn't written in .net
begin
if owner.dotNetDataCollector.Attached then
begin
//enum the modulelist
setlength(dotNetdomains,0);
owner.dotNetDataCollector.EnumDomains(dotNetdomains);
for i:=0 to length(dotNetdomains)-1 do
begin
if (i=0) and (not terminated) then //get more info
begin
setlength(dotNetmodules,0);
if not terminated then
begin
owner.dotNetDataCollector.EnumModuleList(dotNetdomains[i].hDomain, dotNetmodules);
//still here, add the modules
owner.dotnetModuleSymbolListMREW.Beginwrite;
setlength(owner.dotnetModuleSymbolList, length(dotNetmodules));
for j:=0 to length(dotNetmodules)-1 do
begin
owner.dotnetModuleSymbolList[j].modulename:=dotNetmodules[j].name;
owner.dotnetModuleSymbolList[j].modulebase:=dotNetmodules[j].baseaddress;
owner.dotnetModuleSymbolList[j].symbollist:=TSymbolListHandler.create;
end;
end;
owner.dotnetModuleSymbolListMREW.Endwrite;
end;
//cleanup
owner.dotNetDataCollector.ReleaseObject(dotNetdomains[i].hDomain);
end;
//enumerate the first module
if (not terminated) and (length(dotNetmodules)>0) then
begin
owner.EnumDotNetModule(dotNetmodules[0], owner.dotnetModuleSymbolList[0].symbollist);
owner.dotNetDataCollector.ReleaseObject(dotNetmodules[0].hModule); //free this one already
end;
end;
end
else
begin
thisprocesshandle:=OpenProcess(ifthen(GetSystemType<=6,$1f0fff, process_all_access),false,thisprocessid);
end;
debugpart:=1;
if thisprocesshandle<>0 then
begin
symbolloaderthreadcs.Enter; //needed so selfsymbolhandlerdoesnb't cause issues
try
//get the export symbols first
d:=symgetoptions;
d:=d or SYMOPT_CASE_INSENSITIVE or SYMOPT_INCLUDE_32BIT_MODULES;
d:=d and not SYMOPT_DEFERRED_LOADS;
symsetoptions(d);
SymbolsLoaded:=SymInitialize(thisprocesshandle, pchar(''), true);
if symbolsloaded=false then
begin
SymbolsLoaded:=SymInitialize(thisprocesshandle, pchar(''), false);
needstoenumodules:=true;
end
else
begin
needstoenumodules:=false;
end;
if symbolsloaded then
begin
symbolscleaned:=false;
if kernelsymbols then LoadDriverSymbols(false);
LoadDLLSymbols(false, needstoenumodules);
modulecount:=length(modulelist.withdebuginfo)+length(modulelist.withoutdebuginfo)*2;
if modulecount=0 then modulecount:=1;
enumeratedModules:=0;
if terminated then exit;
DLLSymbolsLoaded:=true;
processThreadEvents;
SymEnumerateModules64(thisprocesshandle, @EM, self );
processThreadEvents;
apisymbolsloaded:=true;
SymCleanup(thisprocesshandle);
symbolscleaned:=true;
end;
if terminated then exit;
if owner.dotNetDataCollector.Attached then
begin
fprogress:=50;
//Enumerate the other .net module methods
for i:=1 to length(dotNetmodules)-1 do
begin
if not terminated then
begin
owner.EnumDotNetModule(dotNetmodules[i], owner.dotnetModuleSymbolList[i].symbollist);
owner.dotNetDataCollector.ReleaseObject(dotNetmodules[i].hModule);
end;
end;
end;
dotnetsymbolsloaded:=true;
//enumerate the extended debug symbols
setlength(modulelist.withdebuginfo,0);
setlength(modulelist.withoutdebuginfo,0);
if terminated then exit;
d:=symgetoptions;
d:=d or SYMOPT_CASE_INSENSITIVE or SYMOPT_INCLUDE_32BIT_MODULES;
d:=d or SYMOPT_DEFERRED_LOADS;
symsetoptions(d);
SymbolsLoaded:=false; //SymInitialize(thisprocesshandle, sp, true);
if symbolsloaded=false then
begin
SymbolsLoaded:=SymInitialize(thisprocesshandle, sp, false);
needstoenumodules:=true;
end
else
needstoenumodules:=false;
if terminated then exit;
if symbolsloaded then
begin
symbolscleaned:=false;
debugpart:=2;
//symsetoptions(symgetoptions or SYMOPT_CASE_INSENSITIVE);
if kernelsymbols then LoadDriverSymbols(true);
LoadDLLSymbols(true, needstoenumodules);
processThreadEvents;
//enumerate the basic data from the symbols
//enumeratedModules:=0;
pdbonly:=true;
SymEnumerateModules64(thisprocesshandle, @EM, self );
pdbsymbolsloaded:=true;
if terminated then exit;
processThreadEvents;
debugpart:=3;
isloading:=false;
while symbolloaderthreadeventqueue.Count>0 do
processThreadEvents;
debugpart:=4;
if not terminated then
EnumerateExtendedDebugSymbols;
debugpart:=5;
if not terminated then
EnumerateStructures;
debugpart:=6;
if (targetself=false) and (length(modulelist.withdebuginfo)>0) then
begin
while not terminated do
begin
symbolloaderthreadeventevent.waitfor(100);
while symbolloaderthreadeventqueue.Count>0 do
processThreadEvents;
if ReadProcessMemory(processhandle, amodulebase, @b,1,ar)=false then //release the debug symbols when the process terminates
begin
break;
end;
end;
end;
debugpart:=7;
Symcleanup(thisprocesshandle);
symbolscleaned:=true;
debugpart:=8;
end
else
error:=true;
finally
symbolloaderthreadcs.Leave;
end;
end
else
begin
symbolscleaned:=true;
isloading:=false;
DLLSymbolsLoaded:=true;
apisymbolsloaded:=true;
dotnetsymbolsloaded:=true;
end;
{$endif}
{$ifdef darwin}
if loadsymbolswithsymbolicator=false then
begin
//do it manually
end;
symbolscleaned:=true;
isloading:=false;
while symbolloaderthreadeventqueue.Count>0 do
processThreadEvents;
DLLSymbolsLoaded:=true;
apisymbolsloaded:=true;
dotnetsymbolsloaded:=true;
{$endif}
end
else
begin
//networked
//get a list of module paths ,fetch the symbols from those modules (if they are indeed modules) and then store them
mpl:=tstringlist.create;
self.owner.modulelistMREW.Beginread;
try
for i:=0 to self.owner.modulelistpos-1 do
begin
getmem(modinfo, sizeof(TModInfo));
modinfo^.baseaddress:=self.owner.modulelist[i].baseaddress;
modinfo^.size:=self.owner.modulelist[i].basesize;
mpl.AddObject(self.owner.modulelist[i].modulepath, tobject(modinfo));
end;
finally
self.owner.modulelistMREW.Endread;
end;
modulecount:=mpl.count;
if modulecount=0 then modulecount:=1;
enumeratedModules:=0;
for i:=0 to modulecount-1 do
begin
modinfo:=pmodinfo(mpl.Objects[i]);
c.enumSymbolsFromFile(self.owner.modulelist[i].modulepath, modinfo^.baseaddress, NetworkES);
inc(enumeratedModules);
fprogress:=ceil((i/modulecount)*100);
freememandnil(modinfo);
end;
mpl.free;
end;
finally
isloading:=false;
if symbolscleaned=false then
begin
{$ifdef windows}
symbolloaderthreadcs.Enter;
try
Symcleanup(thisprocesshandle);
finally
symbolloaderthreadcs.Leave;
end;
{$endif}
symbolscleaned:=true;
end;
owner.ReinitializeUserdefinedSymbolList;
if not terminated then
begin
//OutputDebugString('Symbolhandler: sync: Calling finishedloadingsymbols');
Queue(finishedloadingsymbols);
//synchronize(finishedloadingsymbols);
//OutputDebugString('after finishedloadingsymbols');
end
else
OutputDebugString('Symbolhandler was terminated. Not going to sync');
end;
//OutputDebugString('Symbol loader thread has finished without errors');
except
outputdebugstring(rsSymbolloaderthreadHasCrashed);
end;
isloading:=false;
end;
destructor TSymbolloaderthread.destroy;
begin
//close the symbol handler for this processhandle
terminate;
waitfor;
if symbolloaderthreadeventevent<>nil then
freeandnil(symbolloaderthreadeventevent);
freeandnil(symbolloaderthreadeventqueue);
freeandnil(symbolloaderthreadeventqueueCS);
if skiplist<>nil then
freeandnil(skiplist);
if notfoundlist<>nil then
freeandnil(notfoundlist);
inherited destroy;
end;
constructor TSymbolloaderthread.create(owner: TSymhandler; targetself, CreateSuspended: boolean);
var
_processid: dword;
_processhandle: thandle;
begin
self.owner:=owner;
self.targetself:=targetself;
{$ifdef windows}
if targetself then
begin
_processid:=getcurrentprocessid;
_processhandle:=getcurrentprocess;
end
else
{$endif}
begin
_processid:=processhandlerunit.ProcessID;
_processhandle:=processhandlerunit.ProcessHandle;
end;
symbolloaderthreadeventevent:=tevent.Create(nil,false,false,'');
thisprocesshandle:=_processhandle;
thisprocessid:=_processid;
isloading:=true;
SymbolsLoaded:=false;
symbolloaderthreadeventqueue:=Tlist.Create;
symbolloaderthreadeventqueueCS:=TCriticalSection.Create;
driverlistMREW:=TMultiReadExclusiveWriteSynchronizer.Create;
inherited create(CreateSuspended);
end;
//-------------------Symhandler-----------------------
procedure TSymhandler.tokenize(s: string; var tokens: TTokens);
{
Just a tokenizer for simple address specifiers
}
var
i,j: integer;
last: integer;
t: string;
inQuote: boolean;
inroundbrace: integer;
begin
last:=1;
inQuote:=false;
inroundbrace:=0;
for i:=1 to length(s) do
begin
if (s[i] in ['"', '[', ']', '+', '-', '*','(',')']) then
begin
if s[i]='"' then
begin
if not inQuote then
last:=i+1;
inQuote:=not inquote;
end;
if not inQuote then
begin
if s[i]=')' then
dec(inroundbrace);
if inroundbrace=0 then
begin
t:=trim(copy(s, last, i-last));
if t<>'' then
begin
setlength(tokens,length(tokens)+1);
tokens[length(tokens)-1]:=t;
end;
//store seperator char as well, unless it's "
if not (s[i] = '"') then
begin
setlength(tokens,length(tokens)+1);
tokens[length(tokens)-1]:=s[i];
end;
if s[i]='(' then
inc(inroundbrace);
last:=i+1;
end;
end;
end;
end;
//last part
t:=trim(copy(s, last,length(s)));
if t<>'' then
begin
setlength(tokens,length(tokens)+1);
tokens[length(tokens)-1]:=t;
end;
end;
function TSymHandler.isTypeToken(token: string; var nextTokenType: TSymHandlerTokenType): boolean;
begin
result:=false;
token:=uppercase(token);
if length(token)>0 then
begin
//(BYTE), (WORD), (DWORD), (QWORD)/(UINT64), (CHAR), (SHORT),(LONG),(LONGLONG),(INT64)
case token[1] of
'B' : if token='BYTE' then begin nextTokenType:=ttByte; exit(true); end;
'C' : if token='CHAR' then begin nextTokenType:=ttShortInt; exit(true); end;
'D' : if token='DWORD' then begin nextTokenType:=ttDword; exit(true); end;
'I' : if token='INT64' then
begin
nextTokenType:=ttInt64;
exit(true);
end;
'L' : if token='LONG' then
begin
nextTokenType:=ttLongint;
exit(true);
end
else
if token='LONGLONG' then
begin
nextTokenType:=ttInt64;
exit(true);
end;
'Q' : if token='QWORD' then begin nextTokenType:=ttQword; exit(true); end;
'U' : if token='UINT64' then begin nextTokenType:=ttQword; exit(true); end;
'S' : if token='SHORT' then begin nextTokenType:=ttSmallint; exit(true); end;
'W' : if token='WORD' then begin nextTokenType:=ttWord; exit(true); end;
end;
end;
end;
function TSymHandler.getExtendedDataProgress: integer;
begin
result:=0;
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
begin
if symbolloaderthread.debugpart>40000 then
result:=symbolloaderthread.ExtendedDebugSymbolProgress;
end;
symbolloadervalid.Endread;
end;
function TSymHandler.isloadingExtendedData: boolean;
begin
result:=false;
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
result:=symbolloaderthread.debugpart>4000;
symbolloadervalid.Endread;
end;
function TSymHandler.isParsingStructures: boolean;
begin
result:=false;
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
result:=symbolloaderthread.debugpart=5;
symbolloadervalid.Endread;
end;
function TSymHandler.getProgress: integer;
begin
result:=0;
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
begin
if symbolloaderthread.Finished then
result:=100
else
result:=symbolloaderthread.fprogress;
end;
symbolloadervalid.Endread;
end;
function TSymhandler.geterror:boolean;
begin
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
result:=symbolloaderthread.error
else
result:=false; //no error
symbolloadervalid.endread;
end;
function TSymhandler.getDotNetDataCollector: TDotNetPipe;
begin
{$IFDEF windows}
result:=dotNetDataCollector;
{$else}
result:=nil;
{$endif}
end;
function TSymhandler.getDotNetAccess: boolean;
begin
{$IFDEF windows}
result:=dotNetDataCollector.Attached;
{$else}
result:=false;
{$ENDIF}
end;
function TSymhandler.getDotNetObjectList: TDOTNETObjectList;
begin
{$IFDEF windows}
result:=dotNetDataCollector.EnumAllObjects;
{$else}
result:=nil;
{$ENDIF}
end;
procedure TSymhandler.freeDotNetObjectList(list: TDOTNETObjectList);
begin
{$IFDEF windows}
dotNetDataCollector.freeNETObjectList(list);
{$ENDIF}
end;
function TSymhandler.getisloaded:boolean;
begin
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
result:=not symbolloaderthread.isloading
else
result:=false;
symbolloadervalid.endread;
end;
procedure TSymhandler.RegisterUserdefinedSymbolCallback(callback: TUserdefinedSymbolCallback);
begin
UserdefinedSymbolCallback:=callback;
end;
procedure TSymhandler.setshowmodules(x: boolean);
begin
if locked then raise symexception.Create(rsYouCanTChangeThisSettingAtTheMoment);
fshowmodules:=x;
end;
procedure TSymhandler.setshowsections(x: boolean);
begin
if locked then raise symexception.Create(rsYouCanTChangeThisSettingAtTheMoment);
fshowsections:=x;
end;
procedure TSymhandler.setshowsymbols(x: boolean);
begin
if locked then raise symexception.Create(rsYouCanTChangeThisSettingAtTheMoment);
fshowsymbols:=x;
end;
function TSymhandler.getusedprocessid:dword;
begin
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
result:=symbolloaderthread.thisprocessid
else
result:=0;
symbolloadervalid.endread;
end;
function TSymhandler.getusedprocesshandle:thandle;
begin
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
result:=symbolloaderthread.thisprocesshandle
else
result:=0;
symbolloadervalid.endread;
end;
procedure TSymhandler.EnumDotNetModule(m: TdotNetmodule; symbolhandler: TSymbolListHandler);
{
Enumerates the methods of the given module.
pre: owner must have already set a valid dotNetDataCollector and not about to get destroyed
}
var
dotNetTypedefs: TDotNetTypeDefArray;
dotnetmethods: TDotNetMethodArray;
dotnettypedefsIterator: integer;
dotnetmethodsIterator: integer;
i: integer;
name: string;
address: qword;
size: dword;
begin
{$IFDEF windows}
if dotNetDataCollector.Attached then
begin
setlength(dotNetTypedefs, 0);
dotNetDataCollector.EnumTypeDefs(m.hModule, dotNetTypedefs );
for dotnettypedefsIterator:=0 to length(dotnettypedefs)-1 do
begin
setlength(dotnetmethods,0);
dotNetDataCollector.GetTypeDefMethods(m.hModule, dotnettypedefs[dotnettypedefsIterator].token, dotnetmethods);
for dotnetmethodsIterator:=0 to length(dotnetmethods)-1 do
begin
if dotnetmethods[dotnetmethodsIterator].NativeCode<>0 then
begin
if length(dotnetmethods[dotnetmethodsIterator].SecondaryNativeCode)>0 then
begin
for i:=0 to length(dotnetmethods[dotnetmethodsIterator].SecondaryNativeCode)-1 do
begin
address:=dotnetmethods[dotnetmethodsIterator].SecondaryNativeCode[i].address;
size:=dotnetmethods[dotnetmethodsIterator].SecondaryNativeCode[i].size;
if i=0 then //first one
name:=dotnettypedefs[dotnettypedefsIterator].name+'::'+dotnetmethods[dotnetmethodsIterator].name
else
name:=dotnettypedefs[dotnettypedefsIterator].name+'::'+dotnetmethods[dotnetmethodsIterator].name+'_'+inttostr(i+1);
symbolhandler.AddSymbol(m.name, name, address, size);
end;
end
else
symbolhandler.AddSymbol(m.name, dotnettypedefs[dotnettypedefsIterator].name+'::'+dotnetmethods[dotnetmethodsIterator].name, dotnetmethods[dotnetmethodsIterator].NativeCode, 1)
end;
if dotnetmethods[dotnetmethodsIterator].ILCODE<>0 then //this can happen for PINVOKE's methods
symbolhandler.AddSymbol(m.name, dotnettypedefs[dotnettypedefsIterator].name+'::'+dotnetmethods[dotnetmethodsIterator].name+'_IL', dotnetmethods[dotnetmethodsIterator].ILCODE,1);
end;
end;
end;
{$ENDIF}
end;
procedure TSymhandler.reinitializeDotNetSymbols(modulename: string='');
{
Called by user. This indicates that the user wants to wait till it's fully loaded
}
var
domainIterator, moduleIterator: integer;
domains: TDotNetDomainArray;
modules: TDotNetModuleArray;
i: integer;
sh: TSymbolListHandler;
begin
{$IFDEF windows}
dotNetDataCollector.disconnect;
dotNetDataCollector.connect(processid, processhandler.is64Bit);
try
dotNetDataCollector.EnumDomains(domains);
for domainIterator:=0 to length(domains)-1 do
begin
dotNetDataCollector.EnumModuleList(domains[domainIterator].hDomain, modules);
for moduleIterator:=0 to length(modules)-1 do
begin
if (modulename='') or (lowercase(ExtractFileName(modules[moduleIterator].name))=lowercase(modulename)) then
begin
//add/update the symbols
sh:=nil;
dotnetModuleSymbolListMREW.Beginwrite;
try
for i:=0 to length(dotnetModuleSymbolList)-1 do
if modules[moduleIterator].baseaddress=dotnetModuleSymbolList[i].modulebase then
sh:=dotnetModuleSymbolList[i].symbollist;
if sh=nil then //not found
begin
//add it
sh:=TSymbolListHandler.create;
setlength(dotnetModuleSymbolList, length(dotnetModuleSymbolList)+1);
dotnetModuleSymbolList[length(dotnetModuleSymbolList)-1].modulebase:=modules[moduleIterator].baseaddress;
dotnetModuleSymbolList[length(dotnetModuleSymbolList)-1].modulename:=modules[moduleIterator].name;
dotnetModuleSymbolList[length(dotnetModuleSymbolList)-1].symbollist:=sh;
end;
finally
dotnetModuleSymbolListMREW.Endwrite;
end;
EnumDotNetModule(modules[moduleIterator], sh);
end;
dotNetDataCollector.ReleaseObject(modules[moduleIterator].hModule);
end;
dotNetDataCollector.ReleaseObject(domains[domainIterator].hDomain);
end;
except
end;
{$ENDIF}
end;
procedure TSymhandler.reinitialize(force: boolean=false);
var i,j: integer;
s: string;
begin
Log('TSymhandler.reinitialize');
if loadmodulelist or force then //if loadmodulelist returns true it has detected a change in the previous modulelist (baseaddresschange or new/deleted module)
begin
if force then
begin
i:=0;
symbollistsMREW.Beginwrite;
while i<length(symbollists) do
begin
if (symbollists[i].pid<>0) and (symbollists[i].pid<>processid) then
begin
RemoveSymbolList(symbollists[i]);
continue;
end;
inc(i);
end;
symbollistsMREW.EndWrite;
end;
if fetchSymbols then
begin
Log('loadmodulelist or force was true');
symbolloadervalid.Beginread;
try
if symbolloaderthread<>nil then
symbolloaderthread.Terminate; //let's get this started
finally
symbolloadervalid.Endread;
end;
{$IFDEF windows}
dotNetDataCollector.disconnect;
if not targetself then
dotNetDataCollector.connect(processid, processhandler.is64Bit);
{$ENDIF}
if symbolloaderthread<>nil then
begin
symbolloaderthread.Terminate;
//OutputDebugString(pchar(inttostr(GetCurrentThreadId)+':Waiting'));
if symbolloaderthread.Finished=false then
symbolloaderthread.WaitFor; //wait till it's done
//OutputDebugString(pchar(inttostr(GetCurrentThreadId)+':Returned'));
symbolloadervalid.BeginWrite;
try
freeandnil(symbolloaderthread);
finally
symbolloadervalid.Endwrite;
end;
end;
symbolloadervalid.BeginWrite;
symbolloaderthread:=tsymbolloaderthread.Create(self, targetself,true);
symbolloaderthread.kernelsymbols:=kernelsymbols;
symbolloaderthread.searchpath:=searchpath;
symbolloaderthread.symbollist:=symbollist;
symbolloadervalid.EndWrite;
symbolloaderthread.start;
end;
end;
ReinitializeUserdefinedSymbolList;
end;
procedure TSymhandler.searchPDBWhileLoading(state: boolean);
begin
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
symbolloaderthread.searchpdb:=state;
symbolloadervalid.Endread;
end;
procedure TSymhandler.WaitForSections;
begin
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
begin
while (not symbolloaderthread.Finished) and (not symbolloaderthread.sectionsloaded) do
begin
sleep(25);
if GetCurrentThreadID = MainThreadID then
CheckSynchronize;
end;
end;
symbolloadervalid.Endread;
end;
procedure TSymhandler.WaitForExports;
begin
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
begin
while (not symbolloaderthread.Finished) and (not symbolloaderthread.apisymbolsloaded) do
begin
sleep(25);
if GetCurrentThreadID = MainThreadID then
CheckSynchronize;
end;
end;
symbolloadervalid.Endread;
end;
procedure TSymhandler.WaitForDotNet;
begin
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
begin
while (not symbolloaderthread.Finished) and (not symbolloaderthread.dotnetsymbolsloaded) do
begin
sleep(25);
if GetCurrentThreadID = MainThreadID then
CheckSynchronize;
end;
end;
symbolloadervalid.Endread;
end;
procedure TSymhandler.WaitForPDB;
begin
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
begin
while (not symbolloaderthread.Finished) and (not symbolloaderthread.pdbsymbolsloaded) do
begin
sleep(25);
if GetCurrentThreadID = MainThreadID then
CheckSynchronize;
end;
end;
symbolloadervalid.Endread;
end;
procedure TSymhandler.Waitforsymbolsloaded(apisymbolsonly: boolean=false; specificmodule: string='');
//6.8.3+:Just make it till the dll list enum and load is done
begin
symbolloadervalid.beginread;
if symbolloaderthread<>nil then
begin
while (not symbolloaderthread.Finished) and (not symbolloaderthread.DLLSymbolsLoaded) do
begin
sleep(25);
if GetCurrentThreadID = MainThreadID then
CheckSynchronize;
end;
{
while (not symbolloaderthread.Finished) and (symbolloaderthread.isloading) and
not
(
(apisymbolsonly and symbolloaderthread.apisymbolsloaded) or //true if all the symbols are loaded
((specificmodule<>'') and areSymbolsLoadedForModule(specificModule)) //true if the module's symbols are loaded
)
do
begin
sleep(25);
if GetCurrentThreadID = MainThreadID then
CheckSynchronize;
end; }
end;
symbolloadervalid.endread;
end;
procedure TSymhandler.ReinitializeUserdefinedSymbolList;
var i: integer;
x: qword;
err: integer;
haserror: boolean;
begin
for i:=0 to userdefinedsymbolspos-1 do
begin
val('$'+userdefinedsymbols[i].addressstring, x, err);
if err>0 then //it's not a hexadecimal value
begin
x:=getAddressFromName(userdefinedsymbols[i].addressstring, false,haserror);
if not haserror then
userdefinedsymbols[i].address:=x;
end;
end;
end;
function TSymhandler.DeleteUserdefinedSymbol(symbolname:string):boolean;
var i,j: integer;
begin
result:=false;
userdefinedsymbolsCS.enter;
try
for i:=0 to userdefinedsymbolspos-1 do
if uppercase(userdefinedsymbols[i].symbolname)=uppercase(symbolname) then
begin
//found it
{ NO, not anymore
//check if it had a alloc, if so, free it
if (userdefinedsymbols[i].allocsize>0) and (userdefinedsymbols[i].processid=processid) then
VirtualFreeEx(processhandle,pointer(userdefinedsymbols[i].address),0,MEM_RELEASE);}
//now move up all the others and decrease the list
for j:=i to userdefinedsymbolspos-2 do
userdefinedsymbols[j]:=userdefinedsymbols[j+1];
dec(userdefinedsymbolspos);
result:=true;
break;
end;
finally
userdefinedsymbolsCS.leave;
end;
if assigned(UserdefinedSymbolCallback) then
UserdefinedSymbolCallback();
end;
function TSymhandler.SetUserdefinedSymbolAllocSize(symbolname:string; size: dword; preferedaddress: ptruint=0): boolean;
{
This function will find the userdefined symbol, and when found checks if it already
allocated memory. If not allocate memory, else check if the size matches
}
var i:integer;
base: pointer;
begin
result:=false;
if size=0 then raise exception.Create(rsPleaseProvideABiggerSize);
userdefinedsymbolsCS.enter;
try
i:=GetUserdefinedSymbolByNameIndex(symbolname);
if i=-1 then
begin
{userdefinedalloc: pointer; //if set it hold a pointer to the last free memory that was allocated.
userdefinedallocsizeleft: integer; //defines how much memory was left
}
if (globalallocpid<>processid) or (globalalloc=nil) or (globalallocsizeleft<size) then //new alloc
begin
{$ifdef windows}
base:=FindFreeBlockForRegion(preferedaddress,max(65536,size));
{$else}
base:=0;
{$endif}
globalalloc:=virtualallocex(processhandle,base,max(65536,size),MEM_COMMIT or MEM_RESERVE , PAGE_EXECUTE_READWRITE);
globalallocpid:=processid;
globalallocsizeleft:=max(65536,size);
if globalalloc<>nil then
AddUnexpectedExceptionRegion(ptruint(globalalloc),max(65536,size));
end;
if globalalloc=nil then
raise exception.Create(rsErrorAllocatingMemory);
AddUserdefinedSymbol(inttohex(ptrUint(globalalloc),8),symbolname);
i:=GetUserdefinedSymbolByNameIndex(symbolname);
userdefinedsymbols[i].allocsize:=size;
userdefinedsymbols[i].processid:=processid;
size:=(size+15) and not $f;
dec(globalallocsizeleft, size );
inc(pbyte(globalalloc), size);
end
else
begin
//it exists, check first
if (userdefinedsymbols[i].allocsize>0) and (userdefinedsymbols[i].processid=processid) then
begin
//already allocated and processid is the same
if size<>userdefinedsymbols[i].allocsize then
raise exception.Create(Format(rsTheSymbolNamedWasPreviouslyDeclared, [userdefinedsymbols[i].symbolname, inttostr(userdefinedsymbols[i].allocsize), inttostr(size)]));
end;
if userdefinedsymbols[i].processid<>processid then
begin
if (globalallocpid<>processid) or (globalalloc=nil) or (globalallocsizeleft<size) then //new alloc
begin
globalallocpid:=processid;
globalalloc:=virtualallocex(processhandle,{$ifdef windows}FindFreeBlockForRegion(preferedaddress,max(65536,size)){$else}0{$endif},max(65536,size),MEM_COMMIT or MEM_RESERVE , PAGE_EXECUTE_READWRITE);
globalallocsizeleft:=max(65536,size);
if globalalloc<>nil then
AddUnexpectedExceptionRegion(ptruint(globalalloc),max(65536,size));
end;
if globalalloc=nil then
raise exception.Create(rsErrorAllocatingMemory);
userdefinedsymbols[i].address:=ptrUint(globalalloc);
userdefinedsymbols[i].addressstring:=inttohex(ptrUint(globalalloc),8);
userdefinedsymbols[i].allocsize:=size;
userdefinedsymbols[i].processid:=processid;
size:=(size+15) and not $f;
dec(globalallocsizeleft, size );
inc(ptrUint(globalalloc), size);
end;
end;
finally
userdefinedsymbolsCS.leave;
end;
result:=true; //managed to get here without crashing...
if assigned(UserdefinedSymbolCallback) then
UserdefinedSymbolCallback();
end;
function TSymhandler.GetUserdefinedSymbolByNameIndex(symbolname:string):integer;
var i: integer;
begin
result:=-1;
userdefinedsymbolsCS.enter;
try
for i:=0 to userdefinedsymbolspos-1 do
begin
if uppercase(userdefinedsymbols[i].symbolname)=uppercase(symbolname) then
begin
result:=i;
break;
end;
end;
finally
userdefinedsymbolsCS.leave;
end;
end;
function TSymhandler.GetUserdefinedSymbolByAddressIndex(address: ptruint):integer;
var i: integer;
begin
result:=-1;
userdefinedsymbolsCS.enter;
try
for i:=0 to userdefinedsymbolspos-1 do
if userdefinedsymbols[i].address=address then
begin
result:=i;
break;
end;
finally
userdefinedsymbolsCS.leave;
end;
end;
function TSymhandler.GetUserdefinedSymbolByName(symbolname:string):ptrUint;
var i:integer;
begin
result:=0;
userdefinedsymbolsCS.enter;
try
i:=GetUserdefinedSymbolByNameIndex(symbolname);
if i=-1 then exit;
result:=userdefinedsymbols[i].address;
finally
userdefinedsymbolsCS.leave;
end;
end;
function TSymhandler.GetUserdefinedSymbolByAddress(address:ptrUint):string;
var i:integer;
begin
result:='';
userdefinedsymbolsCS.enter;
try
i:=GetUserdefinedSymbolByAddressIndex(address);
if i=-1 then exit;
result:=userdefinedsymbols[i].symbolname;
finally
userdefinedsymbolsCS.leave;
end;
end;
procedure TSymhandler.AddUserdefinedSymbol(addressstring: string; symbolname: string; DoNotSave: Boolean=false);
{
This routine will add the symbolname+address combination to the symbollist
}
var
address: ptruint;
begin
if getuserdefinedsymbolbyname(symbolname)>0 then raise symexception.Create(symbolname+' '+rsAlreadyExists);
address:=getAddressFromName(addressstring);
if address=0 then raise symexception.Create(rsYouCanTAddASymbolWithAddress0);
userdefinedsymbolsCS.enter;
try
if userdefinedsymbolspos+1>=length(userdefinedsymbols) then
setlength(userdefinedsymbols,length(userdefinedsymbols)*2);
userdefinedsymbols[userdefinedsymbolspos].address:=address;
userdefinedsymbols[userdefinedsymbolspos].addressstring:=addressstring;
userdefinedsymbols[userdefinedsymbolspos].symbolname:=symbolname;
userdefinedsymbols[userdefinedsymbolspos].allocsize:=0;
userdefinedsymbols[userdefinedsymbolspos].processid:=0;
userdefinedsymbols[userdefinedsymbolspos].doNotSave:=DoNotSave;
inc(userdefinedsymbolspos);
finally
userdefinedsymbolsCS.leave;
end;
if assigned(UserdefinedSymbolCallback) then
UserdefinedSymbolCallback();
end;
procedure TSymhandler.EnumerateUserdefinedSymbols(list:tstrings);
{
Enumerates all userdefined symbols and stores them in a list
NOTE: The caller must free the object info added
}
var i: integer;
extradata: ^TUDSEnum;
begin
list.Clear;
userdefinedsymbolsCS.enter;
for i:=0 to userdefinedsymbolspos-1 do
begin
getmem(extradata,sizeof(TUDSEnum));
extradata.address:=userdefinedsymbols[i].address;
extradata.allocsize:=userdefinedsymbols[i].allocsize;
extradata.addressstring:=@userdefinedsymbols[i].addressstring[1];
extradata.doNotSave:=userdefinedsymbols[i].doNotSave;
list.Addobject(userdefinedsymbols[i].symbolname,pointer(extradata));
//just don't forget to free it at the caller's end
end;
userdefinedsymbolsCS.leave;
end;
procedure TSymhandler.fillMemoryRegionsWithModuleData(var mr: TMemoryregions; startaddress: ptruint; size: dword);
{
This routine will fill in a TMemoryRegions array with the base and startaddress of the modules it found
}
var currentaddress: ptruint;
mi: tmoduleinfo;
sizeleft: dword;
i: integer;
closest: integer;
begin
modulelistMREW.beginread;
try
if modulelistpos=0 then exit;
currentaddress:=startaddress;
sizeleft:=size;
while sizeleft>0 do
begin
//find a module with currentaddress if nothing found, find the one with the lowest base address after it
if getmodulebyaddress(currentaddress,mi) then
begin
setlength(mr,length(mr)+1);
mr[length(mr)-1].BaseAddress:=currentaddress;
mr[length(mr)-1].MemorySize:=mi.basesize-(currentaddress-mi.baseaddress);
if mr[length(mr)-1].MemorySize>sizeleft then
mr[length(mr)-1].MemorySize:=sizeleft;
sizeleft:=sizeleft-mr[length(mr)-1].MemorySize;
inc(currentaddress,mr[length(mr)-1].MemorySize);
end
else
begin
//move the currentaddress to the next module
closest:=-1;
for i:=0 to modulelistpos-1 do
begin
if modulelist[i].baseaddress>currentaddress then
begin
closest:=i;
break;
end;
end;
//first make sure there is a bigger module
for i:=0 to modulelistpos-1 do
if (modulelist[i].baseaddress>currentaddress) and (modulelist[i].baseaddress<modulelist[closest].baseaddress) then
closest:=i;
if modulelist[closest].baseaddress<currentaddress then exit; //nothing found
mi:=modulelist[closest];
inc(sizeleft,mi.baseaddress-currentaddress);
currentaddress:=mi.baseaddress;
end;
end;
finally
modulelistMREW.endread;
end;
end;
function TSymHandler.OpenDatabaseIfNeeded: boolean;
begin
{$IFDEF windows}
result:=true;
try
if symbolDataBase=nil then
begin
symbolDataBase:=TSQLite3Connection.Create(nil);
symbolDataBase.DatabaseName:=databasepath;
symbolDataBase.Transaction:=TSQLTransaction.Create(symbolDataBase); //not really needed as the symhandler uses it for reads only
symbolDataBase.Connected:=true;
end;
except
on e: exception do
begin
outputdebugstring('OpenDatabaseIfNeeded:'+e.message);
result:=false;
if symbolDataBase<>nil then
freeandnil(symbolDataBase);
end;
end;
{$else}
result:=false;
{$ENDIF}
end;
procedure TSymHandler.getStructureElements(callbackid: integer; moduleid: integer; typeid: integer; list: TStringList);
var
q: TSQLQuery=nil;
elementinfo: TDBElementInfo=nil;
i: longint;
begin
symbolloaderthread.debugpart:=110;
{$IFDEF windows}
if callbackid=-1 then
begin
q:=TSQLQuery.Create(nil);
q.DataBase:=symbolDataBase;
try
// elements(moduleid, typeid, elementnr, elementname, offset, basetype, type)
q.sql.text:='select elementname, offset, basetype, type, tag from elements where moduleid=:moduleid and typeid=:typeid';
q.ParamByName('moduleid').AsInteger:=moduleid;
q.ParamByName('typeid').AsInteger:=typeid;
q.Prepare;
q.Active:=true;
q.first;
while not q.EOF do
begin
elementinfo:=TDBElementInfo.create;
if elementinfo=nil then
begin
outputdebugstring('TDBElementInfo.create returned nil');
exit;
end;
i:=q.FieldByName('offset').AsInteger;
elementinfo.offset:=i;
i:=q.FieldByName('basetype').AsInteger;
elementinfo.basetype:=i;
i:=q.FieldByName('type').AsInteger;
elementinfo.typeid:=i;
i:=q.FieldByName('tag').AsInteger;
elementinfo.tag:=TSymTagEnum(i);
if elementinfo.tag=SymTagPointerType then
elementinfo.vartype:=vtPointer
else
begin
case TBasicType(elementinfo.basetype) of
btChar: elementinfo.vartype:=vtString;
btWChar: elementinfo.vartype:=vtUnicodeString;
btInt: elementinfo.vartype:=vtDword;
btUInt: elementinfo.vartype:=vtDword;
btFloat: elementinfo.vartype:=vtSingle;
btBCD: elementinfo.vartype:=vtByte;
btBool: elementinfo.vartype:=vtByte;
btLong: elementinfo.vartype:=vtQword;
btULong: elementinfo.vartype:=vtQword;
btCurrency: elementinfo.vartype:=vtDword;
btDate: elementinfo.vartype:=vtDword;
btVariant: elementinfo.vartype:=vtDword;
btComplex: elementinfo.vartype:=vtDword;
btBit: elementinfo.vartype:=vtDword;
btBSTR:elementinfo.vartype:=vtString;
btHresult: elementinfo.vartype:=vtDword;
else
begin
elementinfo.vartype:=vtDword;
end;
end;
end;
list.addobject(q.FieldByName('elementname').AsString, elementinfo);
q.next;
end;
q.active:=false;
finally
if q<>nil then
freeandnil(q);
end;
end
else
{$ENDIF}
begin
StructureElementListCallbacks[callbackid].ElementListCallback(moduleid, typeid, list);
end;
end;
procedure TSymHandler.getStructureElementsFromName(name: string; list: TStringList);
begin
symbolloaderthread.getStructureFromName(name, list);
end;
function TSymHandler.getStructureList(list: tstringlist; max: integer=-1): integer;
var
q: TSQLQuery;
moduleidstring: string;
structinfo: TDBStructInfo;
i: integer;
begin
result:=0;
if istrainer then exit;
for i:=0 to length(StructureElementListCallbacks)-1 do
StructureElementListCallbacks[i].StructureListCallback(i,list, max);
if (max<>-1) and (list.Count>=max) then exit;
if hasDefinedStructures then
begin
moduleidstring:='';
modulelistMREW.beginread;
try
for i:=0 to modulelistpos-1 do
if modulelist[i].hasStructInfo then
begin
if moduleidstring='' then
moduleidstring:=inttostr(modulelist[i].databaseModuleID)
else
moduleidstring:=moduleidstring+','+inttostr(modulelist[i].databaseModuleID);
end;
finally
modulelistMREW.endread;
end;
if moduleidstring='' then
begin
symbolloadervalid.Beginread;
try
if symbolloaderthread<>nil then
begin
symbolloaderthread.driverlistMREW.Beginread;
try
for i:=0 to symbolloaderthread.driverlistpos-1 do
if symbolloaderthread.driverlist[i].hasStructInfo then
if moduleidstring='' then
moduleidstring:=inttostr(symbolloaderthread.driverlist[i].databaseModuleID)
else
moduleidstring:=moduleidstring+','+inttostr(symbolloaderthread.driverlist[i].databaseModuleID);
finally
symbolloaderthread.driverlistMREW.endread;
end;
end;
finally
symbolloadervalid.endread;
end;
end;
if moduleidstring='' then exit;
if OpenDataBaseIfNeeded=false then exit;
{$IFDEF windows}
q:=TSQLQuery.Create(nil);
try
// q.SQL.Text:='create table structures(moduleid INTEGER NOT NULL, typeid INTEGER NOT NULL, tablename varchar(255) NOT NULL, length INTEGER NOT NULL, PRIMARY KEY (moduleid, typeid))';
q.sql.text:='select * from structures where moduleid in ('+moduleidstring+')';
q.DataBase:=symbolDataBase;
q.Active:=true;
q.First;
while (not q.EOF){ and ((max=-1) or (list.count<max) ) }do
begin
structinfo:=TDBStructInfo.Create;
structinfo.moduleid:=q.FieldByName('moduleid').AsInteger;
structinfo.typeid:=q.FieldByName('typeid').AsInteger;
structinfo.length:=q.FieldByName('length').AsInteger;
structinfo.callbackid:=-1;
list.AddObject(q.FieldByName('tablename').AsString, structinfo);
q.next;
end;
q.Active:=false;
finally
q.free;
end;
{$ENDIF}
end
else
begin
symbolloaderthread.getStructureList(list);
result:=1; //not a structinfo
end;
end;
function TSymHandler.hasDefinedStructures:boolean;
var i: integer;
begin
if istrainer then exit(false);
if length(StructureElementListCallbacks)>0 then exit(true);
result:=true;
modulelistMREW.beginread;
try
for i:=0 to modulelistpos-1 do
if modulelist[i].hasStructInfo then
exit(true);
finally
modulelistMREW.endread;
end;
symbolloadervalid.Beginread;
try
if symbolloaderthread<>nil then
begin
symbolloaderthread.driverlistMREW.Beginread;
try
for i:=0 to symbolloaderthread.driverlistpos-1 do
if symbolloaderthread.driverlist[i].hasStructInfo then
exit(true);
finally
symbolloaderthread.driverlistMREW.endread;
end;
if symbolloaderthread.hasEnumeratedAllStructures then exit(false);//symbolloader is done and found no structures
end;
finally
symbolloadervalid.endread;
end;
exit;
end;
function TSymhandler.getSymbolInfo(name: string; var syminfo: TCESymbolInfo): boolean;
var s: PCESymbolInfo;
i: integer;
begin
//find the symbol
result:=false;
//first check .net
{$IFDEF windows}
if dotNetDataCollector.Attached then
begin
dotnetModuleSymbolListMREW.beginread;
try
for i:=0 to length(dotnetModuleSymbolList)-1 do
begin
s:=dotnetModuleSymbolList[i].symbollist.FindSymbol(name);
if s<>nil then
begin
syminfo:=s^;
result:=true;
exit;
end;
end;
finally
dotnetModuleSymbolListMREW.endread;
end;
end;
{$ENDIF}
//then check secondary symbollists
symbollistsMREW.Beginread;
try
for i:=0 to length(symbollists)-1 do
begin
s:=symbollists[i].FindSymbol(name);
if s<>nil then
begin
syminfo:=s^;
result:=true;
exit;
end;
end;
finally
symbollistsMREW.Endread;
end;
//and finally check the default symbol list
s:=symbollist.FindSymbol(name);
if s<>nil then
begin
syminfo:=s^;
result:=true;
end;
end;
procedure TSymhandler.GetSymbolList(address: ptruint; list: tstrings);
var si: PCESymbolInfo;
mi: TModuleInfo;
symbolname: string;
i: integer;
params: string;
sl: array of TSymbolListHandler;
begin
list.clear;
if getmodulebyaddress(address, mi) then
begin
{$IFDEF windows}
if dotNetDataCollector.Attached then
begin
//get the .net list if symbols for this module
dotnetModuleSymbolListMREW.beginread;
for i:=0 to length(dotnetModuleSymbolList)-1 do
begin
if dotnetModuleSymbolList[i].modulebase=mi.baseaddress then
begin
si:=dotnetModuleSymbolList[i].symbollist.FindFirstSymbolFromBase(0);
while si<>nil do
begin
symbolname:=si.originalstring;
list.AddObject(symbolname, pointer(si.address));
si:=si.next;
end;
break;
end;
end;
dotnetModuleSymbolListMREW.endread;
end;
{$ENDIF}
symbollistsMREW.Beginread;
for i:=0 to length(symbollists)-1 do
begin
si:=symbollists[i].FindFirstSymbolFromBase(mi.baseaddress);
while (si<>nil) and inrangeq(si.address, mi.baseaddress, mi.baseaddress+mi.basesize) do
begin
symbolname:=si.originalstring;
list.AddObject(symbolname, pointer(si.address));
si:=si.next;
end;
end;
symbollistsMREW.Endread;
si:=symbollist.FindFirstSymbolFromBase(mi.baseaddress);
while (si<>nil) and inrangeq(si.address, mi.baseaddress, mi.baseaddress+mi.basesize) do
begin
symbolname:=si.originalstring;
if si.extra<>nil then
begin
//add the parameters if there are any
if si.extra.forwarder then
symbolname:=symbolname+' --> '+si.extra.forwardsToString
else
begin
params:='';
for i:=0 to si.extra.parameters.Count-1 do
begin
if i>0 then
params:=params+', '+ si.extra.parameters[i].vtype+' '+si.extra.parameters[i].name
else
params:=params+si.extra.parameters[i].vtype+' '+si.extra.parameters[i].name;
end;
symbolname:=symbolname+'('+params+')';
end;
end;
list.AddObject(symbolname, pointer(si.address));
si:=si.next;
end;
end;
end;
procedure TSymhandler.getModuleList(list: tstrings);
var
i,j: integer;
list2: TExtraModuleInfoList;
begin
modulelistMREW.BeginRead;
for i:=0 to modulelistpos-1 do
list.AddObject(modulelist[i].modulename,tobject(modulelist[i].baseaddress));
modulelistMREW.EndRead;
symbolloadervalid.Beginread;
try
if symbolloaderthread<>nil then
begin
symbolloaderthread.driverlistMREW.beginread;
try
for i:=0 to symbolloaderthread.driverlistpos-1 do
list.addObject(symbolloaderthread.driverlist[i].modulename,tobject(symbolloaderthread.driverlist[i].baseaddress));
finally
symbolloaderthread.driverlistMREW.endread;
end;
end;
finally
symbolloadervalid.Endread;
end;
symbollistsMREW.BeginRead;
for i:=0 to length(symbollists)-1 do
begin
setlength(list2,0);
symbollists[i].GetModuleList(list2);
for j:=0 to length(list2)-1 do
list.AddObject(list2[j].modulename,tobject(list2[j].baseaddress));
end;
symbollistsMREW.endread;
end;
function TSymhandler.inSystemModule(address: ptrUint): BOOLEAN;
var mi: TModuleInfo;
begin
result:=false;
if getmodulebyaddress(address,mi) then
result:=mi.isSystemModule;
end;
function TSymhandler.inModule(address: ptrUint): BOOLEAN; //returns true if the given address is part of a module
var mi: TModuleInfo;
begin
result:=getmodulebyaddress(address,mi);
end;
function TSymhandler.areSymbolsLoadedForModule(symbolname: string): boolean;
var mi: TModuleInfo;
begin
if getmodulebyname(symbolname,mi) then
result:=mi.symbolsLoaded
else
result:=false;
end;
procedure TSymhandler.markModuleAsLoaded(address: ptruint);
var i: integer;
begin
modulelistMREW.beginread;
for i:=0 to modulelistpos-1 do
begin
if (address>=modulelist[i].baseaddress) and (address<modulelist[i].baseaddress+modulelist[i].basesize) then
begin
modulelist[i].symbolsLoaded:=true;
break;
end;
end;
modulelistMREW.endread;
end;
function TSymhandler.getmodulebyaddress(address: ptrUint; var mi: TModuleInfo):BOOLEAN;
var i: integer;
begin
if (self<>nil) and (modulelistMREW<>nil) then
begin
result:=false;
modulelistMREW.beginread;
for i:=0 to modulelistpos-1 do
if (address>=modulelist[i].baseaddress) and (address<modulelist[i].baseaddress+modulelist[i].basesize) then
begin
mi:=modulelist[i];
result:=true;
break;
end;
modulelistMREW.endread;
if not result then
begin
symbolloadervalid.beginread;
try
if symbolloaderthread<>nil then
begin
symbolloaderthread.driverlistMREW.beginread;
try
for i:=0 to symbolloaderthread.driverlistpos-1 do
if (address>=symbolloaderthread.driverlist[i].baseaddress) and (address<symbolloaderthread.driverlist[i].baseaddress+symbolloaderthread.driverlist[i].basesize) then
begin
mi:=symbolloaderthread.driverlist[i];
result:=true;
break;
end;
finally
symbolloaderthread.driverlistMREW.Endread;
end;
end;
finally
symbolloadervalid.Endread;
end;
symbollistsMREW.beginread;
for i:=0 to length(symbollists)-1 do
begin
result:=symbollists[i].getModuleByAddress(address, mi);
if result then break;
end;
symbollistsMREW.endread;
end;
end;
end;
function TSymhandler.getmodulebyname(modulename: string; var mi: TModuleInfo):BOOLEAN;
var
i: integer;
moduleNameToFind: string;
currentModuleName: string;
begin
result:=false;
moduleNameToFind:=uppercase(modulename);
if (length(moduleNameToFind)>0) and (moduleNameToFind[1]='"') then
begin
moduleNameToFind:=trim(moduleNameToFind);
moduleNameToFind:=copy(moduleNameToFind, 2, length(moduleNameToFind)-2);
end;
modulelistMREW.beginread;
for i:=0 to modulelistpos-1 do
begin
currentModuleName:=uppercase(modulelist[i].modulename);
if currentModuleName=moduleNameToFind then
begin
mi:=modulelist[i];
result:=true;
break;
end;
end;
modulelistMREW.endread;
if not result then
begin
symbollistsMREW.beginread;
for i:=0 to length(symbollists)-1 do
begin
result:=symbollists[i].getModuleByName(moduleNameToFind,mi);
if result then break;
end;
symbollistsMREW.Endread;
end;
symbolloadervalid.Beginread;
try
if (symbolloaderthread<>nil) and (symbolloaderthread.driverlistpos>0) then
begin
symbolloaderthread.driverlistMREW.beginread;
try
for i:=0 to symbolloaderthread.driverlistpos do
begin
if symbolloaderthread.driverlist[i].modulename=modulename then
begin
mi:=symbolloaderthread.driverlist[i];
exit(true);
end;
end;
finally
symbolloaderthread.driverlistMREW.Endread;
end;
end;
finally
symbolloadervalid.Endread;
end;
end;
function TSymHandler.getsearchpath:string;
begin
result:=searchpath;
end;
procedure TSymHandler.setsearchpath(path:string);
begin
searchpath:=path;
end;
function TSymhandler.getExtraDataFromSymbolAtAddress(address: ptruint): TExtraSymbolData;
//returns the extra data for a symbol (can be nil)
var si: PCESymbolInfo;
begin
result:=nil;
symbolloadervalid.beginread;
si:=symbollist.FindAddress(address);
if si<>nil then
result:=si.extra;
symbolloadervalid.Endread;
if (result<>nil) and ((not result.filledin) and (not result.forwarder)) then //Not yet loaded /not a forwarder
result:=nil;
end;
function TSymhandler.getNameFromAddress(address:ptrUint;symbols, modules, sections: boolean; baseaddress: PUINT64=nil; found: PBoolean=nil; hexcharsize: integer=8; important: boolean=true):string;
var //symbol :PSYMBOL_INFO;
offset: qword;
offsetstring: string;
mi: tmoduleinfo;
si: PCESymbolInfo;
i: integer;
begin
if found<>nil then
found^:=false;
if symbols then
begin
//check the userdefined symbols
result:=self.GetUserdefinedSymbolByAddress(address);
if result<>'' then exit;
//check callbacks
for i:=0 to length(AddressLookupCallbacks)-1 do
begin
if assigned(AddressLookupCallbacks[i]) then
begin
result:=AddressLookupCallbacks[i](address);
if result<>'' then
exit;
end;
end;
//first see if it is a symbol
symbolloadervalid.beginread;
try
if (symbolloaderthread<>nil) then
begin
//if isloaded then
begin
si:=nil;
{$IFDEF windows}
if dotNetDataCollector.Attached then
begin
dotnetModuleSymbolListMREW.beginread;
for i:=0 to length(dotnetModuleSymbolList)-1 do
begin
si:=dotnetModuleSymbolList[i].symbollist.FindAddress(address);
if si<>nil then break;
end;
dotnetModuleSymbolListMREW.endread;
end;
{$ENDIF}
if si=nil then
begin
//check the symbollists registered by the user
symbollistsMREW.Beginread;
for i:=0 to length(symbollists)-1 do
begin
si:=symbollists[i].FindAddress(address);
if si<>nil then break;
end;
symbollistsMREW.endread;
if si=nil then
si:=symbollist.FindAddress(address);
end;
if si<>nil then
begin
offset:=address-si.address;
result:=si.originalstring;
if offset>0 then //unsigned, always bigger
result:=result+'+'+inttohex(offset,1);
if baseaddress<>nil then
baseaddress^:=si.Address;
if found<>nil then
found^:=true;
exit;
end
else
begin
if symbolloaderthread.isloading and important then
begin
result:=symbolloaderthread.getSymbolFromAddress(address);
if (result='') and (symbolloaderthread.isloading=false) then //try again
result:=getNameFromAddress(address, symbols, modules, sections, baseaddress, found, hexcharsize);
if result<>'' then exit;
end;
end;
end;
end;
finally
symbolloadervalid.endread;
end;
end;
mi.baseaddress:=0;
if sections then
begin
if getmodulebyaddress(address,mi) then
begin
for i:=0 to length(mi.sections)-1 do
if inrangex(address, mi.sections[i].address, mi.sections[i].address+mi.sections[i].size-1) then
begin
offset:=address-mi.sections[i].address;
if offset>0 then
offsetstring:='+'+inttohex(offset,1)
else
offsetstring:='';
if mi.sections[i].name[1]='.' then
exit(mi.modulename+mi.sections[i].name+offsetstring)
else
exit(mi.modulename+'.'+mi.sections[i].name+offsetstring)
end;
end;
end;
if modules then
begin
//get the dllname+offset
if (mi.baseaddress<>0) or getmodulebyaddress(address,mi) then //don't look up again if sections already did so
begin
if address-mi.baseaddress=0 then
result:=mi.modulename
else
result:=mi.modulename+'+'+inttohex(address-mi.baseaddress,1);
if baseaddress<>nil then
baseaddress^:=mi.baseaddress;
if found<>nil then
found^:=true;
exit;
end;
end;
result:=inttohex(address,hexcharsize); //default
end;
function TSymhandler.getNameFromAddress(address:ptrUint; var found: boolean; hexcharsize: integer=8):string;
begin
result:=getNameFromAddress(address,self.showsymbols,self.showmodules,self.showsections, nil,@found,hexcharsize);
end;
function TSymhandler.getNameFromAddress(address:ptrUint):string;
begin
result:=getNameFromAddress(address,self.showsymbols,self.showmodules, self.showsections);
end;
function TSymhandler.getAddressFromNameL(name: string; waitforsymbols: boolean=true):ptrUint; //Lua
var e: boolean;
begin
result:=getAddressFromName(name, waitforsymbols, e);
if e then
begin
if ExceptionOnLuaLookup then
raise symexception.Create(Format(rsFailureDeterminingWhatMeans, [name]))
else
result:=0;
end;
end;
function TSymhandler.getAddressFromName(name:string):ptrUint;
begin
result:=getAddressFromName(name,true);
end;
function TSymhandler.getAddressFromName(name: string; waitforsymbols: boolean): ptrUint;
var x: boolean;
begin
result:=getAddressFromName(name,true,x,nil);
{
debugger hell:
tools->debugger options->Language Exceptions
click add...
type in "symexception" without the quotes
this will cause you to still break on normal exception like memory access violations, but not on these
}
if x then
raise symexception.Create(Format(rsFailureDeterminingWhatMeans, [name]));
end;
function TSymhandler.getAddressFromName(name: string; waitforsymbols: boolean; out haserror: boolean):ptrUint;
begin
result:=getAddressFromName(name, waitforsymbols, haserror,nil);
if haserror then result:=0;
end;
function TSymhandler.getAddressFromNameShallow(name: string; waitforsymbols: boolean; out haserror: boolean):ptrUint;
begin
result:=getAddressFromName(name, waitforsymbols, haserror, nil,true);
end;
function TSymhandler.getAddressFromName(name: string; waitforsymbols: boolean; out haserror: boolean; context: PContext; shallow: boolean=false):ptrUint;
//shallow will still lookup symbols when explicitly asked for like $luasymbol, but won't dig deeper or use callbacks
function callbackCheck(s: string; cbType: TSymbolLookupCallbackPoint): ptruint;
var slcindex: integer;
begin
result:=0;
for slcindex:=0 to length(SymbolLookupCallbacks[cbType])-1 do
begin
if assigned(SymbolLookupCallbacks[cbType][slcindex]) then
begin
result:=SymbolLookupCallbacks[cbType][slcindex](s);
if result<>0 then exit;
end;
end;
end;
type TCalculation=(calcAddition, calcSubstraction);
var mi: tmoduleinfo;
si: PCESymbolInfo;
offset: integer;
i,j,k: integer;
p: pchar;
ws: widestring;
pws: pwidechar;
tokens: TTokens;
mathstring: string;
hasMultiplication, hasPointer: boolean;
nextoperation: TCalculation;
regnr: integer;
//symbol: PSYMBOL_INFO;
s: string;
a,br: ptruint;
pointerstartlist: array of
record
start: integer;
tokentype: TSymHandlerTokenType;
end;
pointerstartpos,pointerstartmax: integer;
nexttokentype: TSymHandlerTokenType;
v64: qword;
mr: TMemoryrecord;
function ApplyTokenType(value: qword): qword;
begin
case nexttokentype of
ttByte: result:=Byte(value);
ttWord: result:=Word(value);
ttDword: result:=Dword(value);
ttQword: result:=Qword(value);
ttShortInt: result:=ShortInt(value);
ttSmallint: result:=SmallInt(value);
ttLongint: result:=LongInt(value);
ttInt64: result:=Int64(value);
else
result:=value; //never...
end;
nextTokenType:=ttQword; //reset to default
end;
begin
nexttokentype:=ttQword;
pointerstartpos:=0;
pointerstartmax:=16;
setlength(pointerstartlist,pointerstartmax);
hasMultiplication:=false;
name:=trim(name);
hasPointer:=false;
haserror:=false;
offset:=0;
if not shallow then
begin
result:=callbackCheck(name, slStart);
if result<>0 then exit;
end;
//check if it's a lua symbol notation ('$')
if length(name)>=2 then
begin
if name[1]='$' then
begin
val(name,result,i);
if i=0 then exit; //it's a hexadecimal string starting with a $
end;
end;
val('$'+name,result,i);
if i=0 then exit; //it's a valid hexadecimal string
if lowercase(copy(name,1,2))='0x' then
begin
val(name,result,i);
if i=0 then exit;
end;
//not a hexadecimal string
if not shallow then
begin
result:=callbackCheck(name, slNotInt);
if result<>0 then exit;
end;
tokenize(name, tokens);
//first check the most basic thing
if length(tokens)=0 then
begin
haserror:=true;
exit;
end;
//if it starts with a * or ends with *, - or +, then it's a bad formula
if (tokens[0][1] ='*') or (tokens[length(tokens)-1][1] in ['*','+','-']) then
begin
haserror:=true;
exit;
end;
//convert the tokens into hexadecimal values
symbolloadervalid.beginread;
try
for i:=0 to length(tokens)-1 do
begin
if (length(tokens[i])>0) and (not (tokens[i][1] in ['[',']','+','-','*','(',')'])) then
begin
val('$'+tokens[i],v64,j);
result:=v64;
if j>0 then
begin
//not a hexadecimal value
if getmodulebyname(tokens[i],mi) then
begin
tokens[i]:=inttohex(ApplyTokenType(mi.baseaddress),8);
continue;
end
else
begin
//not a modulename
if not shallow then
begin
result:=callbackCheck(tokens[i], slNotModule);
if result>0 then
begin
tokens[i]:=inttohex(ApplyTokenType(result),8);
continue;
end;
end;
{$IFDEF windows}
if not shallow then
regnr:=getreg(uppercase(tokens[i]),false)
else
regnr:=-1;
if regnr<>-1 then
begin
if (context<>nil) and (context^.{$ifdef cpu64}Rip{$else}Eip{$endif}<>0) then
begin
//get the register value, and because this is an address specifier, use the full 32-bits
case regnr of
0: tokens[i]:=inttohex(ApplyTokenType(context^.{$ifdef cpu64}rax{$else}eax{$endif}),8);
1: tokens[i]:=inttohex(ApplyTokenType(context^.{$ifdef cpu64}rcx{$else}ecx{$endif}),8);
2: tokens[i]:=inttohex(ApplyTokenType(context^.{$ifdef cpu64}rdx{$else}edx{$endif}),8);
3: tokens[i]:=inttohex(ApplyTokenType(context^.{$ifdef cpu64}rbx{$else}ebx{$endif}),8);
4: tokens[i]:=inttohex(ApplyTokenType(context^.{$ifdef cpu64}rsp{$else}esp{$endif}),8);
5: tokens[i]:=inttohex(ApplyTokenType(context^.{$ifdef cpu64}rbp{$else}ebp{$endif}),8);
6: tokens[i]:=inttohex(ApplyTokenType(context^.{$ifdef cpu64}rsi{$else}esi{$endif}),8);
7: tokens[i]:=inttohex(ApplyTokenType(context^.{$ifdef cpu64}rdi{$else}edi{$endif}),8);
{$ifdef cpu64}
8: tokens[i]:=inttohex(ApplyTokenType(context^.r8),8);
9: tokens[i]:=inttohex(ApplyTokenType(context^.r9),8);
10: tokens[i]:=inttohex(ApplyTokenType(context^.r10),8);
11: tokens[i]:=inttohex(ApplyTokenType(context^.r11),8);
12: tokens[i]:=inttohex(ApplyTokenType(context^.r12),8);
13: tokens[i]:=inttohex(ApplyTokenType(context^.r13),8);
14: tokens[i]:=inttohex(ApplyTokenType(context^.r14),8);
15: tokens[i]:=inttohex(ApplyTokenType(context^.r15),8);
{$endif}
end;
continue; //handled
end;
//not handled, but since it's a register, quit now
hasError:=true;
exit(0);
end
else
{$ENDIF}
begin
//no context or not a register
result:=GetUserdefinedSymbolByName(tokens[i]);
if result>0 then
begin
tokens[i]:=inttohex(ApplyTokenType(result),8);
continue;
end;
//not a userdefined symbol
if not shallow then
begin
result:=callbackCheck(tokens[i], slNotUserdefinedSymbol);
if result>0 then
begin
tokens[i]:=inttohex(ApplyTokenType(result),8);
continue;
end;
end;
{$ifdef windows}
if (DBKLoaded) and (length(tokens[i])>6) and (pos('KERNEL_',uppercase(tokens[i]))>0) then
begin
tokens[i]:=copy(tokens[i],8,length(tokens[i])-7);
ws:=tokens[i];
pws:=@ws[1];
result:=ptrUint(GetKProcAddress(pws));
if result<>0 then
begin
tokens[i]:=inttohex(ApplyTokenType(result),8);
continue;
end;
end;
//not a kernel symbol
{$endif}
//check the symbols
// if (symbolloaderthread<>nil) then
if (symbolloaderthread<>nil) then
begin
//it's not a valid address, it's not a calculation, it's not a modulename+offset, so lets see if it's a symbol
//check if it's in
tokens[i]:=StringReplace(tokens[i],'!','.',[]);
si:=nil;
{$IFDEF windows}
if dotNetDataCollector.Attached then
begin
//check the dotnet list first. (if it's a .net process it's more likely the user wants .net stuff)
dotnetModuleSymbolListMREW.beginread;
for j:=0 to length(dotnetModuleSymbolList)-1 do
begin
si:=dotnetModuleSymbolList[j].symbollist.FindSymbol(tokens[i]);
if si<>nil then break;
end;
dotnetModuleSymbolListMREW.Endread;
end;
{$ENDIF}
if si=nil then
begin
symbollistsMREW.Beginread;
for j:=0 to length(symbollists)-1 do
begin
si:=symbollists[j].FindSymbol(tokens[i]);
if si<>nil then break;
end;
symbollistsMREW.EndRead;
if si=nil then
si:=symbollist.FindSymbol(tokens[i]);
end;
if si=nil then //not found
begin
{$ifdef windows}
if uppercase(copy(tokens[i],1,11))='THREADSTACK' then
begin
s:=copy(tokens[i], 12, length(tokens[i])-12+1);
if s='' then s:='0';
if TryStrToInt(s, j) then
begin
a:=GetStackStart(j);
if a<>0 then
begin
tokens[i]:=inttohex(ApplyTokenType(a),8);
continue;
end;
end;
end;
{$endif}
//if si=nil then //STILL not found. Check if it's a structure.element notation
// begin
if LookupStructureOffset(tokens[i], offset) then
begin
tokens[i]:=inttohex(ApplyTokenType(offset),8);
continue;
end;
// end;
if symbolloaderthread.isloading and (waitforsymbols) then
begin
a:=symbolloaderthread.getAddressFromSymbol(tokens[i]);
if a<>0 then
begin
tokens[i]:=inttohex(ApplyTokenType(a),8);
continue;
end;
if symbolloaderthread.isloading and (waitingfrm<>nil) then
begin
haserror:=true;
exit; //the user canceled it
end;
end;
if waitforsymbols then
begin
waitforsymbolsloaded;
//check again now that the symbols are loaded
si:=symbollist.FindSymbol(tokens[i]);
end;
end;
if si<>nil then
begin
if (si.extra<>nil) and (si.extra.forwarder) then
begin
if (si.extra.forwardsTo=0) then
begin
//parse the string at this address
getmem(p,128);
if not targetself then
haserror:=not readprocessmemory(processhandle, pointer(si.address),p,127,br)
else
haserror:=not readprocessmemory(GetCurrentProcess, pointer(si.address),p,127,br);
p[br]:=#0;
si.extra.forwardsTo:=getAddressFromName(p, waitforsymbols, hasError, context, shallow);
si.extra.forwardsToString:=p;
freememandnil(p);
end;
tokens[i]:=inttohex(ApplyTokenType(si.extra.forwardsto),8);
end
else
tokens[i]:=inttohex(ApplyTokenType(si.address),8);
continue;
end;
end;
end;
//check if it's lua (old style)
if tokens[i][1]='$' then
begin
//try lua
j:=lua_gettop(luavm); //make sure the stack ends here when done
try
s:=copy(tokens[i], 2, length(tokens[i]));
lua_getglobal(LuaVM,pchar(s));
if lua_isnil(luavm,-1) then //not found as a single global var
begin
lua_settop(luavm,j);
//try lua function call method
if lua_dostring(Luavm,pchar('return '+s))<>0 then
begin
lua_settop(luavm, j);
lua_pushnil(Luavm);
end;
end;
//convert the result to a hexstring
k:=lua_type(LuaVM, j+1);
if lua_isuserdata(LuaVM, j+1) then
begin
tokens[i]:=inttohex(ptruint(lua_toceuserdata(Luavm, j+1)),8);
continue;
end
else
if (k<>LUA_TSTRING) and (lua_isnumber(LuaVM, j+1)) then
begin
tokens[i]:=inttohex(ApplyTokenType(lua_tointeger(LuaVM, j+1)),8);
continue;
end
else
if lua_isstring(LuaVM, j+1) then
begin
s:=lua_tostring(LuaVM, j+1);
if pos('$',s)=0 then //prevent inf lua loops
begin
try
tokens[i]:=inttohex(ApplyTokenType(getAddressFromName(s)),8);
except
//fail, try one more time with quotes
tokens[i]:=inttohex(ApplyTokenType(getAddressFromName('"'+s+'"')),8);
end;
continue;
end;
end;
finally
lua_settop(luavm,j);
end;
end;
//not a register or symbol
if not shallow then
begin
result:=callbackCheck(tokens[i], slNotSymbol);
if result>0 then
begin
tokens[i]:=inttohex(ApplyTokenType(result),8);
continue;
end;
end;
//One last attempt to fix it, check if it is the last symbol, if not add it. (perhaps the symbol got split into tokens)
if i<length(tokens)-1 then
begin
tokens[i+1]:=tokens[i]+tokens[i+1]; //(if not, it will error out eventually anyhow)
tokens[i]:=''; //empty
end
else
begin
//failure
if not shallow then
begin
result:=callbackCheck(tokens[i], slFailure);
if result>0 then
begin
tokens[i]:=inttohex(ApplyTokenType(result),8);
continue;
end;
end;
haserror:=true;
exit;
end;
end;
end
else
tokens[i]:=inttohex(applytokentype(result),8);
end
else
begin
//it's not a real token
if (length(tokens[i])>0) then
case tokens[i][1] of
'*' : hasMultiplication:=true;
'(':
begin
//could be a typecast
if (length(tokens)>i+2) and (tokens[i+2]=')') then //(something)
begin
if isTypeToken(tokens[i+1], nextTokenType) then //is something one of the types
begin
//it's a typecast, not part of the symbol
tokens[i]:='';
tokens[i+1]:='';
tokens[i+2]:='';
continue;
end;
end;
s:='';
for j:=i+1 to length(tokens)-1 do
begin
if tokens[j]=')' then
begin
mr:=MainForm.addresslist.getRecordWithDescription(s);
if mr<>nil then
begin
for k:=i+1 to j do
tokens[k]:='';
tokens[i]:=inttohex(mr.CachedAddress,1);
end;
break;
end
else
s:=s+tokens[j];
end;
end;
'[':
begin
hasPointer:=true;
pointerstartlist[pointerstartpos].start:=i;
pointerstartlist[pointerstartpos].tokentype:=nexttokentype;
nexttokentype:=ttQword;
inc(pointerstartpos);
if pointerstartpos>=pointerstartmax then
begin
pointerstartmax:=pointerstartmax*2;
setlength(pointerstartlist, pointerstartmax);
end;
end;
']':
begin
if haspointer then
begin
//parse since the last pointerstart
s:='';
if pointerstartpos=0 then
begin
haserror:=true;
exit;
end;
dec(pointerstartpos);
k:=pointerstartlist[pointerstartpos].start;
for j:=k+1 to i-1 do
begin
s:=s+tokens[j];
tokens[j]:='';
end;
a:=getAddressFromName(s,waitforsymbols, haserror, context);
if haserror then exit;
if not targetself then
haserror:=not readprocessmemory(processhandle, pointer(a),@a,processhandler.pointersize,br)
else
haserror:=not readprocessmemory(GetCurrentProcess, pointer(a),@a,{$ifdef cpu32}4{$else}8{$endif},br);
if haserror then exit;
tokens[i]:='';
nexttokentype:=pointerstartlist[pointerstartpos].tokentype;
tokens[k]:=inttohex(ApplyTokenType(a),8);
if pointerstartpos=0 then
haspointer:=false;
end
else
begin
haserror:=true;
exit;
end;
end;
end;
end;
end;
finally
symbolloadervalid.endread;
end;
{ mathstring:='';
for i:=0 to length(tokens)-1 do
mathstring:=mathstring+tokens[i];
}
{
if haspointer then
begin
result:=GetAddressFromPointer(mathstring,haserror);
exit;
end; }
if hasmultiplication then
begin
//remove the empty tokens
i:=0;
while i<length(tokens)-1 do
begin
if tokens[i]='' then
begin
for j:=i to length(tokens)-2 do
tokens[j]:=tokens[j+1];
setlength(tokens, length(tokens)-1);
continue;
end;
inc(i);
end;
end;
//handle the mathstring
try
if hasmultiplication then
begin
//first do the multiplications
for i:=0 to length(tokens)-1 do
begin
if tokens[i]='*' then
begin
//multiply the left and right
tokens[i-1]:=inttohex(StrToQWordEx('$'+tokens[i-1])*strtoint64('$'+tokens[i+1]),8);
tokens[i]:='';
tokens[i+1]:='';
end;
end;
end;
result:=0;
//handle addition and subtraction
nextoperation:=calcAddition;
for i:=0 to length(tokens)-1 do
begin
if length(tokens[i])>0 then
begin
case tokens[i][1] of
'+' : nextoperation:=calcAddition;
'-' :
begin
if nextoperation=calcSubstraction then
nextoperation:=calcAddition else //--=+
nextoperation:=calcSubstraction;
end;
else
begin
//do the calculation
case nextoperation of
calcAddition:
result:=result+StrToQWordEx('$'+tokens[i]);
calcSubstraction:
result:=result-StrToQWordEx('$'+tokens[i]);
end;
nextoperation:=calcAddition;
end;
end;
end;
end;
except
hasError:=true;
end;
end;
function TSymhandler.GetLayoutFromAddress(address: ptruint; var addressdata: TAddressData): boolean;
begin
result:=false;
{$IFDEF windows}
if hasDotNetAccess then
begin
try
if dotNetDataCollector.Attached then
dotNetDataCollector.GetAddressData(address, addressdata);
result:=addressdata.startaddress<>0;
except
freeandnil(dotNetDataCollector);
end;
end;
{$ENDIF}
end;
function TSymhandler.loadmodulelist: boolean; //todo: change to a quicker lookup kind of storage (tree)
var
ths: thandle;
me32:MODULEENTRY32;
s: string;
x: string;
i: integer;
processid: dword;
modulename: string;
alreadyInTheList: boolean;
// oldmodulelist: array of qword;
is64bitprocess: boolean;
newmodulelist: TModuleInfoArray;
newmodulelistpos: integer;
sectionlist: TStringlist;
si: TSectionInfo;
begin
result:=false;
is64bitprocess:=processhandler.is64Bit;
ZeroMemory(@me32, sizeof(MODULEENTRY32));
try
if targetself then
processid:=getcurrentprocessid
else
processid:=processhandlerunit.ProcessID;
if processid=0 then exit;
{
modulelistMREW.beginread;
//make a copy of the old list addresses to compare against
setlength(oldmodulelist, modulelistpos);
for i:=0 to modulelistpos-1 do
oldmodulelist[i]:=modulelist[i].baseaddress;
modulelistMREW.Endread; }
//Note: Just TH32CS_SNAPMODULE32 will result in an empty list
//Just TH32CS_SNAPMODULE only returns the 64-bit modules
//There doesn't seem to be a way to make two lists, 32-bit, then 64-bit, and combine them afterwards
//So for now I just check if it's a system dll, and if so, if it's in the wow64 folder or not
ths:=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE or TH32CS_SNAPMODULE32 {$ifdef darwin}or ifthen(targetself, TH32CS_SNAPMODULENOSYM,0){$endif},processid);
modulelistMREW.BeginRead;
try
newmodulelistpos:=0;
setlength(newmodulelist, length(modulelist));
if ths<>0 then
begin
me32.dwSize:=sizeof(MODULEENTRY32);
if ths<>0 then
begin
try
if module32first(ths,me32) then
repeat
s:=WinCPToUTF8(pchar(@me32.szExePath[0]));
x:=s;
if (s[1]<>'[') then //do not extract the filename if it's a 'special' marker
modulename:=extractfilename(s)
else
modulename:=s;
alreadyInTheList:=false;
//check if this modulename is already in the list, and if so check if it's the same base, else add it
for i:=0 to newmodulelistpos-1 do
begin
if (newmodulelist[i].baseaddress=ptrUint(me32.modBaseAddr)) then
begin
alreadyInTheList:=true;
break; //it's in the list, no need to continue looking, break out of the for loop
end;
end;
if not alreadyInTheList then
begin
if newmodulelistpos+1>=length(newmodulelist) then
setlength(newmodulelist,length(newmodulelist)*2);
newmodulelist[newmodulelistpos].modulename:=modulename;
newmodulelist[newmodulelistpos].modulepath:=x;
//all windows folder files are system modules, except when it is an .exe (minesweeper in xp)
newmodulelist[newmodulelistpos].isSystemModule:=(pos(lowercase(windowsdir),lowercase(x))>0) and (ExtractFileExt(lowercase(x))<>'.exe');
newmodulelist[newmodulelistpos].baseaddress:=ptrUint(me32.modBaseAddr);
newmodulelist[newmodulelistpos].basesize:=me32.modBaseSize;
if not processhandler.isNetwork then
begin
{$ifdef darwin}
newmodulelist[newmodulelistpos].is64bitmodule:=me32.is64bit; //I own this struct now so yes...
{$endif}
{$ifdef windows}
if targetself=false then //not useful for CE
begin
sectionlist:=tstringlist.create;
if peinfo_getSectionList(newmodulelist[newmodulelistpos].baseaddress,sectionlist) then
begin
setlength(newmodulelist[newmodulelistpos].sections, sectionlist.count);
for i:=0 to sectionlist.count-1 do
begin
si:=TSectionInfo(sectionlist.Objects[i]);
newmodulelist[newmodulelistpos].sections[i].name:=si.name;
newmodulelist[newmodulelistpos].sections[i].size:=si.size;
newmodulelist[newmodulelistpos].sections[i].fileaddress:=si.fileAddress;
newmodulelist[newmodulelistpos].sections[i].address:=si.virtualAddress;
si.Free;
end;
end;
sectionlist.free;
end;
if peinfo_is64bitfile(x, newmodulelist[newmodulelistpos].is64bitmodule)=false then
begin
//fallback
{$ifdef cpu64}
if is64bitprocess then
newmodulelist[newmodulelistpos].is64bitmodule:=true
else
begin
if newmodulelist[newmodulelistpos].isSystemModule then
begin
if pos('wow64', lowercase(ExtractFilePath(x)))>0 then //todo: Open the file and check if it's 64-bit or not
newmodulelist[newmodulelistpos].is64bitmodule:=false
else
newmodulelist[newmodulelistpos].is64bitmodule:=true;
end;
end;
{$endif}
end;
{$endif}
end
else
begin
newmodulelist[newmodulelistpos].is64bitmodule:=processhandler.is64Bit;
if pos('/system/',lowercase(x))=1 then //android thingy
newmodulelist[newmodulelistpos].isSystemModule:=true;
end;
if (not newmodulelist[newmodulelistpos].isSystemModule) and (commonModuleList<>nil) then //check if it's a common module (e.g nvidia physx dll's)
newmodulelist[newmodulelistpos].isSystemModule:=commonModuleList.IndexOf(lowercase(newmodulelist[newmodulelistpos].modulename))<>-1;
inc(newmodulelistpos);
if (modulelistpos=0) or (newmodulelistpos>modulelistpos) or (modulelist[newmodulelistpos-1].baseaddress<>newmodulelist[newmodulelistpos-1].baseaddress) then //different size or different order, return true
result:=true; //different
end;
until not module32next(ths,me32);
finally
closehandle(ths);
end;
end;
end;
finally
modulelistmrew.EndRead;
end;
if newmodulelistpos<>modulelistpos then
result:=true;
{begin
for i:=0 to modulelistpos-1 do
begin
if oldmodulelist[i]<>modulelist[i].baseaddress then
begin
//the order changed
result:=true;
break;
end;
end;
end
else
result:=true; //the length of the list changed}
if result=true then
begin
modulelistMREW.BeginWrite;
try
modulelist:=newmodulelist;
modulelistpos:=newmodulelistpos;
finally
modulelistMREW.EndWrite;
end;
end;
except
//MessageBox(0,'procedure TSymhandler.loadmodulelist','procedure TSymhandler.loadmodulelist',0);
end;
{$ifndef jni}
if result then
reinitializeDisassemblerComments; //the comments list is depending on the modulelist since it is written using modulename+offset
{$endif}
end;
function TSymhandler.LookupStructureOffset(s: string; out offset: integer): boolean;
//will search all defines structures and when found return the offset in "offset"
//if found, return true, else false
var
i,j: integer;
structurename: string;
elementname: string;
begin
result:=false;
{$IFNDEF jni}
i:=pos('.', s); //check for the .
if i>0 then
begin
//it has one
structurename:=copy(s, 1, i-1);
elementname:=copy(s, i+1, length(s)); //just the rest
if (trim(structurename)<>'') and (trim(elementname)<>'') then
begin
structurename:=uppercase(structurename);
elementname:=uppercase(elementname);
for i:=0 to DissectedStructs.count-1 do
begin
if uppercase(TDissectedStruct(DissectedStructs[i]).name)=structurename then
begin
//found the structure
for j:=0 to TDissectedStruct(DissectedStructs[i]).count-1 do
begin
if uppercase(TDissectedStruct(DissectedStructs[i]).element[j].Name)=elementname then
begin
//found the element
offset:=TDissectedStruct(DissectedStructs[i]).element[j].Offset;
result:=true;
break;
end;
end;
break;
end;
end;
end;
end;
{$ENDIF}
end;
function TSymhandler.GetAddressFromPointer(s: string; var error: boolean):ptrUint;
{
Will return the address of a pointer noted as [[[xxx+xx]+xx]+xx]+xx
If it is a invalid pointer, or can not be resolved, the result is NULL
}
var i, pointersize: integer;
list: tstringlist;
offsets: array of integer;
baseaddress: ptruint;
off: string;
realaddress, realaddress2: ptrUint;
check: boolean;
count: PtrUInt;
processhandle: THandle;
begin
result:=0;
error:=true;
if not targetself then
begin
processhandle:=processhandlerunit.processhandle;
pointersize:=processhandler.pointersize;
end
else
begin
processhandle:=GetCurrentProcess;
pointersize:={$ifdef cpu32}4{$else}8{$endif};
end;
list:=tstringlist.create;
try
if not ParseAsPointer(s,list) then exit;
try
baseaddress:=getaddressfromname(list[0]);
except
exit;
end;
setlength(offsets,list.count-1);
for i:=1 to list.Count-1 do //start from the first offset
begin
off:=copy(list[i],2,length(list[i]));
try
offsets[i-1]:=StrToQWordEx('$'+off);
except
exit;
end;
if list[i][1]='-' then
offsets[i-1]:=-offsets[i-1];
end;
//still here so notation was correct and baseaddress+offsets are filled in
//now read
realaddress2:=baseaddress;
for i:=0 to length(offsets)-1 do
begin
realaddress:=0;
check:=readprocessmemory(processhandle,pointer(realaddress2),@realaddress,pointersize,count);
if check and (count=pointersize) then
realaddress2:=realaddress+offsets[i]
else
exit;
end;
result:=realaddress2;
error:=false;
finally
list.free;
end;
end;
function TSymhandler.ParseRange(s: string; var start: QWORD; var stop: QWORD): boolean;
var
tokens: ttokens;
i: integer;
t2start: integer=0;
s1,s2: string;
err: boolean=false;
begin
result:=false;
tokenize(s, tokens);
if length(tokens)=0 then exit;
//first find the first part
s1:='';
for i:=0 to length(tokens)-2 do
begin
s1:=s1+tokens[i];
err:=false;
start:=symhandler.getAddressFromName(s1, true, err);
if (err=false) and (tokens[i+1]='-') then
begin
t2start:=i+2;
break;
end;
end;
if err then exit;
s2:='';
for i:=t2start to length(tokens)-1 do
s2:=s2+tokens[i];
stop:=symhandler.getAddressFromName(s2, true, err);
result:=not err;
end;
function TSymhandler.ParseAsPointer(s: string; list:tstrings): boolean;
var i: integer;
prolog: boolean;
currentlevel: integer;
temps: string;
ispointer: boolean;
begin
//parse the string
result:=false;
currentlevel:=0;
prolog:=true;
temps:='';
ispointer:=false;
for i:=1 to length(s) do
begin
if s[i]='[' then
begin
if prolog then
begin
inc(currentlevel);
ispointer:=true;
end
else
exit; //bracket open after the prolog is not allowed
end
else
begin
if prolog then
begin
if not (s[i] in [#8,' ']) then //no space or tab
prolog:=false;
end;
if not prolog then
begin
//definition, currentlevel is set, now parse till last ] (currentlevel=0)
if s[i]=']' then //end of a level
begin
dec(currentlevel);
if temps='' then temps:='+0';
list.Add(temps);
temps:='';
if currentlevel<0 then exit;
continue;
end
else
temps:=temps+s[i];
end;
end;
end;
if temps='' then temps:='+0';
if (ispointer) and (temps<>'') then list.Add(temps);
if currentlevel>0 then exit;
result:=ispointer;
end;
function TSymhandler.getCommonModuleList;
begin
result:=commonModuleList;
end;
procedure TSymhandler.loadCommonModuleList;
{
Loads the commonmodules list which is used by the module enumaration to flag modules as a system dll's
}
var
s: string;
i,j: integer;
begin
s:=cheatenginedir+'commonmodulelist.txt';
if FileExists(s) then //if the list exists
begin
if commonModuleList=nil then
commonModuleList:=tstringlist.create;
commonModuleList.Clear;
try
commonModuleList.LoadFromFile(s{$if FPC_FULLVERSION>=030200},true{$endif});
for i:=commonModuleList.Count-1 downto 0 do
begin
j:=pos('#', commonModuleList[i]);
if j>0 then
commonModuleList[i]:=copy(commonModuleList[i], 1, j-1);
commonModuleList[i]:=lowercase(trim(commonModuleList[i]));
if commonModuleList[i]='' then commonModuleList.Delete(i);
end;
except
//don't care if file can't be loaded anyhow
end;
end;
end;
procedure TSymhandler.RemoveFinishedLoadingSymbolsNotification(n: TNotifyEvent);
var i,j: integer;
begin
//search and destroy
for i:=0 to length(SymbolsLoadedNotification)-1 do
if (TMethod(SymbolsLoadedNotification[i]).Data = TMethod(n).Data) and (TMethod(SymbolsLoadedNotification[i]).Code = TMethod(n).Code) then
begin
for j:=i to length(SymbolsLoadedNotification)-2 do
SymbolsLoadedNotification[j]:=SymbolsLoadedNotification[j+1];
setlength(SymbolsLoadedNotification, length(SymbolsLoadedNotification)-1);
break;
end;
end;
procedure TSymhandler.AddSymbolList(sl: TSymbolListHandler);
var i: integer;
begin
symbollistsMREW.beginwrite;
try
for i:=0 to length(symbollists)-1 do
if symbollists[i]=sl then exit; //already in the list
setlength(symbollists, length(symbollists)+1);
symbollists[length(symbollists)-1]:=sl;
finally
symbollistsMREW.Endwrite;
end;
end;
procedure TSymhandler.RemoveSymbolList(sl: TSymbolListHandler);
var i,j: integer;
begin
symbollistsMREW.Beginwrite;
try
for i:=0 to length(symbollists)-1 do
if symbollists[i]=sl then
begin
for j:=i to length(symbollists)-2 do
symbollists[i]:=symbollists[i+1];
setlength(symbollists, length(symbollists)-1);
end;
finally
symbollistsMREW.Endwrite;
end;
end;
procedure TSymhandler.AddFinishedLoadingSymbolsNotification(n: TNotifyEvent); //there is no remove
begin
setlength(SymbolsLoadedNotification, length(SymbolsLoadedNotification)+1);
SymbolsLoadedNotification[length(SymbolsLoadedNotification)-1]:=n;
end;
procedure TSymhandler.NotifyFinishedLoadingSymbols;
var i: integer;
begin
//tell all notification routines that the symbollist has been updated and is ready for use
for i:=0 to length(SymbolsLoadedNotification)-1 do
if assigned(SymbolsLoadedNotification[i]) then
SymbolsLoadedNotification[i](self);
end;
destructor TSymhandler.destroy;
begin
if symbolloaderthread<>nil then
begin
symbolloaderthread.Terminate;
symbolloaderthread.WaitFor;
freeandnil(symbolloaderthread);
end;
if (symbollist<>nil) then
symbollist.free;
if commonModuleList<>nil then
commonModuleList.free;
modulelistpos:=0;
symbolloadervalid.Free;
modulelistMREW.free;
userdefinedsymbolsCS.free;
symbollistsMREW.free;
setlength(userdefinedsymbols,0);
setlength(modulelist,0);
{$IFDEF windows}
if symbolDataBase<>nil then
freeandnil(symbolDataBase);
{$ENDIF}
end;
constructor TSymhandler.create;
begin
//log('TSymhandler.create');
symbolloadervalid:=TMultiReadExclusiveWriteSynchronizer.create;
modulelistMREW:=TMultiReadExclusiveWriteSynchronizer.create;
userdefinedsymbolsCS:=TCriticalSection.create;
symbollistsMREW:=TMultiReadExclusiveWriteSynchronizer.Create;
{$IFDEF windows}
dotnetModuleSymbolListMREW:=TMultiReadExclusiveWriteSynchronizer.create;
// log('TSymhandler.create 1');
dotNetDataCollector:=TDotNetPipe.create;
{$ENDIF}
//log('TSymhandler.create 2');
//setlength(internalsymbols,4);
setlength(userdefinedsymbols,32);
setlength(modulelist,32);
showmodules:=true;
showsymbols:=true;
ExceptionOnLuaLookup:=true;
// log('TSymhandler.create 3');
symbollist:=TSymbolListHandler.create;
// log('TSymhandler.create exit');
end;
procedure symhandlerInitialize;
var psa,dbghlp: THandle;
begin
symbolloaderthreadcs:=TCriticalSection.Create;
symhandler:=tsymhandler.create;
if selfsymhandler=nil then
begin
selfsymhandler:=Tsymhandler.create;
selfsymhandler.targetself:=true;
selfsymhandler.reinitialize;
end;
{$ifdef windows}
{$ifdef cpu32}
dbghlp:=LoadLibrary(pchar(CheatEngineDir+'\win32\dbghelp.dll'));
{$else}
dbghlp:=LoadLibrary(pchar(CheatEngineDir+'\win64\dbghelp.dll'));
{$endif}
if dbghlp=0 then //fallback to the search path
dbghlp:=loadlibrary('Dbghelp.dll');
SymFromName:=GetProcAddress(dbghlp,'SymFromName');
SymFromAddr:=GetProcAddress(dbghlp,'SymFromAddr');
SymSearch:=GetProcAddress(dbghlp,'SymSearch');
StackWalkEx:=GetProcAddress(dbghlp,'StackWalkEx');
SymLoadModuleEx:=GetProcAddress(dbghlp,'SymLoadModuleEx');
UnDecorateSymbolName:=GetProcAddress(dbghlp,'UnDecorateSymbolName');
psa:=loadlibrary('Psapi.dll');
EnumProcessModules:=GetProcAddress(psa,'EnumProcessModules');
EnumProcessModulesEx:=GetProcAddress(psa,'EnumProcessModulesEx');
GetModuleFileNameEx:=GetProcAddress(psa,'GetModuleFileNameExA');
if not assigned(EnumProcessModulesEx) then
EnumProcessModulesEx:=EnumProcessModulesExNotImplemented;
{$endif}
end;
procedure initDatabasePath; //just sets up the variable. Path creation will happen when needed (so trainers don't make it)
var
reg: Tregistry;
dontusetempdir: boolean=false;
alt: string='';
usedtempdir: string;
begin
databasepath:='';
reg:=Tregistry.Create; //do this as the settings may not have been loaded yet
try
Reg.RootKey := HKEY_CURRENT_USER;
if Reg.OpenKey('\Software\Cheat Engine',false) then
begin
if reg.ValueExists('Don''t use tempdir') then
dontusetempdir:=reg.ReadBool('Don''t use tempdir');
if reg.ValueExists('Scanfolder') then
alt:=trim(reg.ReadString('Scanfolder'));
if length(alt)<=2 then dontusetempdir:=false;
end;
finally
reg.free;
end;
if dontusetempdir then
usedtempdir:=alt;
if (length(trim(tempdiralternative))>2) and dontusetempdir then
usedtempdir:=alt
else
usedtempdir:=trim(GetTempDir);
if trim(usedtempdir)='' then
usedtempdir:=GetCEdir;
if DirectoryExistsUTF8(usedtempdir)=false then
begin
usedtempdir:=WinCPToUTF8(usedtempdir); //perhaps it was in CP
if DirectoryExistsUTF8(usedtempdir)=false then
begin //not UTF8 or CP, get the CE folder
usedtempdir:=GetCEdir;
if DirectoryExistsUTF8(usedtempdir)=false then //perhaps the ce folder was in CP ???
begin
usedtempdir:=WinCPToUTF8(usedtempdir);
if DirectoryExistsUTF8(usedtempdir)=false then
exit; //fuck it , this user doesn't even DESERVE structures now...
end;
end;
end;
if usedtempdir='' then exit;
if usedtempdir[length(usedtempdir)]<>PathDelim then
usedtempdir:=usedtempdir+PathDelim;
databasepath:=usedtempdir+'Cheat Engine Symbols'+pathdelim+'structures.sqlite';
end;
initialization
initDatabasePath;
finalization
if selfsymhandler<>nil then
freeandnil(selfsymhandler);
if symhandler<>nil then
freeandnil(symhandler);
if symbolloaderthreadcs<>nil then
freeandnil(symbolloaderthreadcs);
end.
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/phy0292/cheat-engine.git
git@gitee.com:phy0292/cheat-engine.git
phy0292
cheat-engine
cheat-engine
master

搜索帮助