//---------------------------------------------------------------------------- // // Functions dealing with instructions, such as assembly or disassembly. // // Copyright (C) Microsoft Corporation, 1997-2002. // //---------------------------------------------------------------------------- #include "ntsdp.hpp" ADDR g_DisasmSearchStartAddress; ADDR g_DisasmSearchLastPc; char g_DisasmSearchLastPattern[256]; ULONG g_AsmOptions; ULONG g_X86BiosBaseAddress; // This array must be in DEBUG_ASMOPT bit order. PCSTR g_AsmOptionNames[] = { "verbose", "no_code_bytes", "ignore_output_width", }; void DotAsm(PDOT_COMMAND Cmd, DebugClient* Client) { ULONG Flags = 0; PSTR Arg; ULONG i; for (;;) { // // Parse out a single flag argument. // if (!PeekChar() || *g_CurCmd == ';') { break; } Arg = g_CurCmd; while (*g_CurCmd && !isspace(*g_CurCmd)) { g_CurCmd++; } if (isspace(*g_CurCmd)) { *g_CurCmd++ = 0; } // // Find value for argument. // for (i = 0; i < DIMA(g_AsmOptionNames); i++) { if (!_stricmp(Arg, g_AsmOptionNames[i])) { break; } } if (i < DIMA(g_AsmOptionNames)) { Flags |= 1 << i; } else { ErrOut("Unknown assembly option '%s'\n", Arg); } } if (Cmd->Name[3] != '-') { g_AsmOptions |= Flags; } else { g_AsmOptions &= ~Flags; } NotifyChangeEngineState(DEBUG_CES_ASSEMBLY_OPTIONS, g_AsmOptions, TRUE); dprintf("Assembly options:"); if (g_AsmOptions == 0) { dprintf(" \n"); } else { for (i = 0; i < DIMA(g_AsmOptionNames); i++) { if (g_AsmOptions & (1 << i)) { dprintf(" %s", g_AsmOptionNames[i]); } } dprintf("\n"); } } void ParseInstrGrep(void) { ADDR NextGrepAddr; ADDR CurrGrepAddr; char SourceLine[MAX_DISASM_LEN]; PSTR Pattern; char Save; ULONG64 Length; if (IS_CUR_CONTEXT_ACCESSIBLE()) { g_Machine->GetPC(&g_DisasmSearchLastPc); } Pattern = StringValue(STRV_SPACE_IS_SEPARATOR | STRV_ESCAPED_CHARACTERS | STRV_ALLOW_EMPTY_STRING, &Save); if (Pattern) { g_DisasmSearchLastPattern[0] = '*'; g_DisasmSearchLastPattern[1] = 0; while (Pattern[0] == '*') { Pattern++; } CatString(g_DisasmSearchLastPattern, Pattern, DIMA(g_DisasmSearchLastPattern)); if (Pattern[strlen(Pattern) - 1] != '*') { CatString(g_DisasmSearchLastPattern, "*", DIMA(g_DisasmSearchLastPattern)); } *g_CurCmd = Save; Length = DEBUG_INVALID_OFFSET; g_PrefixSymbols = TRUE; GetRange(&g_DisasmSearchStartAddress, &Length, 1, SEGREG_CODE, DEFAULT_RANGE_LIMIT); g_PrefixSymbols = FALSE; } if (!Flat(g_DisasmSearchStartAddress)) { if (IS_CUR_CONTEXT_ACCESSIBLE()) { dprintf("Search address set to "); dprintAddr(&g_DisasmSearchLastPc); dprintf("\n"); g_DisasmSearchStartAddress = g_DisasmSearchLastPc; } else { ErrOut("Search address required\n"); } return; } NextGrepAddr = g_DisasmSearchStartAddress; while (Length == DEBUG_INVALID_OFFSET || Length-- > 0) { CurrGrepAddr = NextGrepAddr; if (!g_Machine-> Disassemble(g_Process, &NextGrepAddr, SourceLine, FALSE)) { break; } if (MatchPattern(SourceLine, g_DisasmSearchLastPattern)) { g_LastEvalResult.SetU64(Flat(CurrGrepAddr)); g_DisasmSearchStartAddress = NextGrepAddr; OutputSymAddr(Flat(CurrGrepAddr), SYMADDR_FORCE | SYMADDR_LABEL | SYMADDR_SOURCE, NULL); dprintf("%s", SourceLine); if (Length == DEBUG_INVALID_OFFSET) { return; } } if (CheckUserInterrupt()) { return; } } } void TryAssemble(PADDR Addr) { char Assemble[MAX_DISASM_LEN]; // // Set local prompt and command. // g_CommandStart = Assemble; g_CurCmd = Assemble; g_PromptLength = 9; Assemble[0] = '\0'; while (TRUE) { char Ch; dprintAddr(Addr); GetInput("", Assemble, sizeof(Assemble), GETIN_LOG_INPUT_LINE); g_CurCmd = Assemble; RemoveDelChar(g_CurCmd); do { Ch = *g_CurCmd++; } while (Ch == ' ' || Ch == '\t'); if (Ch == '\0') { break; } g_CurCmd--; DBG_ASSERT(fFlat(*Addr) || fInstrPtr(*Addr)); g_Machine->Assemble(g_Process, Addr, g_CurCmd); } } void ParseAssemble(void) { // // Save present prompt and command. // PSTR StartSave = g_CommandStart; // saved start of cmd buffer PSTR CommandSave = g_CurCmd; // current ptr in cmd buffer ULONG PromptSave = g_PromptLength; // size of prompt string BOOL Done = FALSE; char Ch; if (!IS_CUR_MACHINE_ACCESSIBLE()) { error(BADTHREAD); } if ((Ch = PeekChar()) != '\0' && Ch != ';') { GetAddrExpression(SEGREG_CODE, &g_AssemDefault); } while (!Done) { __try { TryAssemble(&g_AssemDefault); // If assembly returned normally we're done. Done = TRUE; } __except(CommandExceptionFilter(GetExceptionInformation())) { // If illegal input was encountered keep looping. } } // // Restore entry prompt and command. // g_CommandStart = StartSave; g_CurCmd = CommandSave; g_PromptLength = PromptSave; } void ParseUnassemble(void) { char Ch; ULONG64 Length; BOOL HasLength; char Text[MAX_DISASM_LEN]; if (!IS_CUR_MACHINE_ACCESSIBLE()) { error(BADTHREAD); } Ch = (char)tolower(*g_CurCmd); if (Ch == 'r') { g_CurCmd++; } else if (IS_KERNEL_TARGET(g_Target) && Ch == 'x') { g_CurCmd += 1; } Length = (g_Machine->m_ExecTypes[0] == IMAGE_FILE_MACHINE_IA64) ? 9 : 8; g_PrefixSymbols = TRUE; HasLength = GetRange(&g_UnasmDefault, &Length, 0, SEGREG_CODE, DEFAULT_RANGE_LIMIT); g_PrefixSymbols = FALSE; if (IS_KERNEL_TARGET(g_Target) && Ch == 'x') { ADDR Addr; if (g_X86BiosBaseAddress == 0) { ULONG64 SymAddr; if (GetOffsetFromSym(g_Process, "hal!HalpEisaMemoryBase", &SymAddr, NULL) != 1) { error(VARDEF); } if (g_Target-> ReadAllVirtual(g_Process, SymAddr, &g_X86BiosBaseAddress, sizeof(ULONG)) != S_OK) { g_X86BiosBaseAddress = 0; error(MEMORY); } } Addr = g_UnasmDefault; Addr.flat += (g_X86BiosBaseAddress + (Addr.seg << 4)); Addr.off = Addr.flat; Addr.type = ADDR_V86 | INSTR_POINTER; while (Length-- > 0) { g_Target->m_Machines[MACHIDX_I386]-> Disassemble(g_Process, &Addr, Text, TRUE); Addr.flat = Addr.off; dprintf("%s", Text); } g_UnasmDefault = Addr; g_UnasmDefault.off -= (g_X86BiosBaseAddress + (Addr.seg << 4)); g_UnasmDefault.flat = g_UnasmDefault.off; } else { MachineInfo* Machine; if (Ch == 'r') { // Force V86-mode address to force 16-bit disassembly. // We leave the flat address so that the actual // address used is not changed and we tweak // the seg:off pair to represent a count from the // start address. g_UnasmDefault.seg = 0; g_UnasmDefault.off = Flat(g_UnasmDefault) & 0xffff; g_UnasmDefault.type = ADDR_V86 | FLAT_COMPUTED | FLAT_BASIS; Machine = g_Target->m_Machines[MACHIDX_I386]; } else { Machine = g_Machine; } BOOL Status; ADDR EndAddr; ULONG SymAddrFlags = SYMADDR_FORCE | SYMADDR_LABEL | SYMADDR_SOURCE; ADDRFLAT(&EndAddr, Length); while ((HasLength && Length--) || (!HasLength && AddrLt(g_UnasmDefault, EndAddr))) { OutputSymAddr(Flat(g_UnasmDefault), SymAddrFlags, NULL); Status = Machine-> Disassemble(g_Process, &g_UnasmDefault, Text, FALSE); dprintf("%s", Text); if (!Status) { error(MEMORY); } SymAddrFlags &= ~SYMADDR_FORCE; if (CheckUserInterrupt()) { return; } } } }