4/1/1998 JosephJ Yesterday I quite successfully set things up so that the kd extensions could be tested as a simple console app. The code in main.c emulates kd from the point of view of the extension dll. It works remarkably well. The memory read/write operations simply read/write memory. I don't know how kd decides which operations are exported by the dll -- does it simply try to do a getprocaddress for anything the user types in? 4/1/1998 JosephJ Plan of action: 1. Write code which hex-dumps all the fields of the ARPC_GLOBALS structure. 2. Fill out the ARPC_CLOBALS description structures. 3. Write basic command parser. 4. Add commands to dump globals // !aac ? d // !aac help !aac dr
. L !aac dr [index] . L !aac dg . !aac dr if[*].*handle* 01234444: ARPC_INTERFACE[0] 09890000: [32] .NDISHandle = 02349880 09890000: [36] .IFHandle = 02349880 01234444: ARPC_INTERFACE[1] 09890000: [32] .NDISHandle = 02349880 09890000: [36] .IFHandle = 02349880 01234444: ARPC_INTERFACE[2] 09890000: [32] .NDISHandle = 02349880 09890000: [36] .IFHandle = 02349880 4/8/1998 JosephJ tok_try_force_to_ident(BOOL fPrefixStart, TOKEN *pTok) // // This gets called when an identifier is expected -- so we see if this // particular token can be interpreted as in identifier. Some examples // of when we can do this: // dt if.*20334 <--- the "20334" could be part of an identifier, because // of the * prefix. // // dt L.help <--- both "L" and "help" would have been parsed as // keywords, but here they are intended to be // identifiers. // dt abc.def <--- abc and def would have been parsed as numbers (they // are valid hex numbers), but are intended to be // identifiers. 4/26/1998 JosephJ Change command structure: !aac i <--- dumps atmarpc interface structure !ndis mpb <--- dumps ndis NDIS_MINIPORT_BLOCK structure !ndis mpb <--- dumps ndis M_DRIVER_BLOCK structure Variations: !acc i 0xf00998009 <-- dump interface at this address !aac i <-- dump interface at last cached interface address, if there is one, else dump list of all interface pointers. !aac i[*] <--- list of all interfaces (if it makes sense) !aac i[2] <--- dump 3rd (zerobased) interface !aac i.*list* <-- as before. List walking support... WalkList( TYPE_INFO *pType, UINT_PTR uStartAddress, UINT uNextOffset, UINT uStartIndex, UINT uEndIndex, DBGCMD *pCmd, NODEFUNC pFunc ); The above function will visit each node in the list in turn, reading just the next pointers. It calls pFunc for each list node between uStartIndex and uEndIndex. It terminates under the first of the following conditions: * Null pointer * ReadMemoryError * Read past uEndIndex * pFunc returns FALSE 5/7/1998 To Do Support following: a -- last-specified adapter i -- last-specified interface a[*] -- adapter list i[*] -- interface list DoCommand -- makeing it more flexable: Add TypeProc to TYPE_INFO: generic func to handle customization: -- print summary information Add ResolveAddress function to DoCommand -- resolve address Add UINT_PTR uLastPtr -- cache of last address used with this type. 5/31/1998 JosephJ Support for dumping flags typedef struct { UINT Mask; UINT Value; char *szName; } FLAGINFO; FLAGINFO rgFlagInfo[] = { {AA_IPMC_AE_GEN_STATE_MASK, AA_IPMC_AE_VALID, "AA_IPMC_AE_VALID"}, {AA_IPMC_AE_GEN_STATE_MASK, AA_IPMC_AE_INVALID, "AA_IPMC_AE_INVALID"}, {AA_IPMC_AE_GEN_STATE_MASK, AA_IPMC_AE_TERMINATING, "AA_IPMC_AE_TERMINATING"}, {AA_IPMC_AE_CONN_STATE_MASK, AA_IPMC_AE_CONN_DISCONNECTED, "AA_IPMC_AE_CONN_DISCONNECTED"} {0,0,NULL} // must be last. }; DumpFlags(dwFlags, rgFlagInfo) { FLAGIONFO *pFI = rgFlagInfo; for(;pFI->szName; pFI++) { if ((dwFlags & pFI->Mask) == pFI->Value) { DbgPrintf(" szName"); } } DbgPrintf("\n"); } Above scheme can deal with traditional enums and 1-bit flags as well. 6/1/1998 JosephJ Perl script .h + annotations -> intermediate_form -> source annotations == allow special cases, so that the generated source does not have to be modified by hand. This allows easy updating. generating code to dump flags: annotation file identifies flag types: (default mask = flag { {MASK } Automatic conversion for: * enum * Flags matching a regex pattern: eg AA_IPMC_AE_* flag: type=enum/macro enum {enum_name}; macroflag{mask, flag_pattern} 7/9/1998 JosephJ Generic list dumping syntax !aac void {1-3@45}.$b25@52 21343434 Dumps a 25-byte section at offset 0x52, for list elements 1 to 3. The next pointer is at offset 0x45. Starting address is 21343434. So: $bnnn means nnn bytes @xxx means byte offset xxx $bnnn@xxx means nnn butes at byte offset xxx Other $ global type definitions: $sz null terminated string $szz multisz stringox $wsz unicode null terminated string $s35 35-byte long ansi string $ws35 35-char long unicode string $dw35 35 dwords $w35 35 16-bit words $pv pointer Some examples ... !aac a -- dumps the most recently referenced adapter (1st time, it will dump the 1st adapter in the global adapter list). !aac a 0x80001092 -- dumps the adapter at the specified address. !aac i -- dumps the most recently referenced interface (1st time, it will dump the 1st interface of the 1st adapter). !aac i.*list* -- dumps all fields of the most recently referenced interface stucture which match the pattern "*list*" !aac ae[*].RefCount -- dumps the ip addreses of all the atm entries of the most recently referenced interface (yes, you can substitute any field name or pattern like "*Ref*" for "RefCount"). !aac ip[*].IPAddress -- dumps the ref counts of all the ip address of the most recently reference atm entry. !aac ip[1] -- dumps the next ip structure in the list of ip structures for an atm entry (so you can step through the list items by successively calling !aac ip[1]). !aac vc[*] -- dumps the vc list for the most recently referenced atm entry. The dumping formats are terrible -- I'll clean it up and provide more type-friendly output format over time.