dbgsym.c 84 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. dbgsym.c
  5. Abstract:
  6. This module implements high level symbol support for the debugger.
  7. Author:
  8. Evan Green 7-May-2013
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "dbgrtl.h"
  16. #include <minoca/debug/spproto.h>
  17. #include <minoca/lib/im.h>
  18. #include <minoca/debug/dbgext.h>
  19. #include "symbols.h"
  20. #include "dbgapi.h"
  21. #include "dbgrprof.h"
  22. #include "dbgrcomm.h"
  23. #include "dbgsym.h"
  24. #include <assert.h>
  25. #include <errno.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. //
  30. // ---------------------------------------------------------------- Definitions
  31. //
  32. //
  33. // Define a constant representing the maximum string length of an address
  34. // symbol offset. This is equal to the length of "+0x0000000000000000".
  35. //
  36. #define OFFSET_MAX_LENGTH 19
  37. #define LINE_NUMBER_STRING_LENGTH 9
  38. #define MAX_LINE_NUMBER 99999999
  39. //
  40. // ------------------------------------------------------ Data Type Definitions
  41. //
  42. typedef union _NUMERIC_UNION {
  43. UCHAR Uint8;
  44. CHAR Int8;
  45. USHORT Uint16;
  46. SHORT Int16;
  47. ULONG Uint32;
  48. LONG Int32;
  49. ULONGLONG Uint64;
  50. LONGLONG Int64;
  51. float Float32;
  52. double Float64;
  53. } NUMERIC_UNION, *PNUMERIC_UNION;
  54. //
  55. // ----------------------------------------------- Internal Function Prototypes
  56. //
  57. //
  58. // -------------------------------------------------------------------- Globals
  59. //
  60. //
  61. // ------------------------------------------------------------------ Functions
  62. //
  63. INT
  64. DbgPrintAddressSymbol (
  65. PDEBUGGER_CONTEXT Context,
  66. ULONGLONG Address
  67. )
  68. /*++
  69. Routine Description:
  70. This routine prints a descriptive version of the given address, including
  71. the module and function name if possible.
  72. Arguments:
  73. Context - Supplies a pointer to the application context.
  74. Address - Supplies the virtual address of the target to print information
  75. about.
  76. Return Value:
  77. 0 if information was successfully printed.
  78. Returns an error code on failure.
  79. --*/
  80. {
  81. PSTR AddressSymbol;
  82. AddressSymbol = DbgGetAddressSymbol(Context, Address);
  83. if (AddressSymbol == NULL) {
  84. return ENOENT;
  85. }
  86. DbgOut("%s", AddressSymbol);
  87. free(AddressSymbol);
  88. return 0;
  89. }
  90. PSTR
  91. DbgGetAddressSymbol (
  92. PDEBUGGER_CONTEXT Context,
  93. ULONGLONG Address
  94. )
  95. /*++
  96. Routine Description:
  97. This routine gets a descriptive string version of the given address,
  98. including the module and function name if possible. It is the caller's
  99. responsibility to free the returned string.
  100. Arguments:
  101. Context - Supplies a pointer to the application context.
  102. Address - Supplies the virtual address of the target to get information
  103. about.
  104. Return Value:
  105. Returns a null-terminated string if successfull, or NULL on failure.
  106. --*/
  107. {
  108. PSTR FunctionName;
  109. PSOURCE_LINE_SYMBOL Line;
  110. LONG LineNumber;
  111. PDEBUGGER_MODULE Module;
  112. ULONGLONG Offset;
  113. PSYMBOL_SEARCH_RESULT ResultValid;
  114. SYMBOL_SEARCH_RESULT SearchResult;
  115. PSTR Symbol;
  116. ULONG SymbolSize;
  117. Line = NULL;
  118. //
  119. // Attempt to get the module this address is in. If one cannot be found,
  120. // then there is no useful information to print, so exit.
  121. //
  122. Module = DbgpFindModuleFromAddress(Context, Address, &Address);
  123. if (Module == NULL) {
  124. SymbolSize = OFFSET_MAX_LENGTH + sizeof(CHAR);
  125. Symbol = malloc(SymbolSize);
  126. if (Symbol == NULL) {
  127. return NULL;
  128. }
  129. sprintf(Symbol, "0x%08I64x", Address);
  130. return Symbol;
  131. }
  132. //
  133. // Attempt to find the current function symbol in the module.
  134. //
  135. SearchResult.Variety = SymbolResultInvalid;
  136. ResultValid = NULL;
  137. if (Module->Symbols != NULL) {
  138. ResultValid = DbgLookupSymbol(Module->Symbols, Address, &SearchResult);
  139. }
  140. //
  141. // If a symbol was found, allocate a buffer of the appropriate size and
  142. // print the string into that buffer.
  143. //
  144. if (ResultValid != NULL) {
  145. if (SearchResult.Variety == SymbolResultFunction) {
  146. LineNumber = 0;
  147. if ((Context->Flags & DEBUGGER_FLAG_PRINT_LINE_NUMBERS) != 0) {
  148. Line = DbgLookupSourceLine(Module->Symbols, Address);
  149. if (Line != NULL) {
  150. LineNumber = Line->LineNumber;
  151. if (LineNumber > MAX_LINE_NUMBER) {
  152. LineNumber = MAX_LINE_NUMBER;
  153. }
  154. }
  155. }
  156. //
  157. // Determine the size of the function string, accounting for the
  158. // module name, function name, the separating exclamation point
  159. // and the NULL terminating character.
  160. //
  161. SymbolSize = RtlStringLength(Module->ModuleName) +
  162. (sizeof(CHAR) * 2);
  163. FunctionName = SearchResult.U.FunctionResult->Name;
  164. if (FunctionName != NULL) {
  165. SymbolSize += RtlStringLength(FunctionName);
  166. }
  167. //
  168. // If there's a line number, also include space for a space,
  169. // open bracket, source file string, colon, line number, and
  170. // close bracket.
  171. //
  172. if (Line != NULL) {
  173. SymbolSize += RtlStringLength(Line->ParentSource->SourceFile) +
  174. LINE_NUMBER_STRING_LENGTH +
  175. (4 * sizeof(CHAR));
  176. }
  177. //
  178. // Add additional length if an offset needs to be appended.
  179. //
  180. Offset = Address - SearchResult.U.FunctionResult->StartAddress;
  181. if (Offset != 0) {
  182. SymbolSize += OFFSET_MAX_LENGTH;
  183. }
  184. Symbol = malloc(SymbolSize);
  185. if (Symbol == NULL) {
  186. return NULL;
  187. }
  188. if (Offset != 0) {
  189. if (Line != NULL) {
  190. snprintf(Symbol,
  191. SymbolSize,
  192. "%s!%s+0x%I64x [%s:%d]",
  193. Module->ModuleName,
  194. SearchResult.U.FunctionResult->Name,
  195. Offset,
  196. Line->ParentSource->SourceFile,
  197. LineNumber);
  198. } else {
  199. snprintf(Symbol,
  200. SymbolSize,
  201. "%s!%s+0x%I64x",
  202. Module->ModuleName,
  203. SearchResult.U.FunctionResult->Name,
  204. Offset);
  205. }
  206. } else {
  207. if (Line != NULL) {
  208. snprintf(Symbol,
  209. SymbolSize,
  210. "%s!%s [%s:%d]",
  211. Module->ModuleName,
  212. SearchResult.U.FunctionResult->Name,
  213. Line->ParentSource->SourceFile,
  214. LineNumber);
  215. } else {
  216. snprintf(Symbol,
  217. SymbolSize,
  218. "%s!%s",
  219. Module->ModuleName,
  220. SearchResult.U.FunctionResult->Name);
  221. }
  222. }
  223. return Symbol;
  224. } else if (SearchResult.Variety == SymbolResultData) {
  225. //
  226. // Determine the size of the data string, accounting for the
  227. // module name, data name, the separating exclamation pointer and
  228. // the NULL terminating character.
  229. //
  230. SymbolSize = RtlStringLength(Module->ModuleName) +
  231. RtlStringLength(SearchResult.U.DataResult->Name) +
  232. (sizeof(CHAR) * 2);
  233. Symbol = malloc(SymbolSize);
  234. if (Symbol == NULL) {
  235. return NULL;
  236. }
  237. sprintf(Symbol,
  238. "%s!%s",
  239. Module->ModuleName,
  240. SearchResult.U.DataResult->Name);
  241. return Symbol;
  242. } else {
  243. return NULL;
  244. }
  245. }
  246. //
  247. // If a symbol was not found, then create a string based on the module name
  248. // and the module offset. Allocate a string accounting for the module name,
  249. // offset length, and NULL terminating character.
  250. //
  251. SymbolSize = RtlStringLength(Module->ModuleName) +
  252. OFFSET_MAX_LENGTH +
  253. sizeof(CHAR);
  254. Symbol = malloc(SymbolSize);
  255. if (Symbol == NULL) {
  256. return NULL;
  257. }
  258. Address += Module->BaseDifference;
  259. if (Address >= Module->BaseAddress) {
  260. Offset = Address - Module->BaseAddress;
  261. sprintf(Symbol, "%s+0x%I64x", Module->ModuleName, Offset);
  262. } else {
  263. Offset = Module->BaseAddress - Address;
  264. sprintf(Symbol, "%s-0x%I64x", Module->ModuleName, Offset);
  265. }
  266. return Symbol;
  267. }
  268. BOOL
  269. DbgGetDataSymbolTypeInformation (
  270. PDATA_SYMBOL DataSymbol,
  271. PTYPE_SYMBOL *TypeSymbol,
  272. PULONG TypeSize
  273. )
  274. /*++
  275. Routine Description:
  276. This routine computes the type and type size of the given data symbol.
  277. Arguments:
  278. DataSymbol - Supplies a pointer to the data symbol whose type and type size
  279. are to be calculated.
  280. TypeSymbol - Supplies a pointer that receives a pointer to the type symbol
  281. that corresponds to the given data symbol.
  282. TypeSize - Supplies a pointer that receives the type size of the given
  283. data symbol.
  284. Return Value:
  285. Returns TRUE on success, or FALSE on failure.
  286. --*/
  287. {
  288. PTYPE_SYMBOL Type;
  289. assert(DataSymbol != NULL);
  290. assert(TypeSize != NULL);
  291. assert(TypeSymbol != NULL);
  292. //
  293. // Get the type information and size.
  294. //
  295. Type = DbgGetType(DataSymbol->TypeOwner, DataSymbol->TypeNumber);
  296. if (Type == NULL) {
  297. DbgOut("Error: Could not lookup type number for data symbol!\n"
  298. "Type was in file %s, symbol number %d\n",
  299. DataSymbol->TypeOwner->SourceFile,
  300. DataSymbol->TypeNumber);
  301. return FALSE;
  302. }
  303. *TypeSize = DbgGetTypeSize(Type, 0);
  304. *TypeSymbol = Type;
  305. return TRUE;
  306. }
  307. INT
  308. DbgGetDataSymbolAddress (
  309. PDEBUGGER_CONTEXT Context,
  310. PDEBUG_SYMBOLS Symbols,
  311. PDATA_SYMBOL DataSymbol,
  312. ULONGLONG DebasedPc,
  313. PULONGLONG Address
  314. )
  315. /*++
  316. Routine Description:
  317. This routine returns the memory address of the given data symbol.
  318. Arguments:
  319. Context - Supplies a pointer to the application context.
  320. Symbols - Supplies a pointer to the module symbols.
  321. DataSymbol - Supplies a pointer to the data symbol whose address is to be
  322. returned.
  323. DebasedPc - Supplies the program counter value, assuming the image were
  324. loaded at its preferred base address (that is, actual PC minus the
  325. loaded base difference of the module).
  326. Address - Supplies a pointer where the debased memory address of the symbol
  327. will be returned. That is, the caller needs to add any loaded base
  328. difference of the module to this value.
  329. Return Value:
  330. 0 on success.
  331. ENOENT if the data symbol is not currently valid.
  332. ERANGE if the data symbol is not stored in memory.
  333. Other error codes on other failures.
  334. --*/
  335. {
  336. PSYMBOLS_GET_ADDRESS_OF_DATA_SYMBOL AddressOf;
  337. INT Status;
  338. if (DebasedPc < DataSymbol->MinimumValidExecutionAddress) {
  339. return ENOENT;
  340. }
  341. switch (DataSymbol->LocationType) {
  342. case DataLocationAbsoluteAddress:
  343. *Address = DataSymbol->Location.Address;
  344. Status = 0;
  345. break;
  346. case DataLocationComplex:
  347. AddressOf = Symbols->Interface->GetAddressOfDataSymbol;
  348. if (AddressOf == NULL) {
  349. DbgOut("Error: Complex symbol had no AddressOf function.\n");
  350. Status = EINVAL;
  351. break;
  352. }
  353. Status = AddressOf(Symbols, DataSymbol, DebasedPc, Address);
  354. break;
  355. default:
  356. Status = ERANGE;
  357. break;
  358. }
  359. return Status;
  360. }
  361. INT
  362. DbgGetDataSymbolData (
  363. PDEBUGGER_CONTEXT Context,
  364. PDEBUG_SYMBOLS Symbols,
  365. PDATA_SYMBOL DataSymbol,
  366. ULONGLONG DebasedPc,
  367. PVOID DataStream,
  368. ULONG DataStreamSize,
  369. PSTR Location,
  370. ULONG LocationSize
  371. )
  372. /*++
  373. Routine Description:
  374. This routine returns the data contained by the given data symbol.
  375. Arguments:
  376. Context - Supplies a pointer to the application context.
  377. Symbols - Supplies a pointer to the module symbols.
  378. DataSymbol - Supplies a pointer to the data symbol whose data is to be
  379. retrieved.
  380. DebasedPc - Supplies the program counter value, assuming the image were
  381. loaded at its preferred base address (that is, actual PC minus the
  382. loaded base difference of the module).
  383. DataStream - Supplies a pointer that receives the data from the data symbol.
  384. DataStreamSize - Supplies the size of the data stream buffer.
  385. Location - Supplies an optional pointer where a string describing the
  386. location of the data symbol will be returned on success.
  387. LocationSize - Supplies the size of the location in bytes.
  388. Return Value:
  389. 0 on success.
  390. ENOENT if the data symbol is not currently active given the current state
  391. of the machine.
  392. Returns an error code on failure.
  393. --*/
  394. {
  395. ULONG BytesRead;
  396. LONGLONG Offset;
  397. INT Printed;
  398. ULONG Register;
  399. INT Result;
  400. ULONGLONG TargetAddress;
  401. ULONGLONG Value;
  402. //
  403. // Collect the data contents for the symbol based on where it is located.
  404. //
  405. switch (DataSymbol->LocationType) {
  406. case DataLocationRegister:
  407. Register = DataSymbol->Location.Register;
  408. if (LocationSize != 0) {
  409. Printed = snprintf(Location,
  410. LocationSize,
  411. "@%s",
  412. DbgGetRegisterName(Symbols->Machine, Register));
  413. if (Printed > 0) {
  414. Location += Printed;
  415. LocationSize -= Printed;
  416. }
  417. }
  418. Result = DbgGetRegister(Context,
  419. &(Context->FrameRegisters),
  420. Register,
  421. &Value);
  422. if (Result != 0) {
  423. goto GetDataSymbolDataEnd;
  424. }
  425. //
  426. // Get a pointer to the data.
  427. //
  428. switch (Context->MachineType) {
  429. case MACHINE_TYPE_X86:
  430. if (DataStreamSize >= 4) {
  431. *(PULONG)DataStream = Value;
  432. DataStream += 4;
  433. DataStreamSize -= 4;
  434. }
  435. if (DataStreamSize >= 4) {
  436. switch (Register) {
  437. case X86RegisterEax:
  438. Register = X86RegisterEdx;
  439. break;
  440. case X86RegisterEbx:
  441. Register = X86RegisterEcx;
  442. break;
  443. default:
  444. DbgOut("Error: Data symbol location was a register, but "
  445. "type size was %d!\n"
  446. "Error: the register was %d.\n",
  447. DataStreamSize,
  448. Register);
  449. break;
  450. }
  451. DbgGetRegister(Context,
  452. &(Context->FrameRegisters),
  453. Register,
  454. &Value);
  455. *(PULONG)DataStream = Value;
  456. }
  457. break;
  458. //
  459. // ARM registers. Since the registers are all in order and are named
  460. // r0-r15, the register number is an offset from the register base, r0.
  461. //
  462. case MACHINE_TYPE_ARM:
  463. if (DataStreamSize >= 4) {
  464. *(PULONG)DataStream = Value;
  465. DataStream += 4;
  466. DataStreamSize -= 4;
  467. }
  468. if (DataStreamSize >= 4) {
  469. DbgGetRegister(Context,
  470. &(Context->FrameRegisters),
  471. Register + 1,
  472. &Value);
  473. *(PULONG)DataStream = Value;
  474. }
  475. break;
  476. //
  477. // Unknown machine type.
  478. //
  479. default:
  480. DbgOut("Error: Unknown machine type %d.\n", Context->MachineType);
  481. Result = EINVAL;
  482. break;
  483. }
  484. break;
  485. case DataLocationIndirect:
  486. Register = DataSymbol->Location.Indirect.Register;
  487. Offset = DataSymbol->Location.Indirect.Offset;
  488. //
  489. // Get the target virtual address and attempt to read from the debuggee.
  490. //
  491. Result = DbgGetRegister(Context,
  492. &(Context->FrameRegisters),
  493. Register,
  494. &TargetAddress);
  495. if (Result != 0) {
  496. DbgOut("Error: Failed to get register %d.\n",
  497. DataSymbol->Location.Indirect.Register);
  498. goto GetDataSymbolDataEnd;
  499. }
  500. TargetAddress += Offset;
  501. if (LocationSize != 0) {
  502. if (Offset >= 0) {
  503. Printed = snprintf(
  504. Location,
  505. LocationSize,
  506. "[@%s+0x%I64x]",
  507. DbgGetRegisterName(Symbols->Machine, Register),
  508. Offset);
  509. } else {
  510. Printed = snprintf(
  511. Location,
  512. LocationSize,
  513. "[@%s-0x%I64x]",
  514. DbgGetRegisterName(Symbols->Machine, Register),
  515. -Offset);
  516. }
  517. if (Printed > 0) {
  518. Location += Printed;
  519. LocationSize -= Printed;
  520. }
  521. }
  522. Result = DbgReadMemory(Context,
  523. TRUE,
  524. TargetAddress,
  525. DataStreamSize,
  526. DataStream,
  527. &BytesRead);
  528. if ((Result != 0) || (BytesRead != DataStreamSize)) {
  529. if (Result == 0) {
  530. Result = EINVAL;
  531. }
  532. DbgOut("Error: Type is %d bytes large, but only %d bytes could be "
  533. "read from the target!\n",
  534. DataStreamSize,
  535. BytesRead);
  536. goto GetDataSymbolDataEnd;
  537. }
  538. break;
  539. case DataLocationAbsoluteAddress:
  540. TargetAddress = DataSymbol->Location.Address;
  541. if (LocationSize != 0) {
  542. Printed = snprintf(Location,
  543. LocationSize,
  544. "[%+I64x]",
  545. TargetAddress);
  546. if (Printed > 0) {
  547. Location += Printed;
  548. LocationSize -= Printed;
  549. }
  550. }
  551. Result = DbgReadMemory(Context,
  552. TRUE,
  553. TargetAddress,
  554. DataStreamSize,
  555. DataStream,
  556. &BytesRead);
  557. if ((Result != 0) || (BytesRead != DataStreamSize)) {
  558. if (Result == 0) {
  559. Result = EINVAL;
  560. }
  561. DbgOut("Error: Type is %d bytes large, but only %d bytes could be "
  562. "read from the target!\n",
  563. DataStreamSize,
  564. BytesRead);
  565. goto GetDataSymbolDataEnd;
  566. }
  567. break;
  568. case DataLocationComplex:
  569. if (Symbols->Interface->ReadDataSymbol == NULL) {
  570. DbgOut("Error: Cannot resolve complex symbol.\n");
  571. Result = EINVAL;
  572. goto GetDataSymbolDataEnd;
  573. }
  574. Result = Symbols->Interface->ReadDataSymbol(Symbols,
  575. DataSymbol,
  576. DebasedPc,
  577. DataStream,
  578. DataStreamSize,
  579. Location,
  580. LocationSize);
  581. if (Result != 0) {
  582. if (Result != ENOENT) {
  583. DbgOut("Error: Cannot read local %s.\n", DataSymbol->Name);
  584. }
  585. goto GetDataSymbolDataEnd;
  586. }
  587. LocationSize = 0;
  588. break;
  589. default:
  590. DbgOut("Error: Unknown data symbol location %d.\n",
  591. DataSymbol->LocationType);
  592. Result = EINVAL;
  593. goto GetDataSymbolDataEnd;
  594. }
  595. if (LocationSize != 0) {
  596. *Location = '\0';
  597. }
  598. Result = 0;
  599. GetDataSymbolDataEnd:
  600. return Result;
  601. }
  602. INT
  603. DbgPrintDataSymbol (
  604. PDEBUGGER_CONTEXT Context,
  605. PDEBUG_SYMBOLS Symbols,
  606. PDATA_SYMBOL DataSymbol,
  607. ULONGLONG DebasedPc,
  608. ULONG SpaceLevel,
  609. ULONG RecursionDepth
  610. )
  611. /*++
  612. Routine Description:
  613. This routine prints the location and value of a data symbol.
  614. Arguments:
  615. Context - Supplies a pointer to the application context.
  616. Symbols - Supplies a pointer to the module symbols.
  617. DataSymbol - Supplies a pointer to the data symbol to print.
  618. DebasedPc - Supplies the program counter value, assuming the image were
  619. loaded at its preferred base address (that is, actual PC minus the
  620. loaded base difference of the module).
  621. SpaceLevel - Supplies the number of spaces to print after every newline.
  622. Used for nesting types.
  623. RecursionDepth - Supplies how many times this should recurse on structure
  624. members. If 0, only the name of the type is printed.
  625. Return Value:
  626. 0 on success.
  627. ENOENT if the data symbol is not currently active given the current state
  628. of the machine.
  629. Returns an error code on failure.
  630. --*/
  631. {
  632. PVOID DataStream;
  633. CHAR Location[64];
  634. INT Result;
  635. PTYPE_SYMBOL Type;
  636. ULONG TypeSize;
  637. DataStream = NULL;
  638. assert(Context->CurrentEvent.Type == DebuggerEventBreak);
  639. Result = DbgGetDataSymbolTypeInformation(DataSymbol, &Type, &TypeSize);
  640. if (Result == FALSE) {
  641. Result = 0;
  642. goto PrintDataSymbolEnd;
  643. }
  644. //
  645. // Allocate and get the data stream.
  646. //
  647. DataStream = malloc(TypeSize);
  648. if (DataStream == NULL) {
  649. Result = ENOMEM;
  650. goto PrintDataSymbolEnd;
  651. }
  652. Result = DbgGetDataSymbolData(Context,
  653. Symbols,
  654. DataSymbol,
  655. DebasedPc,
  656. DataStream,
  657. TypeSize,
  658. Location,
  659. sizeof(Location));
  660. if (Result != 0) {
  661. if (Result != ENOENT) {
  662. DbgOut("Error: unable to get data for data symbol %s\n",
  663. DataSymbol->Name);
  664. }
  665. goto PrintDataSymbolEnd;
  666. }
  667. Location[sizeof(Location) - 1] = '\0';
  668. DbgOut("%-12s %-20s: ", Location, DataSymbol->Name);
  669. //
  670. // Print the type contents.
  671. //
  672. Result = DbgPrintType(Context,
  673. Type,
  674. DataStream,
  675. TypeSize,
  676. SpaceLevel,
  677. RecursionDepth);
  678. Result = 0;
  679. PrintDataSymbolEnd:
  680. if (DataStream != NULL) {
  681. free(DataStream);
  682. }
  683. return Result;
  684. }
  685. INT
  686. DbgGetRegister (
  687. PDEBUGGER_CONTEXT Context,
  688. PREGISTERS_UNION Registers,
  689. ULONG RegisterNumber,
  690. PULONGLONG RegisterValue
  691. )
  692. /*++
  693. Routine Description:
  694. This routine returns the contents of a register given a debug symbol
  695. register index.
  696. Arguments:
  697. Context - Supplies a pointer to the application context.
  698. Registers - Supplies a pointer to the current machine context.
  699. RegisterNumber - Supplies the register index to get.
  700. RegisterValue - Supplies a pointer where the register value will be
  701. returned on success.
  702. Return Value:
  703. 0 on success.
  704. EINVAL if the register number is invalid.
  705. Other error codes on other failures.
  706. --*/
  707. {
  708. PULONG Registers32;
  709. INT Status;
  710. ULONGLONG Value;
  711. Status = 0;
  712. Value = -1ULL;
  713. switch (Context->MachineType) {
  714. case MACHINE_TYPE_X86:
  715. switch (RegisterNumber) {
  716. case X86RegisterEax:
  717. Value = Registers->X86.Eax;
  718. break;
  719. case X86RegisterEcx:
  720. Value = Registers->X86.Ecx;
  721. break;
  722. case X86RegisterEdx:
  723. Value = Registers->X86.Edx;
  724. break;
  725. case X86RegisterEbx:
  726. Value = Registers->X86.Ebx;
  727. break;
  728. case X86RegisterEsp:
  729. Value = Registers->X86.Esp;
  730. break;
  731. case X86RegisterEbp:
  732. Value = Registers->X86.Ebp;
  733. break;
  734. case X86RegisterEsi:
  735. Value = Registers->X86.Esi;
  736. break;
  737. case X86RegisterEdi:
  738. Value = Registers->X86.Edi;
  739. break;
  740. case X86RegisterEip:
  741. Value = Registers->X86.Eip;
  742. break;
  743. case X86RegisterEflags:
  744. Value = Registers->X86.Eflags;
  745. break;
  746. case X86RegisterCs:
  747. Value = Registers->X86.Cs;
  748. break;
  749. case X86RegisterSs:
  750. Value = Registers->X86.Ss;
  751. break;
  752. case X86RegisterDs:
  753. Value = Registers->X86.Ds;
  754. break;
  755. case X86RegisterEs:
  756. Value = Registers->X86.Es;
  757. break;
  758. case X86RegisterFs:
  759. Value = Registers->X86.Fs;
  760. break;
  761. case X86RegisterGs:
  762. Value = Registers->X86.Gs;
  763. break;
  764. default:
  765. //
  766. // TODO: Fetch the floating point registers if not yet grabbed.
  767. //
  768. if ((RegisterNumber >= X86RegisterSt0) &&
  769. (RegisterNumber <= X86RegisterFpDo)) {
  770. DbgOut("TODO: FPU Register %d.\n", RegisterNumber);
  771. Value = 0;
  772. break;
  773. }
  774. assert(FALSE);
  775. Status = EINVAL;
  776. break;
  777. }
  778. break;
  779. case MACHINE_TYPE_ARM:
  780. if ((RegisterNumber >= ArmRegisterR0) &&
  781. (RegisterNumber <= ArmRegisterR15)) {
  782. Registers32 = &(Registers->Arm.R0);
  783. Value = Registers32[RegisterNumber];
  784. } else if ((RegisterNumber >= ArmRegisterD0) &&
  785. (RegisterNumber <= ArmRegisterD31)) {
  786. //
  787. // TODO: Fetch the floating point registers if not yet grabbed.
  788. //
  789. DbgOut("TODO: FPU Register D%d\n", RegisterNumber - ArmRegisterD0);
  790. Value = 0;
  791. } else {
  792. assert(FALSE);
  793. Status = EINVAL;
  794. }
  795. break;
  796. default:
  797. assert(FALSE);
  798. Status = EINVAL;
  799. break;
  800. }
  801. *RegisterValue = Value;
  802. return Status;
  803. }
  804. INT
  805. DbgSetRegister (
  806. PDEBUGGER_CONTEXT Context,
  807. PREGISTERS_UNION Registers,
  808. ULONG RegisterNumber,
  809. ULONGLONG Value
  810. )
  811. /*++
  812. Routine Description:
  813. This routine sets the contents of a register given its register number.
  814. Arguments:
  815. Context - Supplies a pointer to the application context.
  816. Registers - Supplies a pointer to the current machine context. The register
  817. value will be set in this context.
  818. RegisterNumber - Supplies the register index to set.
  819. Value - Supplies the new value to set.
  820. Return Value:
  821. 0 on success.
  822. EINVAL if the register number is invalid.
  823. Other error codes on other failures.
  824. --*/
  825. {
  826. PULONG Registers32;
  827. INT Status;
  828. Status = 0;
  829. switch (Context->MachineType) {
  830. case MACHINE_TYPE_X86:
  831. switch (RegisterNumber) {
  832. case X86RegisterEax:
  833. Registers->X86.Eax = Value;
  834. break;
  835. case X86RegisterEcx:
  836. Registers->X86.Ecx = Value;
  837. break;
  838. case X86RegisterEdx:
  839. Registers->X86.Edx = Value;
  840. break;
  841. case X86RegisterEbx:
  842. Registers->X86.Ebx = Value;
  843. break;
  844. case X86RegisterEsp:
  845. Registers->X86.Esp = Value;
  846. break;
  847. case X86RegisterEbp:
  848. Registers->X86.Ebp = Value;
  849. break;
  850. case X86RegisterEsi:
  851. Registers->X86.Esi = Value;
  852. break;
  853. case X86RegisterEdi:
  854. Registers->X86.Edi = Value;
  855. break;
  856. case X86RegisterEip:
  857. Registers->X86.Eip = Value;
  858. break;
  859. case X86RegisterEflags:
  860. Registers->X86.Eflags = Value;
  861. break;
  862. case X86RegisterCs:
  863. Registers->X86.Cs = Value;
  864. break;
  865. case X86RegisterSs:
  866. Registers->X86.Ss = Value;
  867. break;
  868. case X86RegisterDs:
  869. Registers->X86.Ds = Value;
  870. break;
  871. case X86RegisterEs:
  872. Registers->X86.Es = Value;
  873. break;
  874. case X86RegisterFs:
  875. Registers->X86.Fs = Value;
  876. break;
  877. case X86RegisterGs:
  878. Registers->X86.Gs = Value;
  879. break;
  880. default:
  881. //
  882. // TODO: Fetch the floating point registers if not yet grabbed.
  883. //
  884. if ((RegisterNumber >= X86RegisterSt0) &&
  885. (RegisterNumber <= X86RegisterFpDo)) {
  886. DbgOut("TODO: FPU Register %d.\n", RegisterNumber);
  887. break;
  888. }
  889. assert(FALSE);
  890. Status = EINVAL;
  891. break;
  892. }
  893. break;
  894. case MACHINE_TYPE_ARM:
  895. if ((RegisterNumber >= ArmRegisterR0) &&
  896. (RegisterNumber <= ArmRegisterR15)) {
  897. Registers32 = &(Registers->Arm.R0);
  898. Registers32[RegisterNumber] = Value;
  899. } else if ((RegisterNumber >= ArmRegisterD0) &&
  900. (RegisterNumber <= ArmRegisterD31)) {
  901. //
  902. // TODO: Fetch the floating point registers if not yet grabbed.
  903. //
  904. DbgOut("TODO: FPU Register D%d\n", RegisterNumber - ArmRegisterD0);
  905. } else {
  906. assert(FALSE);
  907. Status = EINVAL;
  908. }
  909. break;
  910. default:
  911. assert(FALSE);
  912. Status = EINVAL;
  913. break;
  914. }
  915. return Status;
  916. }
  917. INT
  918. DbgGetTypeByName (
  919. PDEBUGGER_CONTEXT Context,
  920. PSTR TypeName,
  921. PTYPE_SYMBOL *Type
  922. )
  923. /*++
  924. Routine Description:
  925. This routine finds a type symbol object by its type name.
  926. Arguments:
  927. Context - Supplies a pointer to the application context.
  928. TypeName - Supplies a pointer to the string containing the name of the
  929. type to find. This can be prefixed with an module name if needed.
  930. Type - Supplies a pointer where a pointer to the type will be returned.
  931. Return Value:
  932. 0 on success.
  933. ENOENT if no type with the given name was found.
  934. Returns an error number on failure.
  935. --*/
  936. {
  937. PTYPE_SYMBOL FoundType;
  938. BOOL Result;
  939. SYMBOL_SEARCH_RESULT SearchResult;
  940. INT Status;
  941. FoundType = NULL;
  942. SearchResult.Variety = SymbolResultType;
  943. Result = DbgpFindSymbol(Context, TypeName, &SearchResult);
  944. if ((Result == FALSE) || (SearchResult.Variety != SymbolResultType)) {
  945. Status = ENOENT;
  946. goto GetTypeByNameEnd;
  947. }
  948. //
  949. // Read the base type.
  950. //
  951. FoundType = SearchResult.U.TypeResult;
  952. FoundType = DbgSkipTypedefs(FoundType);
  953. Status = 0;
  954. GetTypeByNameEnd:
  955. if (Status != 0) {
  956. FoundType = NULL;
  957. }
  958. *Type = FoundType;
  959. return Status;
  960. }
  961. INT
  962. DbgReadIntegerMember (
  963. PDEBUGGER_CONTEXT Context,
  964. PTYPE_SYMBOL Type,
  965. PSTR MemberName,
  966. ULONGLONG Address,
  967. PVOID Data,
  968. ULONG DataSize,
  969. PULONGLONG Value
  970. )
  971. /*++
  972. Routine Description:
  973. This routine reads an integer sized member out of an already read-in
  974. structure.
  975. Arguments:
  976. Context - Supplies a pointer to the application context.
  977. Type - Supplies a pointer to the type of the data.
  978. MemberName - Supplies a pointer to the member name.
  979. Address - Supplies the address where the data was obtained.
  980. Data - Supplies a pointer to the data contents.
  981. DataSize - Supplies the size of the data buffer in bytes.
  982. Value - Supplies a pointer where the value will be returned on success.
  983. Return Value:
  984. 0 on success.
  985. Returns an error number on failure.
  986. --*/
  987. {
  988. PVOID ShiftedData;
  989. UINTN ShiftedDataSize;
  990. INT Status;
  991. Status = DbgpGetStructureMember(Context,
  992. Type,
  993. MemberName,
  994. Address,
  995. Data,
  996. DataSize,
  997. &ShiftedData,
  998. &ShiftedDataSize,
  999. &Type);
  1000. if (Status != 0) {
  1001. return Status;
  1002. }
  1003. if (ShiftedDataSize > sizeof(ULONGLONG)) {
  1004. DbgOut("Error: Member %s.%s was larger than integer size.\n",
  1005. Type->Name,
  1006. MemberName);
  1007. free(ShiftedData);
  1008. return EINVAL;
  1009. }
  1010. *Value = 0;
  1011. memcpy(Value, ShiftedData, ShiftedDataSize);
  1012. return Status;
  1013. }
  1014. INT
  1015. DbgReadTypeByName (
  1016. PDEBUGGER_CONTEXT Context,
  1017. ULONGLONG Address,
  1018. PSTR TypeName,
  1019. PTYPE_SYMBOL *FinalType,
  1020. PVOID *Data,
  1021. PULONG DataSize
  1022. )
  1023. /*++
  1024. Routine Description:
  1025. This routine reads in data from the target for a specified type, which is
  1026. given as a string.
  1027. Arguments:
  1028. Context - Supplies a pointer to the application context.
  1029. Address - Supplies a target address pointer where the data resides.
  1030. TypeName - Supplies a pointer to a string containing the type name to get.
  1031. This should start with a type name, and can use dot '.' notation to
  1032. specify field members, and array[] notation to specify dereferences.
  1033. FinalType - Supplies a pointer where the final type symbol will be returned
  1034. on success.
  1035. Data - Supplies a pointer where the data will be returned on success. The
  1036. caller is responsible for freeing this data when finished.
  1037. DataSize - Supplies a pointer where the size of the data in bytes will be
  1038. returned.
  1039. Return Value:
  1040. 0 on success.
  1041. Returns an error number on failure.
  1042. --*/
  1043. {
  1044. PSTR Current;
  1045. PVOID CurrentData;
  1046. ULONG CurrentDataSize;
  1047. PSTR End;
  1048. PVOID NewData;
  1049. UINTN NewDataSize;
  1050. INT Status;
  1051. PTYPE_SYMBOL Type;
  1052. CurrentData = NULL;
  1053. CurrentDataSize = 0;
  1054. TypeName = strdup(TypeName);
  1055. if (TypeName == NULL) {
  1056. Status = ENOMEM;
  1057. goto ReadTypeByNameEnd;
  1058. }
  1059. End = TypeName + strlen(TypeName);
  1060. //
  1061. // Get the base type name.
  1062. //
  1063. Current = TypeName;
  1064. while ((*Current != '\0') && (*Current != '.') && (*Current != '[')) {
  1065. Current += 1;
  1066. }
  1067. *Current = '\0';
  1068. Current += 1;
  1069. Status = DbgGetTypeByName(Context, TypeName, &Type);
  1070. if (Status != 0) {
  1071. goto ReadTypeByNameEnd;
  1072. }
  1073. if (Type == NULL) {
  1074. DbgOut("Error: Cannot read void.\n");
  1075. Status = EINVAL;
  1076. goto ReadTypeByNameEnd;
  1077. }
  1078. //
  1079. // Read the base type.
  1080. //
  1081. Status = DbgReadType(Context,
  1082. Address,
  1083. Type,
  1084. &CurrentData,
  1085. &CurrentDataSize);
  1086. if (Status != 0) {
  1087. goto ReadTypeByNameEnd;
  1088. }
  1089. //
  1090. // Dereference through the structure members.
  1091. //
  1092. if (Current < End) {
  1093. Status = DbgpGetStructureMember(Context,
  1094. Type,
  1095. Current,
  1096. Address,
  1097. CurrentData,
  1098. CurrentDataSize,
  1099. &NewData,
  1100. &NewDataSize,
  1101. &Type);
  1102. if (Status != 0) {
  1103. goto ReadTypeByNameEnd;
  1104. }
  1105. free(CurrentData);
  1106. CurrentData = NewData;
  1107. CurrentDataSize = NewDataSize;
  1108. }
  1109. ReadTypeByNameEnd:
  1110. if (TypeName != NULL) {
  1111. free(TypeName);
  1112. }
  1113. if (Status != 0) {
  1114. if (CurrentData != NULL) {
  1115. free(CurrentData);
  1116. CurrentData = NULL;
  1117. }
  1118. CurrentDataSize = 0;
  1119. Type = NULL;
  1120. }
  1121. if (FinalType != NULL) {
  1122. *FinalType = Type;
  1123. }
  1124. *Data = CurrentData;
  1125. *DataSize = CurrentDataSize;
  1126. return Status;
  1127. }
  1128. INT
  1129. DbgReadType (
  1130. PDEBUGGER_CONTEXT Context,
  1131. ULONGLONG Address,
  1132. PTYPE_SYMBOL Type,
  1133. PVOID *Data,
  1134. PULONG DataSize
  1135. )
  1136. /*++
  1137. Routine Description:
  1138. This routine reads in data from the target for a specified type.
  1139. Arguments:
  1140. Context - Supplies a pointer to the application context.
  1141. Address - Supplies a target address pointer where the data resides.
  1142. Type - Supplies a pointer to the type symbol to get.
  1143. Data - Supplies a pointer where the data will be returned on success. The
  1144. caller is responsible for freeing this data when finished.
  1145. DataSize - Supplies a pointer where the size of the data in bytes will be
  1146. returned.
  1147. Return Value:
  1148. 0 on success.
  1149. Returns an error number on failure.
  1150. --*/
  1151. {
  1152. PVOID Buffer;
  1153. ULONG BytesRead;
  1154. ULONGLONG Size;
  1155. INT Status;
  1156. *Data = NULL;
  1157. *DataSize = 0;
  1158. Size = DbgGetTypeSize(Type, 0);
  1159. Buffer = malloc(Size);
  1160. if (Buffer == NULL) {
  1161. return ENOMEM;
  1162. }
  1163. memset(Buffer, 0, Size);
  1164. Status = DbgReadMemory(Context, TRUE, Address, Size, Buffer, &BytesRead);
  1165. if (Status != 0) {
  1166. free(Buffer);
  1167. return Status;
  1168. }
  1169. *Data = Buffer;
  1170. *DataSize = Size;
  1171. return 0;
  1172. }
  1173. INT
  1174. DbgPrintTypeByName (
  1175. PDEBUGGER_CONTEXT Context,
  1176. ULONGLONG Address,
  1177. PSTR TypeName,
  1178. ULONG SpaceLevel,
  1179. ULONG RecursionCount
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. This routine prints a structure or value at a specified address, whose type
  1184. is specified by a string.
  1185. Arguments:
  1186. Context - Supplies a pointer to the application context.
  1187. Address - Supplies a target address pointer where the data resides.
  1188. TypeName - Supplies a pointer to a string containing the type name to get.
  1189. This should start with a type name, and can use dot '.' notation to
  1190. specify field members, and array[] notation to specify dereferences.
  1191. SpaceLevel - Supplies the number of spaces worth of indentation to print
  1192. for subsequent lines.
  1193. RecursionCount - Supplies the number of substructures to recurse into.
  1194. Return Value:
  1195. 0 on success.
  1196. Returns an error number on failure.
  1197. --*/
  1198. {
  1199. PVOID Data;
  1200. UINTN DataSize;
  1201. INT Status;
  1202. PTYPE_SYMBOL Type;
  1203. Data = NULL;
  1204. Status = DbgReadTypeByName(Context,
  1205. Address,
  1206. TypeName,
  1207. &Type,
  1208. &Data,
  1209. &DataSize);
  1210. if (Status != 0) {
  1211. return Status;
  1212. }
  1213. Status = DbgPrintType(Context,
  1214. Type,
  1215. Data,
  1216. DataSize,
  1217. SpaceLevel,
  1218. RecursionCount);
  1219. free(Data);
  1220. return Status;
  1221. }
  1222. INT
  1223. DbgPrintTypeMember (
  1224. PDEBUGGER_CONTEXT Context,
  1225. ULONGLONG Address,
  1226. PVOID Data,
  1227. ULONG DataSize,
  1228. PTYPE_SYMBOL Type,
  1229. PSTR MemberName,
  1230. ULONG SpaceLevel,
  1231. ULONG RecursionCount
  1232. )
  1233. /*++
  1234. Routine Description:
  1235. This routine prints a member of a structure or union whose contents have
  1236. already been read in.
  1237. Arguments:
  1238. Context - Supplies a pointer to the application context.
  1239. Address - Supplies the address where this data came from.
  1240. Data - Supplies a pointer to the data contents.
  1241. DataSize - Supplies the size of the data contents buffer in bytes.
  1242. Type - Supplies a pointer to the structure type.
  1243. MemberName - Supplies the name of the member to print.
  1244. SpaceLevel - Supplies the number of spaces worth of indentation to print
  1245. for subsequent lines.
  1246. RecursionCount - Supplies the number of substructures to recurse into.
  1247. Return Value:
  1248. 0 on success.
  1249. Returns an error number on failure.
  1250. --*/
  1251. {
  1252. PVOID ShiftedData;
  1253. UINTN ShiftedDataSize;
  1254. INT Status;
  1255. Status = DbgpGetStructureMember(Context,
  1256. Type,
  1257. MemberName,
  1258. Address,
  1259. Data,
  1260. DataSize,
  1261. &ShiftedData,
  1262. &ShiftedDataSize,
  1263. &Type);
  1264. if (Status != 0) {
  1265. return Status;
  1266. }
  1267. Status = DbgPrintType(Context,
  1268. Type,
  1269. ShiftedData,
  1270. ShiftedDataSize,
  1271. SpaceLevel,
  1272. RecursionCount);
  1273. return Status;
  1274. }
  1275. INT
  1276. DbgPrintType (
  1277. PDEBUGGER_CONTEXT Context,
  1278. PTYPE_SYMBOL Type,
  1279. PVOID Data,
  1280. UINTN DataSize,
  1281. ULONG SpaceLevel,
  1282. ULONG RecursionCount
  1283. )
  1284. /*++
  1285. Routine Description:
  1286. This routine prints the given type to the debugger console.
  1287. Arguments:
  1288. Context - Supplies a pointer to the application context.
  1289. Type - Supplies a pointer to the data type to print.
  1290. Data - Supplies a pointer to the data contents.
  1291. DataSize - Supplies the size of the data buffer in bytes.
  1292. SpaceLevel - Supplies the number of spaces worth of indentation to print
  1293. for subsequent lines.
  1294. RecursionCount - Supplies the number of substructures to recurse into.
  1295. Return Value:
  1296. 0 on success.
  1297. Returns an error number on failure.
  1298. --*/
  1299. {
  1300. ULONGLONG ArrayIndex;
  1301. ULONG BitRemainder;
  1302. ULONG Bytes;
  1303. PDATA_TYPE_ENUMERATION Enumeration;
  1304. PENUMERATION_MEMBER EnumerationMember;
  1305. CHAR Field[256];
  1306. PVOID MemberData;
  1307. PSTR MemberName;
  1308. PTYPE_SYMBOL MemberType;
  1309. NUMERIC_UNION NumericValue;
  1310. PDATA_TYPE_RELATION Relation;
  1311. PTYPE_SYMBOL RelativeType;
  1312. PVOID ShiftedData;
  1313. INT Status;
  1314. PDATA_TYPE_STRUCTURE Structure;
  1315. PSTRUCTURE_MEMBER StructureMember;
  1316. UINTN TypeSize;
  1317. Status = 0;
  1318. switch (Type->Type) {
  1319. case DataTypeNumeric:
  1320. Status = DbgpPrintNumeric(Type, Data, DataSize);
  1321. break;
  1322. case DataTypeRelation:
  1323. Type = DbgSkipTypedefs(Type);
  1324. if (Type == NULL) {
  1325. DbgOut("void");
  1326. Status = 0;
  1327. break;
  1328. }
  1329. //
  1330. // If it just ended up being a typedef to something else, print that
  1331. // something else.
  1332. //
  1333. if (Type->Type != DataTypeRelation) {
  1334. Status = DbgPrintType(Context,
  1335. Type,
  1336. Data,
  1337. DataSize,
  1338. SpaceLevel,
  1339. RecursionCount);
  1340. return Status;
  1341. }
  1342. //
  1343. // This is either a pointer or an array.
  1344. //
  1345. Relation = &(Type->U.Relation);
  1346. RelativeType = DbgGetType(Relation->OwningFile, Relation->TypeNumber);
  1347. assert((Relation->Array.Minimum != Relation->Array.Maximum) ||
  1348. (Relation->Pointer != 0));
  1349. //
  1350. // If it's a pointer, then the type is just a pointer.
  1351. //
  1352. if (Relation->Pointer != 0) {
  1353. TypeSize = Relation->Pointer;
  1354. if (DataSize < TypeSize) {
  1355. return ERANGE;
  1356. }
  1357. NumericValue.Uint64 = 0;
  1358. memcpy(&NumericValue, Data, TypeSize);
  1359. DbgOut("0x%08I64x", NumericValue.Uint64);
  1360. break;
  1361. }
  1362. //
  1363. // This is an array.
  1364. //
  1365. TypeSize = 0;
  1366. DbgPrintTypeName(Type);
  1367. if (RecursionCount == 0) {
  1368. break;
  1369. }
  1370. SpaceLevel += 2;
  1371. TypeSize = DbgGetTypeSize(RelativeType, 0);
  1372. //
  1373. // If it's a a string, print it out as such.
  1374. //
  1375. if ((RelativeType->Type == DataTypeNumeric) &&
  1376. (RelativeType->U.Numeric.Signed != FALSE) &&
  1377. (RelativeType->U.Numeric.BitSize == BITS_PER_BYTE) &&
  1378. (RelativeType->U.Numeric.Float == FALSE)) {
  1379. TypeSize = Relation->Array.Maximum - Relation->Array.Minimum + 1;
  1380. if (DataSize < TypeSize) {
  1381. return ERANGE;
  1382. }
  1383. DbgPrintStringData(Data, TypeSize, SpaceLevel);
  1384. } else {
  1385. for (ArrayIndex = Relation->Array.Minimum;
  1386. ArrayIndex <= Relation->Array.Maximum;
  1387. ArrayIndex += 1) {
  1388. if (DataSize < TypeSize) {
  1389. Status = ERANGE;
  1390. break;
  1391. }
  1392. DbgOut("\n%*s", SpaceLevel, "");
  1393. DbgOut("[%I64d] --------------------------------------"
  1394. "-------", ArrayIndex);
  1395. DbgOut("\n%*s", SpaceLevel + 2, "");
  1396. Status = DbgPrintType(Context,
  1397. RelativeType,
  1398. Data,
  1399. DataSize,
  1400. SpaceLevel + 2,
  1401. RecursionCount - 1);
  1402. if (Status != 0) {
  1403. break;
  1404. }
  1405. Data += TypeSize;
  1406. DataSize -= TypeSize;
  1407. }
  1408. }
  1409. SpaceLevel -= 2;
  1410. break;
  1411. case DataTypeEnumeration:
  1412. Enumeration = &(Type->U.Enumeration);
  1413. TypeSize = Enumeration->SizeInBytes;
  1414. if (TypeSize > sizeof(NumericValue)) {
  1415. TypeSize = sizeof(NumericValue);
  1416. }
  1417. NumericValue.Uint64 = 0;
  1418. memcpy(&NumericValue, Data, TypeSize);
  1419. switch (TypeSize) {
  1420. case 1:
  1421. NumericValue.Int64 = NumericValue.Int8;
  1422. break;
  1423. case 2:
  1424. NumericValue.Int64 = NumericValue.Int16;
  1425. break;
  1426. case 4:
  1427. NumericValue.Int64 = NumericValue.Int32;
  1428. break;
  1429. case 8:
  1430. break;
  1431. default:
  1432. assert(FALSE);
  1433. return EINVAL;
  1434. }
  1435. DbgOut("%I64d", NumericValue.Int64);
  1436. EnumerationMember = Enumeration->FirstMember;
  1437. while (EnumerationMember != NULL) {
  1438. if (EnumerationMember->Value == NumericValue.Int64) {
  1439. DbgOut(" %s", EnumerationMember->Name);
  1440. break;
  1441. }
  1442. EnumerationMember = EnumerationMember->NextMember;
  1443. }
  1444. break;
  1445. case DataTypeStructure:
  1446. Structure = &(Type->U.Structure);
  1447. TypeSize = Structure->SizeInBytes;
  1448. if (DataSize < TypeSize) {
  1449. return ERANGE;
  1450. }
  1451. //
  1452. // If the recursion depth is zero, don't print this structure contents
  1453. // out, only print the name.
  1454. //
  1455. DbgPrintTypeName(Type);
  1456. if (RecursionCount == 0) {
  1457. break;
  1458. }
  1459. SpaceLevel += 2;
  1460. StructureMember = Structure->FirstMember;
  1461. while (StructureMember != NULL) {
  1462. Bytes = StructureMember->BitOffset / BITS_PER_BYTE;
  1463. if (Bytes >= DataSize) {
  1464. return ERANGE;
  1465. }
  1466. BitRemainder = StructureMember->BitOffset % BITS_PER_BYTE;
  1467. MemberData = Data + Bytes;
  1468. DbgOut("\n%*s", SpaceLevel, "");
  1469. snprintf(Field, sizeof(Field), "+0x%x", Bytes);
  1470. DbgOut("%-6s ", Field);
  1471. ShiftedData = NULL;
  1472. MemberName = StructureMember->Name;
  1473. if (MemberName == NULL) {
  1474. MemberName = "";
  1475. }
  1476. if (BitRemainder != 0) {
  1477. snprintf(Field,
  1478. sizeof(Field),
  1479. "%s:%d",
  1480. MemberName,
  1481. BitRemainder);
  1482. } else {
  1483. snprintf(Field, sizeof(Field), "%s", MemberName);
  1484. }
  1485. Field[sizeof(Field) - 1] = '\0';
  1486. DbgOut("%-17s : ", Field);
  1487. //
  1488. // Manipulate the data for the structure member if it's got a
  1489. // bitwise offset or size.
  1490. //
  1491. if ((BitRemainder != 0) || (StructureMember->BitSize != 0)) {
  1492. ShiftedData = DbgpShiftBufferRight(MemberData,
  1493. DataSize - Bytes,
  1494. BitRemainder,
  1495. StructureMember->BitSize);
  1496. if (ShiftedData == NULL) {
  1497. return ENOMEM;
  1498. }
  1499. MemberData = ShiftedData;
  1500. }
  1501. MemberType = DbgGetType(StructureMember->TypeFile,
  1502. StructureMember->TypeNumber);
  1503. if (MemberType == NULL) {
  1504. DbgOut("DANGLING REFERENCE %s, %d\n",
  1505. StructureMember->TypeFile->SourceFile,
  1506. StructureMember->TypeNumber);
  1507. assert(MemberType != NULL);
  1508. } else {
  1509. Status = DbgPrintType(Context,
  1510. MemberType,
  1511. MemberData,
  1512. DataSize - Bytes,
  1513. SpaceLevel,
  1514. RecursionCount - 1);
  1515. if (Status != 0) {
  1516. break;
  1517. }
  1518. }
  1519. if (ShiftedData != NULL) {
  1520. free(ShiftedData);
  1521. ShiftedData = NULL;
  1522. }
  1523. StructureMember = StructureMember->NextMember;
  1524. }
  1525. SpaceLevel -= 2;
  1526. break;
  1527. case DataTypeFunctionPointer:
  1528. TypeSize = Type->U.FunctionPointer.SizeInBytes;
  1529. if (TypeSize > sizeof(NumericValue)) {
  1530. TypeSize = sizeof(NumericValue);
  1531. }
  1532. NumericValue.Uint64 = 0;
  1533. memcpy(&NumericValue, Data, TypeSize);
  1534. DbgOut("(*0x%08I64x)()", NumericValue.Uint64);
  1535. break;
  1536. default:
  1537. assert(FALSE);
  1538. break;
  1539. }
  1540. return Status;
  1541. }
  1542. VOID
  1543. DbgPrintStringData (
  1544. PSTR String,
  1545. UINTN Size,
  1546. ULONG SpaceDepth
  1547. )
  1548. /*++
  1549. Routine Description:
  1550. This routine prints string data to the debugger console.
  1551. Arguments:
  1552. String - Supplies a pointer to the string data.
  1553. Size - Supplies the number of bytes to print out.
  1554. SpaceDepth - Supplies the indentation to use when breaking up a string into
  1555. multiple lines.
  1556. Return Value:
  1557. None.
  1558. --*/
  1559. {
  1560. UCHAR Character;
  1561. ULONG Column;
  1562. Column = SpaceDepth;
  1563. DbgOut("\"");
  1564. Column += 1;
  1565. while (Size != 0) {
  1566. Character = *String;
  1567. if ((Character >= ' ') && (Character < 0x80)) {
  1568. DbgOut("%c", Character);
  1569. Column += 1;
  1570. } else if (Character == '\0') {
  1571. DbgOut("\\0");
  1572. Column += 2;
  1573. } else if (Character == '\r') {
  1574. DbgOut("\\r");
  1575. Column += 2;
  1576. } else if (Character == '\n') {
  1577. DbgOut("\\n");
  1578. Column += 2;
  1579. } else if (Character == '\f') {
  1580. DbgOut("\\f");
  1581. Column += 2;
  1582. } else if (Character == '\v') {
  1583. DbgOut("\\v");
  1584. Column += 2;
  1585. } else if (Character == '\t') {
  1586. DbgOut("\\t");
  1587. Column += 2;
  1588. } else if (Character == '\a') {
  1589. DbgOut("\\a");
  1590. Column += 2;
  1591. } else if (Character == '\b') {
  1592. DbgOut("\\b");
  1593. Column += 2;
  1594. } else {
  1595. DbgOut("\\x%02x", Character);
  1596. Column += 4;
  1597. }
  1598. String += 1;
  1599. Size -= 1;
  1600. if (Column >= 80) {
  1601. Column = SpaceDepth;
  1602. DbgOut("\n%*s", SpaceDepth, "");
  1603. }
  1604. }
  1605. DbgOut("\"");
  1606. return;
  1607. }
  1608. PDEBUGGER_MODULE
  1609. DbgpFindModuleFromAddress (
  1610. PDEBUGGER_CONTEXT Context,
  1611. ULONGLONG Address,
  1612. PULONGLONG DebasedAddress
  1613. )
  1614. /*++
  1615. Routine Description:
  1616. This routine attempts to locate a loaded module that corresponds to a
  1617. virtual address in the target.
  1618. Arguments:
  1619. Context - Supplies a pointer to the application context.
  1620. Address - Supplies an address somewhere in one of the loaded modules.
  1621. DebasedAddress - Supplies an optional pointer where the address minus the
  1622. loaded base difference from where the module would have preferred to
  1623. have been loaded will be returned. This will be the address from the
  1624. symbols' perspective.
  1625. Return Value:
  1626. Returns a pointer to the module that the address is contained in, or NULL if
  1627. one cannot be found.
  1628. --*/
  1629. {
  1630. PDEBUGGER_MODULE CurrentModule;
  1631. PLIST_ENTRY CurrentModuleEntry;
  1632. PDEBUGGER_MODULE FoundModule;
  1633. FoundModule = NULL;
  1634. CurrentModuleEntry = Context->ModuleList.ModulesHead.Next;
  1635. while (CurrentModuleEntry != &(Context->ModuleList.ModulesHead)) {
  1636. CurrentModule = LIST_VALUE(CurrentModuleEntry,
  1637. DEBUGGER_MODULE,
  1638. ListEntry);
  1639. CurrentModuleEntry = CurrentModuleEntry->Next;
  1640. if (!IS_MODULE_IN_CURRENT_PROCESS(Context, CurrentModule)) {
  1641. continue;
  1642. }
  1643. if ((Address >= CurrentModule->LowestAddress) &&
  1644. (Address < CurrentModule->LowestAddress + CurrentModule->Size)) {
  1645. FoundModule = CurrentModule;
  1646. break;
  1647. }
  1648. }
  1649. if ((FoundModule != NULL) && (DebasedAddress != NULL)) {
  1650. *DebasedAddress = Address - FoundModule->BaseDifference;
  1651. }
  1652. return FoundModule;
  1653. }
  1654. PDEBUGGER_MODULE
  1655. DbgpGetModule (
  1656. PDEBUGGER_CONTEXT Context,
  1657. PSTR ModuleName,
  1658. ULONG MaxLength
  1659. )
  1660. /*++
  1661. Routine Description:
  1662. This routine gets a module given the module name.
  1663. Arguments:
  1664. Context - Supplies a pointer to the application context.
  1665. ModuleName - Supplies a null terminated string specifying the module name.
  1666. MaxLength - Supplies the maximum length of the module name.
  1667. Return Value:
  1668. Returns a pointer to the module, or NULL if one could not be found.
  1669. --*/
  1670. {
  1671. PDEBUGGER_MODULE CurrentModule;
  1672. PLIST_ENTRY CurrentModuleEntry;
  1673. CurrentModuleEntry = Context->ModuleList.ModulesHead.Next;
  1674. while (CurrentModuleEntry != &(Context->ModuleList.ModulesHead)) {
  1675. CurrentModule = LIST_VALUE(CurrentModuleEntry,
  1676. DEBUGGER_MODULE,
  1677. ListEntry);
  1678. CurrentModuleEntry = CurrentModuleEntry->Next;
  1679. if (!IS_MODULE_IN_CURRENT_PROCESS(Context, CurrentModule)) {
  1680. continue;
  1681. }
  1682. if (strncasecmp(ModuleName, CurrentModule->ModuleName, MaxLength) ==
  1683. 0) {
  1684. return CurrentModule;
  1685. }
  1686. }
  1687. return NULL;
  1688. }
  1689. ULONGLONG
  1690. DbgpGetFunctionStartAddress (
  1691. PDEBUGGER_CONTEXT Context,
  1692. ULONGLONG Address
  1693. )
  1694. /*++
  1695. Routine Description:
  1696. This routine looks up the address for the beginning of the function given
  1697. an address somewhere in the function.
  1698. Arguments:
  1699. Context - Supplies a pointer to the application context.
  1700. Address - Supplies a virtual address somewhere inside the function.
  1701. Return Value:
  1702. Returns the address of the first instruction of the current function, or 0
  1703. if the funtion could not be found.
  1704. --*/
  1705. {
  1706. ULONGLONG DebasedAddress;
  1707. ULONGLONG FunctionStart;
  1708. PDEBUGGER_MODULE Module;
  1709. PSYMBOL_SEARCH_RESULT ResultValid;
  1710. SYMBOL_SEARCH_RESULT SearchResult;
  1711. FunctionStart = 0;
  1712. //
  1713. // Attempt to get the module this address is in. If one cannot be found,
  1714. // then there is no useful information to print, so exit.
  1715. //
  1716. Module = DbgpFindModuleFromAddress(Context, Address, &DebasedAddress);
  1717. if (Module == NULL) {
  1718. goto GetFunctionStartAddressEnd;
  1719. }
  1720. //
  1721. // Attempt to find the current function symbol in the module.
  1722. //
  1723. SearchResult.Variety = SymbolResultInvalid;
  1724. ResultValid = NULL;
  1725. if (Module->Symbols != NULL) {
  1726. ResultValid = DbgLookupSymbol(Module->Symbols,
  1727. DebasedAddress,
  1728. &SearchResult);
  1729. }
  1730. if ((ResultValid != NULL) &&
  1731. (SearchResult.Variety == SymbolResultFunction)) {
  1732. FunctionStart = SearchResult.U.FunctionResult->StartAddress +
  1733. Module->BaseDifference;
  1734. }
  1735. GetFunctionStartAddressEnd:
  1736. return FunctionStart;
  1737. }
  1738. BOOL
  1739. DbgpFindSymbol (
  1740. PDEBUGGER_CONTEXT Context,
  1741. PSTR SearchString,
  1742. PSYMBOL_SEARCH_RESULT SearchResult
  1743. )
  1744. /*++
  1745. Routine Description:
  1746. This routine searches for symbols. Wildcards are accepted. If the search
  1747. string is preceded by "modulename!" then only that module will be searched.
  1748. Arguments:
  1749. Context - Supplies a pointer to the application context.
  1750. SearchString - Supplies the string to search for.
  1751. SearchResult - Supplies a pointer that receives symbol search result data.
  1752. Return Value:
  1753. Returns TRUE on success, or FALSE on failure.
  1754. --*/
  1755. {
  1756. PDEBUGGER_MODULE CurrentModule;
  1757. PLIST_ENTRY CurrentModuleEntry;
  1758. BOOL HaveSilverMedalResult;
  1759. PSTR ModuleEnd;
  1760. ULONG ModuleLength;
  1761. PTYPE_SYMBOL ResolvedType;
  1762. BOOL Result;
  1763. PSYMBOL_SEARCH_RESULT ResultValid;
  1764. SYMBOL_SEARCH_RESULT SilverMedalResult;
  1765. PDATA_TYPE_STRUCTURE Structure;
  1766. PDEBUGGER_MODULE UserModule;
  1767. Result = FALSE;
  1768. ResultValid = NULL;
  1769. HaveSilverMedalResult = FALSE;
  1770. UserModule = NULL;
  1771. //
  1772. // Parameter checking.
  1773. //
  1774. if (SearchResult == NULL) {
  1775. goto FindSymbolEnd;
  1776. }
  1777. //
  1778. // If an exclamation point exists, then the module was specified. Find that
  1779. // module.
  1780. //
  1781. ModuleEnd = strchr(SearchString, '!');
  1782. if (ModuleEnd != NULL) {
  1783. ModuleLength = (UINTN)ModuleEnd - (UINTN)SearchString;
  1784. UserModule = DbgpGetModule(Context, SearchString, ModuleLength);
  1785. if (UserModule == NULL) {
  1786. DbgOut("Module %s not found.\n", SearchString);
  1787. goto FindSymbolEnd;
  1788. }
  1789. //
  1790. // Move the search string and initialize the list entry.
  1791. //
  1792. SearchString = ModuleEnd + 1;
  1793. CurrentModuleEntry = &(UserModule->ListEntry);
  1794. //
  1795. // If a module was not specified, simply start with the first one.
  1796. //
  1797. } else {
  1798. CurrentModuleEntry = Context->ModuleList.ModulesHead.Next;
  1799. }
  1800. //
  1801. // Loop over all modules.
  1802. //
  1803. while (CurrentModuleEntry != &(Context->ModuleList.ModulesHead)) {
  1804. CurrentModule = LIST_VALUE(CurrentModuleEntry,
  1805. DEBUGGER_MODULE,
  1806. ListEntry);
  1807. CurrentModuleEntry = CurrentModuleEntry->Next;
  1808. if (!IS_MODULE_IN_CURRENT_PROCESS(Context, CurrentModule)) {
  1809. if (UserModule != NULL) {
  1810. break;
  1811. }
  1812. continue;
  1813. }
  1814. //
  1815. // Search for the symbol in the current module. Exit if it is found.
  1816. //
  1817. SearchResult->U.TypeResult = NULL;
  1818. while (TRUE) {
  1819. ResultValid = DbgpFindSymbolInModule(CurrentModule->Symbols,
  1820. SearchString,
  1821. SearchResult);
  1822. //
  1823. // If not found, stop looking in this module, and go to the next
  1824. // module.
  1825. //
  1826. if (ResultValid == NULL) {
  1827. break;
  1828. }
  1829. Result = TRUE;
  1830. //
  1831. // If it's a structure with a zero size, keep looking to see if
  1832. // another there is a different definition with a non-zero size.
  1833. //
  1834. if (SearchResult->Variety == SymbolResultType) {
  1835. ResolvedType = DbgSkipTypedefs(SearchResult->U.TypeResult);
  1836. if ((ResolvedType != NULL) &&
  1837. (ResolvedType->Type == DataTypeStructure)) {
  1838. Structure = &(ResolvedType->U.Structure);
  1839. //
  1840. // If it's got a body, return it.
  1841. //
  1842. if (Structure->SizeInBytes != 0) {
  1843. goto FindSymbolEnd;
  1844. }
  1845. RtlCopyMemory(&SilverMedalResult,
  1846. SearchResult,
  1847. sizeof(SYMBOL_SEARCH_RESULT));
  1848. //
  1849. // Remember that there is this search result with a zero
  1850. // size in case that's all there is, but keep looking for
  1851. // something better.
  1852. //
  1853. HaveSilverMedalResult = TRUE;
  1854. //
  1855. // It doesn't resolve or it's not a structure, so return it.
  1856. //
  1857. } else {
  1858. goto FindSymbolEnd;
  1859. }
  1860. //
  1861. // It's not a type result, so return it.
  1862. //
  1863. } else {
  1864. goto FindSymbolEnd;
  1865. }
  1866. }
  1867. //
  1868. // If a specific user module was specified, do not loop over more
  1869. // modules.
  1870. //
  1871. if (UserModule != NULL) {
  1872. break;
  1873. }
  1874. }
  1875. //
  1876. // If there's not a valid result but there's a valid "second best"
  1877. // result, then use that and declare success.
  1878. //
  1879. if (HaveSilverMedalResult != FALSE) {
  1880. Result = TRUE;
  1881. RtlCopyMemory(SearchResult,
  1882. &SilverMedalResult,
  1883. sizeof(SYMBOL_SEARCH_RESULT));
  1884. }
  1885. FindSymbolEnd:
  1886. return Result;
  1887. }
  1888. PDEBUGGER_MODULE
  1889. DbgpFindModuleFromEntry (
  1890. PDEBUGGER_CONTEXT Context,
  1891. PLOADED_MODULE_ENTRY TargetEntry
  1892. )
  1893. /*++
  1894. Routine Description:
  1895. This routine attempts to locate a loaded module that corresponds to the
  1896. target's description of a loaded module.
  1897. Arguments:
  1898. Context - Supplies a pointer to the application context.
  1899. TargetEntry - Supplies the target's module description.
  1900. Return Value:
  1901. Returns a pointer to the existing loaded module if one exists, or NULL if
  1902. one cannot be found.
  1903. --*/
  1904. {
  1905. PDEBUGGER_MODULE Backup;
  1906. ULONG BinaryNameLength;
  1907. ULONG CharacterIndex;
  1908. PLIST_ENTRY CurrentListEntry;
  1909. PDEBUGGER_MODULE CurrentModule;
  1910. PSTR FriendlyName;
  1911. ULONG FriendlyNameLength;
  1912. Backup = NULL;
  1913. if (TargetEntry == NULL) {
  1914. return NULL;
  1915. }
  1916. CurrentListEntry = Context->ModuleList.ModulesHead.Next;
  1917. while (CurrentListEntry != &(Context->ModuleList.ModulesHead)) {
  1918. CurrentModule = LIST_VALUE(CurrentListEntry,
  1919. DEBUGGER_MODULE,
  1920. ListEntry);
  1921. //
  1922. // Set up now for the next entry so that conditions can fail and use
  1923. // continue.
  1924. //
  1925. CurrentListEntry = CurrentListEntry->Next;
  1926. if (CurrentModule->Process != TargetEntry->Process) {
  1927. continue;
  1928. }
  1929. if (CurrentModule->LowestAddress != TargetEntry->LowestAddress) {
  1930. continue;
  1931. }
  1932. BinaryNameLength = TargetEntry->StructureSize -
  1933. sizeof(LOADED_MODULE_ENTRY) +
  1934. (ANYSIZE_ARRAY * sizeof(CHAR));
  1935. DbgpGetFriendlyName(TargetEntry->BinaryName,
  1936. BinaryNameLength,
  1937. &FriendlyName,
  1938. &FriendlyNameLength);
  1939. CharacterIndex = 0;
  1940. while (CharacterIndex < FriendlyNameLength) {
  1941. if (CurrentModule->ModuleName[CharacterIndex] !=
  1942. FriendlyName[CharacterIndex]) {
  1943. break;
  1944. }
  1945. CharacterIndex += 1;
  1946. }
  1947. if (CharacterIndex < FriendlyNameLength) {
  1948. continue;
  1949. }
  1950. if (CurrentModule->ModuleName[CharacterIndex] != '\0') {
  1951. continue;
  1952. }
  1953. //
  1954. // If the timestamps don't match, save this as a backup but look for
  1955. // something even better.
  1956. //
  1957. if ((TargetEntry->Timestamp != 0) &&
  1958. (TargetEntry->Timestamp != CurrentModule->Timestamp)) {
  1959. if (Backup == NULL) {
  1960. Backup = CurrentModule;
  1961. }
  1962. continue;
  1963. }
  1964. //
  1965. // All conditions were met, so this must be a match.
  1966. //
  1967. return CurrentModule;
  1968. }
  1969. return Backup;
  1970. }
  1971. INT
  1972. DbgpFindLocal (
  1973. PDEBUGGER_CONTEXT Context,
  1974. PREGISTERS_UNION Registers,
  1975. PSTR LocalName,
  1976. PDEBUG_SYMBOLS *ModuleSymbols,
  1977. PDATA_SYMBOL *Local,
  1978. PULONGLONG DebasedPc
  1979. )
  1980. /*++
  1981. Routine Description:
  1982. This routine searches the local variables and parameters in the function
  1983. containing the given address for a variable matching the given name.
  1984. Arguments:
  1985. Context - Supplies a pointer to the application context.
  1986. Registers - Supplies a pointer to the registers to use for the search.
  1987. LocalName - Supplies a case insensitive string of the local name.
  1988. ModuleSymbols - Supplies a pointer where the symbols for the module will be
  1989. returned on success.
  1990. Local - Supplies a pointer where the local symbol will be returned on
  1991. success.
  1992. DebasedPc - Supplies a pointer where the PC will be returned, adjusted by
  1993. the amount the image load was adjusted by.
  1994. Return Value:
  1995. 0 on success.
  1996. ENOENT if no local by that name could be found.
  1997. Returns an error number on other failures.
  1998. --*/
  1999. {
  2000. PLIST_ENTRY CurrentEntry;
  2001. PFUNCTION_SYMBOL Function;
  2002. PDATA_SYMBOL LocalSymbol;
  2003. PDEBUGGER_MODULE Module;
  2004. PDATA_SYMBOL Parameter;
  2005. ULONGLONG Pc;
  2006. PSYMBOL_SEARCH_RESULT ResultValid;
  2007. SYMBOL_SEARCH_RESULT SearchResult;
  2008. //
  2009. // Attempt to get the module this address is in. If one cannot be found,
  2010. // then there is no useful information to print, so exit.
  2011. //
  2012. Pc = DbgGetPc(Context, Registers);
  2013. Module = DbgpFindModuleFromAddress(Context, Pc, &Pc);
  2014. if (Module == NULL) {
  2015. return ENOENT;
  2016. }
  2017. //
  2018. // Attempt to find the current function symbol in the module.
  2019. //
  2020. SearchResult.Variety = SymbolResultInvalid;
  2021. ResultValid = NULL;
  2022. if (Module->Symbols != NULL) {
  2023. ResultValid = DbgFindFunctionSymbol(Module->Symbols,
  2024. NULL,
  2025. Pc,
  2026. &SearchResult);
  2027. } else {
  2028. return ENOENT;
  2029. }
  2030. //
  2031. // If a function could not be found, bail.
  2032. //
  2033. if ((ResultValid == NULL) ||
  2034. (SearchResult.Variety != SymbolResultFunction)) {
  2035. return ENOENT;
  2036. }
  2037. Function = SearchResult.U.FunctionResult;
  2038. //
  2039. // First check the locals.
  2040. //
  2041. LocalSymbol = DbgpGetLocal(Function, LocalName, Pc);
  2042. if (LocalSymbol == NULL) {
  2043. //
  2044. // Check any function parameters.
  2045. //
  2046. CurrentEntry = Function->ParametersHead.Next;
  2047. while (CurrentEntry != &(Function->ParametersHead)) {
  2048. Parameter = LIST_VALUE(CurrentEntry, DATA_SYMBOL, ListEntry);
  2049. CurrentEntry = CurrentEntry->Next;
  2050. if (strcasecmp(LocalName, Parameter->Name) == 0) {
  2051. LocalSymbol = Parameter;
  2052. break;
  2053. }
  2054. }
  2055. }
  2056. if (LocalSymbol != NULL) {
  2057. if (ModuleSymbols != NULL) {
  2058. *ModuleSymbols = Module->Symbols;
  2059. }
  2060. if (Local != NULL) {
  2061. *Local = LocalSymbol;
  2062. }
  2063. if (DebasedPc != NULL) {
  2064. *DebasedPc = Pc;
  2065. }
  2066. return 0;
  2067. }
  2068. return ENOENT;
  2069. }
  2070. PDATA_SYMBOL
  2071. DbgpGetLocal (
  2072. PFUNCTION_SYMBOL Function,
  2073. PSTR LocalName,
  2074. ULONGLONG ExecutionAddress
  2075. )
  2076. /*++
  2077. Routine Description:
  2078. This routine gets the most up to date version of a local variable symbol.
  2079. Arguments:
  2080. Function - Supplies a pointer to the function with the desired local
  2081. variables.
  2082. LocalName - Supplies a case sensitive string of the local name.
  2083. ExecutionAddress - Supplies the current execution address. This function
  2084. will attempt to find the local variable matching the LocalName whose
  2085. minimum execution address is as close to ExecutionAddress as possible.
  2086. It is assumed that this address has already been de-based (the current
  2087. base address has been subtracted from it).
  2088. Return Value:
  2089. Returns a pointer to the local variable symbol, or NULL if one could not
  2090. be found.
  2091. --*/
  2092. {
  2093. PDATA_SYMBOL CurrentLocal;
  2094. PLIST_ENTRY CurrentLocalEntry;
  2095. PDATA_SYMBOL Winner;
  2096. Winner = NULL;
  2097. CurrentLocalEntry = Function->LocalsHead.Next;
  2098. while (CurrentLocalEntry != &(Function->LocalsHead)) {
  2099. CurrentLocal = LIST_VALUE(CurrentLocalEntry,
  2100. DATA_SYMBOL,
  2101. ListEntry);
  2102. CurrentLocalEntry = CurrentLocalEntry->Next;
  2103. //
  2104. // Skip this symbol if the minimum execution address is not even valid.
  2105. // This is done first because it is a cheaper test than string compare.
  2106. //
  2107. if (ExecutionAddress < CurrentLocal->MinimumValidExecutionAddress) {
  2108. continue;
  2109. }
  2110. //
  2111. // Check if the name matches.
  2112. //
  2113. if (strcasecmp(LocalName, CurrentLocal->Name) != 0) {
  2114. continue;
  2115. }
  2116. //
  2117. // If no winner has been found yet, this one becomes the current winner
  2118. // by default.
  2119. //
  2120. if (Winner == NULL) {
  2121. Winner = CurrentLocal;
  2122. //
  2123. // There is already a current winner, see if this one has a lower
  2124. // minimum execution address (closer to the current one, but still
  2125. // greater).
  2126. //
  2127. } else {
  2128. if (CurrentLocal->MinimumValidExecutionAddress <
  2129. Winner->MinimumValidExecutionAddress) {
  2130. Winner = CurrentLocal;
  2131. }
  2132. }
  2133. }
  2134. return Winner;
  2135. }
  2136. VOID
  2137. DbgpGetFriendlyName (
  2138. PSTR FullName,
  2139. ULONG FullNameLength,
  2140. PSTR *NameBegin,
  2141. PULONG NameLength
  2142. )
  2143. /*++
  2144. Routine Description:
  2145. This routine determines the portion of the given binary name to use as the
  2146. friendly name.
  2147. Arguments:
  2148. FullName - Supplies a pointer to the full path of the binary, null
  2149. terminated.
  2150. FullNameLength - Supplies the length of the full name buffer in bytes
  2151. including the null terminator.
  2152. NameBegin - Supplies a pointer where the beginning of the friendly name
  2153. will be returned. This will point inside the full name.
  2154. NameLength - Supplies a pointer where the number of characters in the
  2155. friendly name will be returned, not including the null terminator.
  2156. Return Value:
  2157. Returns TRUE on success, or FALSE on failure.
  2158. --*/
  2159. {
  2160. ULONG FriendlyNameLength;
  2161. PSTR LastSeparator;
  2162. PSTR LastSlash;
  2163. PSTR Period;
  2164. LastSeparator = RtlStringFindCharacterRight(FullName, '\\', FullNameLength);
  2165. if (LastSeparator != NULL) {
  2166. LastSeparator += 1;
  2167. }
  2168. LastSlash = RtlStringFindCharacterRight(FullName, '/', FullNameLength);
  2169. if (LastSlash != NULL) {
  2170. LastSlash += 1;
  2171. }
  2172. if ((LastSeparator == NULL) ||
  2173. ((LastSlash != NULL) && (LastSlash > LastSeparator))) {
  2174. LastSeparator = LastSlash;
  2175. }
  2176. if (LastSeparator == NULL) {
  2177. LastSeparator = FullName;
  2178. }
  2179. FullNameLength -= (UINTN)LastSeparator - (UINTN)FullName;
  2180. Period = RtlStringFindCharacterRight(LastSeparator, '.', FullNameLength);
  2181. if (Period == NULL) {
  2182. FriendlyNameLength = FullNameLength;
  2183. } else {
  2184. FriendlyNameLength = (UINTN)Period - (UINTN)LastSeparator;
  2185. if (FriendlyNameLength == 0) {
  2186. assert(FullNameLength > 1);
  2187. FriendlyNameLength = FullNameLength - 1;
  2188. LastSeparator += 1;
  2189. }
  2190. }
  2191. assert(FriendlyNameLength != 0);
  2192. *NameBegin = LastSeparator;
  2193. *NameLength = FriendlyNameLength;
  2194. return;
  2195. }
  2196. INT
  2197. DbgpPrintNumeric (
  2198. PTYPE_SYMBOL Type,
  2199. PVOID Data,
  2200. UINTN DataSize
  2201. )
  2202. /*++
  2203. Routine Description:
  2204. This routine prints a numeric type's contents.
  2205. Arguments:
  2206. Type - Supplies a pointer to the type symbol to print.
  2207. Data - Supplies a pointer to the data contents.
  2208. DataSize - Supplies the size of the data in bytes.
  2209. Return Value:
  2210. 0 on success.
  2211. ENOBUFS if the provided buffer is not large enough to accomodate the given
  2212. type.
  2213. --*/
  2214. {
  2215. ULONG BitSize;
  2216. PDATA_TYPE_NUMERIC Numeric;
  2217. NUMERIC_UNION NumericValue;
  2218. UINTN TypeSize;
  2219. assert(Type->Type == DataTypeNumeric);
  2220. Numeric = &(Type->U.Numeric);
  2221. BitSize = Numeric->BitSize;
  2222. TypeSize = ALIGN_RANGE_UP(BitSize, BITS_PER_BYTE) / BITS_PER_BYTE;
  2223. if (DataSize < TypeSize) {
  2224. return ERANGE;
  2225. }
  2226. NumericValue.Uint64 = 0;
  2227. memcpy(&NumericValue, Data, TypeSize);
  2228. if ((BitSize & (BITS_PER_BYTE - 1)) != 0) {
  2229. NumericValue.Uint64 &= (1ULL << BitSize) - 1;
  2230. }
  2231. if (Numeric->Float != FALSE) {
  2232. switch (TypeSize) {
  2233. case 4:
  2234. DbgOut("%f", (double)(NumericValue.Float32));
  2235. break;
  2236. case 8:
  2237. DbgOut("%f", NumericValue.Float64);
  2238. break;
  2239. default:
  2240. DbgOut("%I64x", NumericValue.Uint64);
  2241. break;
  2242. }
  2243. } else if (Numeric->Signed != FALSE) {
  2244. switch (TypeSize) {
  2245. case 1:
  2246. DbgOut("%d", NumericValue.Int8);
  2247. break;
  2248. case 2:
  2249. DbgOut("%d", NumericValue.Int16);
  2250. break;
  2251. case 4:
  2252. DbgOut("%d", NumericValue.Int32);
  2253. break;
  2254. case 8:
  2255. default:
  2256. DbgOut("%I64d", NumericValue.Int64);
  2257. break;
  2258. }
  2259. } else {
  2260. DbgOut("0x%I64x", NumericValue.Uint64);
  2261. }
  2262. return 0;
  2263. }
  2264. INT
  2265. DbgpGetStructureMember (
  2266. PDEBUGGER_CONTEXT Context,
  2267. PTYPE_SYMBOL Type,
  2268. PSTR MemberName,
  2269. ULONGLONG Address,
  2270. PVOID Data,
  2271. UINTN DataSize,
  2272. PVOID *ShiftedData,
  2273. PUINTN ShiftedDataSize,
  2274. PTYPE_SYMBOL *FinalType
  2275. )
  2276. /*++
  2277. Routine Description:
  2278. This routine returns a shifted form of the given data for accessing
  2279. specific members of a structure.
  2280. Arguments:
  2281. Context - Supplies a pointer to the application context.
  2282. Type - Supplies a pointer to the structure type.
  2283. MemberName - Supplies a pointer to the member name string, which can
  2284. contain dot '.' notation for accessing members, and array [] notation
  2285. for access sub-elements and dereferencing.
  2286. Address - Supplies the address the read data is located at.
  2287. Data - Supplies a pointer to the read in data.
  2288. DataSize - Supplies the size of the read data in bytes.
  2289. ShiftedData - Supplies a pointer where the shifted data will be returned on
  2290. success. The caller is responsible for freeing this data when finished.
  2291. ShiftedDataSize - Supplies a pointer where the size of the shifted data
  2292. will be returned on success.
  2293. FinalType - Supplies an optional pointer where the final type of the
  2294. data will be returned on success.
  2295. Return Value:
  2296. 0 on success.
  2297. Returns an error number on failure.
  2298. --*/
  2299. {
  2300. ULONGLONG ArrayIndex;
  2301. PSTR Current;
  2302. PVOID CurrentData;
  2303. UINTN CurrentDataSize;
  2304. BOOL Dereference;
  2305. PSTR End;
  2306. PSTR FieldName;
  2307. CHAR FieldType;
  2308. PSTRUCTURE_MEMBER Member;
  2309. PVOID NewData;
  2310. ULONG NewDataSize;
  2311. CHAR OriginalCharacter;
  2312. PTYPE_SYMBOL RelativeType;
  2313. UINT ShiftAmount;
  2314. INT Status;
  2315. UINTN TypeSize;
  2316. CurrentData = Data;
  2317. CurrentDataSize = DataSize;
  2318. MemberName = strdup(MemberName);
  2319. if (MemberName == NULL) {
  2320. Status = ENOMEM;
  2321. goto GetStructureMemberEnd;
  2322. }
  2323. Type = DbgSkipTypedefs(Type);
  2324. End = MemberName + strlen(MemberName);
  2325. Current = MemberName;
  2326. Status = 0;
  2327. //
  2328. // Now loop reading members and array indices.
  2329. //
  2330. while (Current < End) {
  2331. //
  2332. // Assume a member if a dot is missing from the beginning.
  2333. //
  2334. if ((*Current != '.') && (*Current != '[')) {
  2335. FieldType = '.';
  2336. } else {
  2337. FieldType = *Current;
  2338. Current += 1;
  2339. }
  2340. if (*Current == '\0') {
  2341. break;
  2342. }
  2343. FieldName = Current;
  2344. //
  2345. // Handle an array access.
  2346. //
  2347. if (FieldType == '[') {
  2348. //
  2349. // Find the closing square bracket.
  2350. //
  2351. while ((*Current != '\0') && (*Current != ']')) {
  2352. Current += 1;
  2353. }
  2354. *Current = '\0';
  2355. Current += 1;
  2356. Status = DbgEvaluate(Context, FieldName, &ArrayIndex);
  2357. if (Status != 0) {
  2358. DbgOut("Error: Failed to evaluate array index '%s'.\n",
  2359. FieldName);
  2360. goto GetStructureMemberEnd;
  2361. }
  2362. //
  2363. // If this current type is not a relation, then a dereference will
  2364. // have to occur to make something like mytype[3] work, where
  2365. // mytype is a structure.
  2366. //
  2367. Dereference = FALSE;
  2368. if (Type->Type != DataTypeRelation) {
  2369. Dereference = TRUE;
  2370. //
  2371. // If it is a relation, use the relative type as the type size. If
  2372. // this is a pointer type, then it will also need a dereference
  2373. // through it.
  2374. //
  2375. } else if ((Type->U.Relation.Pointer != 0) ||
  2376. (Type->U.Relation.Array.Minimum !=
  2377. Type->U.Relation.Array.Maximum)) {
  2378. if (Type->U.Relation.Pointer != 0) {
  2379. Dereference = TRUE;
  2380. Address = 0;
  2381. memcpy(&Address, CurrentData, Type->U.Relation.Pointer);
  2382. }
  2383. RelativeType = DbgGetType(Type->U.Relation.OwningFile,
  2384. Type->U.Relation.TypeNumber);
  2385. if ((RelativeType == NULL) || (RelativeType == Type)) {
  2386. DbgOut("Error: Cannot get void type.\n");
  2387. Status = EINVAL;
  2388. goto GetStructureMemberEnd;
  2389. }
  2390. Type = RelativeType;
  2391. }
  2392. TypeSize = DbgGetTypeSize(Type, 0);
  2393. if (TypeSize == 0) {
  2394. DbgOut("Error: Got a type size of zero.\n");
  2395. Status = EINVAL;
  2396. goto GetStructureMemberEnd;
  2397. }
  2398. //
  2399. // If this was a pointer, dereference through the pointer to get
  2400. // the new data.
  2401. //
  2402. if (Dereference != FALSE) {
  2403. Address += TypeSize * ArrayIndex;
  2404. Status = DbgReadType(Context,
  2405. Address,
  2406. Type,
  2407. &NewData,
  2408. &NewDataSize);
  2409. if (Status != 0) {
  2410. goto GetStructureMemberEnd;
  2411. }
  2412. //
  2413. // If this was an array, just shift the buffer over to index into
  2414. // it.
  2415. //
  2416. } else {
  2417. ShiftAmount = TypeSize * ArrayIndex * BITS_PER_BYTE;
  2418. NewData = DbgpShiftBufferRight(CurrentData,
  2419. CurrentDataSize,
  2420. ShiftAmount,
  2421. 0);
  2422. if (NewData == NULL) {
  2423. Status = ENOMEM;
  2424. goto GetStructureMemberEnd;
  2425. }
  2426. NewDataSize = TypeSize;
  2427. }
  2428. //
  2429. // Access a structure member.
  2430. //
  2431. } else if (FieldType == '.') {
  2432. //
  2433. // Find the end of the member name.
  2434. //
  2435. while ((*Current != '\0') && (*Current != '.') &&
  2436. (*Current != '[')) {
  2437. Current += 1;
  2438. }
  2439. OriginalCharacter = *Current;
  2440. *Current = '\0';
  2441. if (Type->Type != DataTypeStructure) {
  2442. DbgOut("Error: %s is not a structure.\n", Type->Name);
  2443. Status = EINVAL;
  2444. goto GetStructureMemberEnd;
  2445. }
  2446. //
  2447. // Find the member. First try matching case, then try case
  2448. // insensitive.
  2449. //
  2450. Member = Type->U.Structure.FirstMember;
  2451. while (Member != NULL) {
  2452. if ((Member->Name != NULL) &&
  2453. (strcmp(Member->Name, FieldName) == 0)) {
  2454. break;
  2455. }
  2456. Member = Member->NextMember;
  2457. }
  2458. if (Member == NULL) {
  2459. Member = Type->U.Structure.FirstMember;
  2460. while (Member != NULL) {
  2461. if ((Member->Name != NULL) &&
  2462. (strcasecmp(Member->Name, FieldName) == 0)) {
  2463. break;
  2464. }
  2465. Member = Member->NextMember;
  2466. }
  2467. }
  2468. if (Member == NULL) {
  2469. DbgOut("Error: Structure %s has no member %s.\n",
  2470. Type->Name,
  2471. FieldName);
  2472. Status = ENOENT;
  2473. goto GetStructureMemberEnd;
  2474. }
  2475. //
  2476. // Get the next type of this member.
  2477. //
  2478. Type = DbgGetType(Member->TypeFile, Member->TypeNumber);
  2479. if (Type != NULL) {
  2480. Type = DbgSkipTypedefs(Type);
  2481. }
  2482. if (Type == NULL) {
  2483. DbgOut("Error: Got incomplete member %s.\n", FieldName);
  2484. Status = EINVAL;
  2485. goto GetStructureMemberEnd;
  2486. }
  2487. //
  2488. // Manipulate the buffer to put the member at the beginning, which
  2489. // creates a new buffer.
  2490. //
  2491. NewData = DbgpShiftBufferRight(CurrentData,
  2492. CurrentDataSize,
  2493. Member->BitOffset,
  2494. Member->BitSize);
  2495. if (NewData == NULL) {
  2496. Status = ENOMEM;
  2497. goto GetStructureMemberEnd;
  2498. }
  2499. NewDataSize = DbgGetTypeSize(Type, 0);
  2500. *Current = OriginalCharacter;
  2501. } else {
  2502. assert(FALSE);
  2503. Status = EINVAL;
  2504. break;
  2505. }
  2506. assert(NewData != NULL);
  2507. if (CurrentData != Data) {
  2508. free(CurrentData);
  2509. }
  2510. CurrentData = NewData;
  2511. CurrentDataSize = NewDataSize;
  2512. }
  2513. GetStructureMemberEnd:
  2514. if (MemberName != NULL) {
  2515. free(MemberName);
  2516. }
  2517. if (Status != 0) {
  2518. if ((CurrentData != NULL) && (CurrentData != Data)) {
  2519. free(CurrentData);
  2520. CurrentData = NULL;
  2521. }
  2522. CurrentDataSize = 0;
  2523. Type = NULL;
  2524. }
  2525. *ShiftedData = CurrentData;
  2526. *ShiftedDataSize = CurrentDataSize;
  2527. *FinalType = Type;
  2528. return Status;
  2529. }
  2530. PVOID
  2531. DbgpShiftBufferRight (
  2532. PVOID Buffer,
  2533. UINTN DataSize,
  2534. UINTN Bits,
  2535. UINTN BitSize
  2536. )
  2537. /*++
  2538. Routine Description:
  2539. This routine shifts a buffer right by a given number of bits. Zero bits
  2540. will be shifted in from the left.
  2541. Arguments:
  2542. Buffer - Supplies a pointer to the buffer contents to shift. This buffer
  2543. will remain untouched.
  2544. DataSize - Supplies the size of the data in bytes.
  2545. Bits - Supplies the number of bits to shift.
  2546. BitSize - Supplies an optional number of bits to keep after shifting, all
  2547. others will be masked. Supply 0 to perform no masking.
  2548. Return Value:
  2549. Returns a pointer to a newly allocated and shifted buffer on success.
  2550. NULL on allocation failure.
  2551. --*/
  2552. {
  2553. UINTN ByteCount;
  2554. PUCHAR Bytes;
  2555. UINTN Index;
  2556. Bytes = malloc(DataSize);
  2557. if (Bytes == NULL) {
  2558. return NULL;
  2559. }
  2560. ByteCount = Bits / BITS_PER_BYTE;
  2561. Bits %= BITS_PER_BYTE;
  2562. if (DataSize > ByteCount) {
  2563. memcpy(Bytes, Buffer + ByteCount, DataSize - ByteCount);
  2564. memset(Bytes + DataSize - ByteCount, 0, ByteCount);
  2565. } else {
  2566. memset(Bytes, 0, DataSize);
  2567. return Bytes;
  2568. }
  2569. if (Bits != 0) {
  2570. //
  2571. // Now the tricky part, shifting by between 1 and 7 bits.
  2572. //
  2573. for (Index = 0; Index < DataSize - 1; Index += 1) {
  2574. Bytes[Index] = (Bytes[Index] >> Bits) |
  2575. (Bytes[Index + 1] << (BITS_PER_BYTE - Bits));
  2576. }
  2577. Bytes[Index] = Bytes[Index] >> Bits;
  2578. }
  2579. //
  2580. // Do some masking as well.
  2581. //
  2582. if (BitSize != 0) {
  2583. Index = BitSize / BITS_PER_BYTE;
  2584. BitSize %= BITS_PER_BYTE;
  2585. if (BitSize != 0) {
  2586. Bytes[Index] &= (1 << BitSize) - 1;
  2587. Index += 1;
  2588. }
  2589. if (Index != DataSize) {
  2590. memset(Bytes + Index, 0, DataSize - Index);
  2591. }
  2592. }
  2593. return Bytes;
  2594. }
  2595. //
  2596. // --------------------------------------------------------- Internal Functions
  2597. //