Advertisement
Guest User

Untitled

a guest
Jun 27th, 2017
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.58 KB | None | 0 0
  1. /*
  2. * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16.  
  17. #include <Log.h>
  18. #include <Debugger.h>
  19. #include <DebuggerIO.h>
  20. #include <LocalIO.h>
  21. #include <SerialIO.h>
  22. #include <DisassembleCommand.h>
  23. #include <QuitCommand.h>
  24. #include <PanicCommand.h>
  25. #include <BreakpointCommand.h>
  26. #include <CpuInfoCommand.h>
  27. #include <DumpCommand.h>
  28. #include <LogViewer.h>
  29. #include <Backtracer.h>
  30. #include <AllocationCommand.h>
  31. #include <SlamCommand.h>
  32. #include <utilities/utility.h>
  33. #include <StepCommand.h>
  34. #include <TraceCommand.h>
  35. #include <MemoryInspector.h>
  36. #include <IoCommand.h>
  37. #include <ThreadsCommand.h>
  38. #include <DevicesCommand.h>
  39. #include <LookupCommand.h>
  40. #include <SyscallTracerCommand.h>
  41. #include <LookupCommand.h>
  42. #include <HelpCommand.h>
  43. #include <LocksCommand.h>
  44. #include <MappingCommand.h>
  45. #include <process/Thread.h>
  46. #include <process/initialiseMultitasking.h>
  47. #include <machine/Machine.h>
  48. #include <process/Scheduler.h>
  49. #include <graphics/GraphicsService.h>
  50.  
  51. Debugger Debugger::m_Instance;
  52.  
  53. TraceCommand g_Trace;
  54. /// Helper function. Returns the index of a command in pCommands that matches prefix. Starts searching
  55. /// through pCommands at index start. Returns -1 if none found.
  56. static int getCommandMatchingPrefix(char *prefix, DebuggerCommand **pCommands, size_t nCmds, size_t start)
  57. {
  58.     for (size_t i = start; i < nCmds; i++)
  59.     {
  60.         if (!strncmp(pCommands[i]->getString(), prefix, strlen(prefix)))
  61.             return i;
  62.     }
  63.     return -1;
  64. }
  65.  
  66. /// Helper function. Returns true if the string in pStr matches pCommand. If so, pStr is changed
  67. /// so that on return, it contains the parameters to that command (everything after the first space).
  68. static bool matchesCommand(char *pStr, DebuggerCommand *pCommand)
  69. {
  70.     if (!strncmp(pCommand->getString(), pStr, strlen(pCommand->getString())))
  71.     {
  72.         size_t n = strlen(pCommand->getString());
  73.         memcpy(pStr, pStr+n+1, strlen(pStr)-n);
  74.         return true;
  75.     }
  76.     else
  77.     {
  78.         return false;
  79.     }
  80. }
  81.  
  82. Debugger::Debugger() :
  83. m_pTempState(0), m_nIoType(DEBUGGER)
  84. {
  85. }
  86.  
  87. Debugger::~Debugger()
  88. {
  89. }
  90.  
  91. void Debugger::initialise()
  92. {
  93. #ifndef ARM_COMMON /// \todo Figure out a way of getting similar functionality on ARM
  94.   if (!InterruptManager::instance().registerInterruptHandlerDebugger(InterruptManager::instance().getBreakpointInterruptNumber(), this))
  95.         ERROR_NOLOCK("Debugger: breakpoint interrupt registration failed!");
  96.     if (!InterruptManager::instance().registerInterruptHandlerDebugger(InterruptManager::instance().getDebugInterruptNumber(), this))
  97.         ERROR_NOLOCK("Debugger: debug interrupt registration failed!");
  98. #endif
  99. }
  100.  
  101. /// \todo OZMFGBARBIE, this needs major cleanup. Look at the state of it!! :O
  102. void Debugger::start(InterruptState &state, LargeStaticString &description)
  103. {
  104.     Log::instance() << " << Flushing log content >>" << Flush;
  105.  
  106.     // Drop out of whatever graphics mode we were in
  107.   GraphicsService::GraphicsProvider provider;
  108.     memset(&provider, 0, sizeof(provider));
  109.     provider.bTextModes = true;
  110.  
  111.     ServiceFeatures *pFeatures = ServiceManager::instance().enumerateOperations(String("graphics"));
  112.     Service         *pService  = ServiceManager::instance().getService(String("graphics"));
  113.     bool bSuccess = false;
  114.     if(pFeatures->provides(ServiceFeatures::probe))
  115.         if(pService)
  116.             bSuccess = pService->serve(ServiceFeatures::probe, reinterpret_cast<void*>(&provider), sizeof(provider));
  117.  
  118.         if(bSuccess && !provider.bTextModes)
  119.             provider.pDisplay->setScreenMode(0);
  120.  
  121.         // We take a copy of the interrupt state here so that we can replace it with another thread's interrupt state should we
  122.   // decide to switch threads.
  123. #ifdef MULTIPROCESSOR
  124.         Machine::instance().stopAllOtherProcessors();
  125. #endif
  126.         // The current thread, in case we decide to switch.
  127. #if defined(THREADS)
  128.             Thread *pThread = Processor::information().getCurrentThread();
  129. #endif
  130.  
  131.         bool debugState = Machine::instance().getKeyboard()->getDebugState();
  132.         Machine::instance().getKeyboard()->setDebugState(true);
  133.  
  134.         DebuggerIO *pInterfaces[2] = {0};
  135.  
  136. #ifndef DONT_LOG_TO_SERIAL
  137.         static SerialIO serialIO(Machine::instance().getSerial(0));
  138.         serialIO.initialise();
  139. #endif
  140.  
  141.         /*
  142.         * I/O implementations.
  143.         */
  144.         int nInterfaces = 0;
  145.         if(Machine::instance().getNumVga()) // Not all machines have "VGA", so handle that
  146.   {
  147.             static LocalIO localIO(Machine::instance().getVga(0), Machine::instance().getKeyboard());
  148. #ifdef DONT_LOG_TO_SERIAL
  149.             pInterfaces[0] = &localIO;
  150.             nInterfaces = 1;
  151. #else
  152.                 pInterfaces[0] = &localIO;
  153.             pInterfaces[1] = &serialIO;
  154.             nInterfaces = 2;
  155. #endif
  156.         }
  157. #ifndef DONT_LOG_TO_SERIAL
  158.         else
  159.         {
  160.             pInterfaces[0] = &serialIO;
  161.             nInterfaces = 1;
  162.         }
  163. #endif
  164.  
  165.         if(!nInterfaces)
  166.         {
  167.             // Oops, system doesn't support any output mechanisms!
  168.     ERROR_NOLOCK("This machine/CPU combination doesn't support any output methods for the debugger!");
  169.         }
  170.  
  171.         // IO interface.
  172.   DebuggerIO *pIo = 0;
  173.         int nChosenInterface = -1;
  174.  
  175.         // Commands.
  176.   static DisassembleCommand disassembler;
  177.         static LogViewer logViewer;
  178.         static Backtracer backtracer;
  179.         static QuitCommand quit;
  180.         static BreakpointCommand breakpoint;
  181.         static DumpCommand dump;
  182.         static StepCommand step;
  183.         static MemoryInspector memory;
  184.         static PanicCommand panic;
  185.         static CpuInfoCommand cpuInfo;
  186.         static IoCommand io;
  187.         static DevicesCommand devices;
  188.         static SyscallTracerCommand syscallTracer;
  189.         static LookupCommand lookup;
  190.         static HelpCommand help;
  191.         static MappingCommand mapping;
  192.  
  193. #if defined(THREADS)
  194.             static ThreadsCommand threads;
  195.  
  196.         threads.setPointers(&pThread, &state);
  197. #endif
  198.  
  199. #if defined(THREADS)
  200.             size_t nCommands = 21;
  201. #else
  202.             size_t nCommands = 20;
  203. #endif
  204.         DebuggerCommand *pCommands[] = {&syscallTracer,
  205.             &disassembler,
  206.             &logViewer,
  207.             &backtracer,
  208.             &quit,
  209.             &breakpoint,
  210.             &dump,
  211.             &step,
  212.             &memory,
  213.             &g_Trace,
  214.             &panic,
  215.             &cpuInfo,
  216.             &devices,
  217. #if defined(THREADS)
  218.                 &threads,
  219. #endif
  220.                 &io,
  221.                 &g_AllocationCommand,
  222.                 &g_SlamCommand,
  223.                 &lookup,
  224.                 &help,
  225.                 &g_LocksCommand,
  226.                 &mapping};
  227.  
  228.         // Are we going to jump directly into the tracer? In which case bypass device detection.
  229.   int n = g_Trace.execTrace();
  230.         if (n == -1)
  231.         {
  232.             // Write a "Press any key..." message to each device, then poll each device.
  233.     // The first one with data waiting becomes the active device, all others are locked out.
  234.     for (int i = 0; i < nInterfaces; i++)
  235.             {
  236.                 pInterfaces[i]->disableCli();
  237.                 pInterfaces[i]->drawString("Press any key to enter the debugger...", 0, 0, DebuggerIO::LightBlue, DebuggerIO::Black);
  238.                 NormalStaticString str;
  239.                 str += description;
  240.                 pInterfaces[i]->drawString(str, 2, 0, DebuggerIO::LightBlue, DebuggerIO::Black);
  241.             }
  242.             // Poll each device.
  243.     while (pIo == 0)
  244.                 for (int i = 0; i < nInterfaces; i++)
  245.             {
  246.                 char c = pInterfaces[i]->getCharNonBlock();
  247.                 if ((c >= 32 && static_cast<unsigned char>(c) <= 127) || c == '\n' ||
  248.                     c == 0x08 || c == '\r' || c == 0x09)
  249.                 {
  250.                     pIo = pInterfaces[i];
  251.                     nChosenInterface = i;
  252.                     break;
  253.                 }
  254.             }
  255.         }
  256.         else
  257.         {
  258.             pIo = pInterfaces[n];
  259.             nChosenInterface = n;
  260.         }
  261.         pIo->readDimensions();
  262.  
  263.         // Say sorry to the losers...
  264.   for (int i = 0; i < nInterfaces; i++)
  265.         if (pIo != pInterfaces[i])
  266.             pInterfaces[i]->drawString("Locked by another device.", 1, 0, DebuggerIO::LightRed, DebuggerIO::Black);
  267.  
  268.         pIo->setCliUpperLimit(1); // Give us room for a status bar on top.
  269.   pIo->setCliLowerLimit(1); // And a status bar on the bottom.
  270.   pIo->enableCli(); // Start CLI mode.
  271.  
  272.         description += "\n";
  273.         pIo->writeCli(description, DebuggerIO::Yellow, DebuggerIO::Black);
  274.  
  275.         description.clear();
  276.         description += "Kernel heap ends at ";
  277.         description.append(reinterpret_cast<uintptr_t>(VirtualAddressSpace::getKernelAddressSpace().m_HeapEnd), 16);
  278.         description += "\n";
  279.         pIo->writeCli(description, DebuggerIO::Yellow, DebuggerIO::Black);
  280.  
  281.         // Main CLI loop.
  282.   bool bKeepGoing = false;
  283.         do
  284.         {
  285.             HugeStaticString command;
  286.             HugeStaticString output;
  287.             // Should we jump directly in to the tracer?
  288.     if (g_Trace.execTrace() != -1)
  289.             {
  290.                 bKeepGoing = g_Trace.execute(command, output, state, pIo);
  291.                 continue;
  292.             }
  293.             else
  294.                 g_Trace.setInterface(nChosenInterface);
  295.             // Clear the top and bottom status lines.
  296.     pIo->drawHorizontalLine(' ', 0, 0, pIo->getWidth()-1, DebuggerIO::White, DebuggerIO::Green);
  297.             pIo->drawHorizontalLine(' ', pIo->getHeight()-1, 0, pIo->getWidth()-1, DebuggerIO::White, DebuggerIO::Green);
  298.             // Write the correct text in the upper status line.
  299.     pIo->drawString("Pedigree debugger", 0, 0, DebuggerIO::White, DebuggerIO::Green);
  300.  
  301.             bool matchedCommand = false;
  302.             DebuggerCommand *pAutoComplete = 0;
  303.             while(1)
  304.             {
  305.                 // Try and get a character from the CLI, passing in a buffer to populate and an
  306.       // autocomplete command for if the user presses TAB (if one is defined).
  307.       if (pIo->readCli(command, pAutoComplete))
  308.                     break; // Command complete, try and parse it.
  309.  
  310.                 // The command wasn't complete - let's parse it and try and get an autocomplete string.
  311.       HugeStaticString str;
  312.                 NormalStaticString str2;
  313.                 matchedCommand = false;
  314.                 for (size_t i = 0; i < nCommands; i++)
  315.                 {
  316.                     // TODO: This cast is completly wrong. As I said, don't touch (as in 'write') StaticString's
  317.         //       internal string. The const is not there because I don't like you :-), it is there
  318.         //       because directly writing is not garantueed to work (and it actually will break our code).
  319.         if (matchesCommand(const_cast<char*>(static_cast<const char*>(command)), pCommands[i]))
  320.                     {
  321.                         str2 = static_cast<const char *>(pCommands[i]->getString());
  322.                         str2 += ' ';
  323.                         pCommands[i]->autocomplete(command, str);
  324.                         matchedCommand = true;
  325.                         break;
  326.                     }
  327.                 }
  328.  
  329.                 pAutoComplete = 0;
  330.                 if (!matchedCommand)
  331.                 {
  332.                     int i = -1;
  333.                     while ( (i = getCommandMatchingPrefix(const_cast<char*>(static_cast<const char*>(command)), pCommands, nCommands, i+1)) != -1)
  334.                     {
  335.                         if (!pAutoComplete)
  336.                             pAutoComplete = pCommands[i];
  337.                         str += static_cast<const char*> (pCommands[i]->getString());
  338.                         str += " ";
  339.                     }
  340.                 }
  341.  
  342.                 pIo->drawHorizontalLine(' ', pIo->getHeight()-1, 0, pIo->getWidth()-1, DebuggerIO::White, DebuggerIO::Green);
  343.                 pIo->drawString(str2, pIo->getHeight()-1, 0, DebuggerIO::Yellow, DebuggerIO::Green);
  344.                 pIo->drawString(str, pIo->getHeight()-1, str2.length(), DebuggerIO::White, DebuggerIO::Green);
  345.             }
  346.  
  347.             // A command was entered.
  348.     bool bValidCommand = false;
  349.             for (size_t i = 0; i < nCommands; i++)
  350.             {
  351.                 if (matchesCommand(const_cast<char*>(static_cast<const char*>(command)), pCommands[i]))
  352.                 {
  353.                     bKeepGoing = pCommands[i]->execute(command, output, state, pIo);
  354.                     pIo->writeCli(output, DebuggerIO::LightGrey, DebuggerIO::Black);
  355.                     bValidCommand = true;
  356.                 }
  357.             }
  358.  
  359.             if (!bValidCommand)
  360.             {
  361.                 pIo->writeCli("Unrecognised command.\n", DebuggerIO::LightGrey, DebuggerIO::Black);
  362.                 bKeepGoing = true;
  363.             }
  364.  
  365.         }
  366.         while (bKeepGoing);
  367.         if(Machine::instance().getNumVga())
  368.             pInterfaces[0]->destroy(); // Causes rememberMode to be called twice.
  369. #ifndef DONT_LOG_TO_SERIAL
  370.         serialIO.destroy();
  371. #endif
  372.  
  373.         Machine::instance().getKeyboard()->setDebugState(debugState);
  374.     }
  375.  
  376.     void Debugger::interrupt(size_t interruptNumber, InterruptState &state)
  377.     {
  378.         LargeStaticString description;
  379.         // We switch here on the interrupt number, and dispatch accordingly.
  380.   if (interruptNumber == InterruptManager::instance().getBreakpointInterruptNumber())
  381.         {
  382.             // Here we check to see if the breakpoint was caused by an assertion, or a fatal error.
  383.     if (state.getRegister(0) == ASSERT_FAILED_SENTINEL)
  384.             {
  385.                 // As it's an assert or fatal, we assume state.getRegister(1) is a pointer to a descriptive string.
  386.       const char *pDescription = reinterpret_cast<const char*> (state.getRegister(1));
  387.                 description += pDescription;
  388.             }
  389.             else
  390.             {
  391.                 description += "Breakpoint exception.";
  392.             }
  393.             start(state, description);
  394.         }
  395.         else if (interruptNumber == InterruptManager::instance().getDebugInterruptNumber())
  396.             {
  397.                 Processor::setSingleStep(false, state);
  398.                 description = "Debug/trap exception";
  399.                 start(state, description);
  400.             }
  401.         }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement