diff --git a/cosos/Extension.cpp b/cosos/Extension.cpp index 50c4a9d..f9f3c4c 100644 --- a/cosos/Extension.cpp +++ b/cosos/Extension.cpp @@ -33,6 +33,7 @@ Implements Extension class that provides entry points to the debugging engine. #include #include #include +#include #include "AddressCommandParser.h" #include "EEHeapCommandParser.h" @@ -47,6 +48,8 @@ Implements Extension class that provides entry points to the debugging engine. #include "DbgEngLogger.h" #include "HtraceCommandParser.h" #include "DbgEngMemoryReader.h" +#include "DumpHeapCommandParser.h" +#include "SafeWaitHandleParser.h" //---------------------------------------------------------------------------- // @@ -104,9 +107,9 @@ HRESULT EXT_CLASS::Initialize() DebugControl->GetWindbgExtensionApis64(&ExtensionApis); #if _DEBUG - dprintf("COSOS v0.2.2 (%s) - Cousin of Son of Strike (DEBUG build) loaded.\n", __TIMESTAMP__); + dprintf("COSOS v0.2.3 (%s) - Cousin of Son of Strike (DEBUG build) loaded.\n", __TIMESTAMP__); #else - dprintf("COSOS v0.2.2 (%s) - Cousin of Son of Strike loaded.\n", __TIMESTAMP__); + dprintf("COSOS v0.2.3 (%s) - Cousin of Son of Strike loaded.\n", __TIMESTAMP__); #endif DebugControl->Release(); @@ -291,9 +294,9 @@ EXT_COMMAND(waitingforobjects, auto wap = WaitApiStackParser(memory_reader, logger); auto handles = std::vector>(); - auto waited_upon_addresses = std::vector>(); + auto waited_upon_others = std::vector>(); - wap.GetHandlesAndAddresses(stackTracesOutput, handles, waited_upon_addresses); + wap.GetHandlesAndAddresses(stackTracesOutput, handles, waited_upon_others); // Save wait graph. bool save_graph = this->HasArg("dot"); @@ -314,17 +317,38 @@ EXT_COMMAND(waitingforobjects, dot_file << "digraph {\n"; } + // TODO need to find MethodTable of SafeWaitHandle and pass it to DumpHeap. + // Find SafeWaitHandle objects in the heap. + auto dumpheap = DumpHeapCommandParser(executor, logger); + auto dumpheap_output = dumpheap.execute("Microsoft.Win32.SafeHandles.SafeWaitHandle"); + + auto swh_parser = SafeWaitHandleParser(memory_reader, logger); + auto swh_output = swh_parser.execute(dumpheap_output); + + auto handle_address = swh_output.get_handle_addresses(); + // WaitOnAddress and waiting on handles are exclusive. - for (auto waited_upon_address : waited_upon_addresses) + for (auto waited_upon_value : waited_upon_others) { - this->Dml("%x Address:\n", waited_upon_address.second, waited_upon_address.second); - this->Dml("\t%x\n", waited_upon_address.first, waited_upon_address.first); + this->Dml("%x %s:\n", std::get<1>(waited_upon_value), std::get<1>(waited_upon_value), std::get<2>(waited_upon_value).c_str()); + this->Dml("\t%x\n", std::get<0>(waited_upon_value), std::get<0>(waited_upon_value)); + + if (save_graph) + { + dot_file << std::hex << "\"" << std::get<0>(waited_upon_value) << "\" [shape=cds]" << std::endl; + dot_file << "\"" << std::get<0>(waited_upon_value) << "\" -> \"" << std::hex << std::get<1>(waited_upon_value) << " " << std::get<2>(waited_upon_value).c_str() << "\" [label = \"is waiting\"]" << std::endl; + } } HtraceCommandParser htraceCommandParser(executor, logger); auto is_htrace_enabled = htraceCommandParser.is_enabled(); + if (!is_htrace_enabled) + { + dprintf("htrace is not enabled.\n"); + } + for (auto thread_handle : handles) { HandleCommandParser handleCommandParser(executor, logger); @@ -335,6 +359,21 @@ EXT_COMMAND(waitingforobjects, if (prev_handle != thread_handle.second) { + std::string handle_address_dml = ""; + + if (handle_address != nullptr) + { + auto address = handle_address->find(thread_handle.second); + + if (address != handle_address->end()) + { + char buf[100]; + memset(buf, 0, 100); + _snprintf(buf, 100, " object %x", address->second, address->second); + handle_address_dml = std::string(buf); + } + } + if (is_htrace_enabled) { /* Find last opener. */ @@ -346,7 +385,7 @@ EXT_COMMAND(waitingforobjects, { auto last_opener_thread = htrace_output.get_thread_id(); - this->Dml("%x %s last opened by %x:\n", thread_handle.second, thread_handle.second, handle_type.c_str(), last_opener_thread, last_opener_thread); + this->Dml("%x %s%s last opened by %x:\n", thread_handle.second, thread_handle.second, handle_type.c_str(), handle_address_dml, last_opener_thread, last_opener_thread); if (save_graph) { @@ -356,12 +395,12 @@ EXT_COMMAND(waitingforobjects, } else { - this->Dml("%x %s:\n", thread_handle.second, thread_handle.second, handle_type.c_str()); + this->Dml("%x %s%s:\n", thread_handle.second, thread_handle.second, handle_type.c_str(), handle_address_dml.c_str()); } } else { - this->Dml("%x %s:\n", thread_handle.second, thread_handle.second, handle_type.c_str()); + this->Dml("%x %s%s:\n", thread_handle.second, thread_handle.second, handle_type.c_str(), handle_address_dml.c_str()); } } diff --git a/cosos/WaitApiStackParser.cpp b/cosos/WaitApiStackParser.cpp index 0c1f13e..6ecf800 100644 --- a/cosos/WaitApiStackParser.cpp +++ b/cosos/WaitApiStackParser.cpp @@ -32,6 +32,8 @@ Implements WaitApiStackParser for stack trace outputs calling kernel wait APIs. #include #include "WaitApiStackParser.h" +const int OBJECT_COUNT_1 = 101; + std::map> WaitApiStackParser::_symbol_object = { /* symbol_name, count_arg_number, address_arg_number */ { "ntdll!NtWaitForSingleObject", std::make_pair(1, KernelObjectDescriptor::ADDRESS_IS_IMMEDIATE) }, @@ -40,13 +42,30 @@ std::map> WaitApiStackParse { "ntdll!NtWaitForWorkViaWorkerFactory", std::make_pair(1, KernelObjectDescriptor::ADDRESS_IS_IMMEDIATE) }, { "ntdll!NtSignalAndWaitForSingleObject", std::make_pair(2, KernelObjectDescriptor::ADDRESS_IS_IMMEDIATE) }, { "ntdll!NtWaitForAlertByThreadId", std::make_pair(1, KernelObjectDescriptor::ADDRESS_IS_IMMEDIATE) }, + { "ntdll!NtRemoveIoCompletion", std::make_pair(1, KernelObjectDescriptor::ADDRESS_IS_IMMEDIATE) }, + { "ntdll!NtDelayExecution", std::make_pair(2, OBJECT_COUNT_1) }, + { "user32!NtUserMessageCall", std::make_pair(1, KernelObjectDescriptor::ADDRESS_IS_IMMEDIATE) }, // https://msdn.microsoft.com/en-us/library/windows/desktop/ms687069(v=vs.85).aspx }; bool is_handle(std::string symbol_name) { - return symbol_name != "ntdll!NtWaitForAlertByThreadId"; + return symbol_name != "ntdll!NtWaitForAlertByThreadId" + && symbol_name != "ntdll!NtDelayExecution" + && symbol_name != "user32!NtUserMessageCall"; +} + +std::string WaitApiStackParser::get_name(const std::string& symbol_name) +{ + if (symbol_name == "ntdll!NtWaitForAlertByThreadId") + return "Address"; + else if (symbol_name == "ntdll!NtDelayExecution") + return "Delay"; + else if (symbol_name == "user32!NtUserMessageCall") + return "hWnd"; + else + return "Handle"; } /** @@ -154,6 +173,9 @@ KernelObjectDescriptor WaitApiStackParser::ParseObjectDescriptor(const PartialSt case 3: count = stackFrame.arg3; break; + case OBJECT_COUNT_1: + count = 1; + break; default: count = KernelObjectDescriptor::VALUE_NOT_FOUND; break; @@ -162,6 +184,7 @@ KernelObjectDescriptor WaitApiStackParser::ParseObjectDescriptor(const PartialSt auto ret = KernelObjectDescriptor(value, count); ret.set_handle(is_handle(stackFrame.symbol_name)); + ret.set_name(get_name(stackFrame.symbol_name)); return ret; } @@ -257,13 +280,13 @@ Parses objectDescriptors and fills handles and addresses vectors. /// The object descriptors. /// The handles. /// The addresses. -void WaitApiStackParser::GetHandlesAndAddresses(const std::vector* objectDescriptors, std::vector>& handles, std::vector>& addresses) +void WaitApiStackParser::GetHandlesAndAddresses(const std::vector* objectDescriptors, std::vector>& handles, std::vector>& others) { for (auto descriptor : *objectDescriptors) { if (!descriptor.is_handle()) { - addresses.push_back(std::make_pair(descriptor.get_thread_id(), descriptor.get_value())); + others.push_back(std::make_tuple(descriptor.get_thread_id(), descriptor.get_value(), descriptor.get_name())); continue; } @@ -313,7 +336,7 @@ void WaitApiStackParser::GetHandlesAndAddresses(const std::vector a, std::pair b){ return a.second < b.second; }); - std::sort(addresses.begin(), addresses.end(), [](std::pair a, std::pair b){ return a.second < b.second; }); + std::sort(others.begin(), others.end(), [](std::tuple a, std::tuple b){ return std::get<1>(a) < std::get<1>(b); }); } /** @@ -323,11 +346,11 @@ Parses objectDescriptors and fills handles and addresses vectors. \param handles Parsed handles. \param addresses Parsed addresses. */ -void WaitApiStackParser::GetHandlesAndAddresses(const std::string& command_output, std::vector>& handles, std::vector>& addresses) +void WaitApiStackParser::GetHandlesAndAddresses(const std::string& command_output, std::vector>& handles, std::vector>& others) { auto objectDescriptors = Parse(command_output); - GetHandlesAndAddresses(objectDescriptors, handles, addresses); + GetHandlesAndAddresses(objectDescriptors, handles, others); delete objectDescriptors; } \ No newline at end of file diff --git a/cosos/WaitApiStackParser.h b/cosos/WaitApiStackParser.h index 77076d2..6ee686b 100644 --- a/cosos/WaitApiStackParser.h +++ b/cosos/WaitApiStackParser.h @@ -76,6 +76,7 @@ class KernelObjectDescriptor unsigned long _value; unsigned long _count; bool _is_handle = true; + std::string _name; public: static const unsigned long ADDRESS_IS_IMMEDIATE = -1; @@ -96,10 +97,12 @@ class KernelObjectDescriptor unsigned long get_thread_id(){ return _thread_id; } unsigned long get_value(){ return _value; } unsigned long get_count(){ return _count; } + std::string get_name(){ return _name; } unsigned long is_handle(){ return _is_handle; } void set_thread_id(unsigned long thread_id){ _thread_id = thread_id; } void set_handle(unsigned long is_handle){ _is_handle = is_handle; } + void set_name(const std::string& name){ _name = name; } bool is_value_address(){ return _count != ADDRESS_IS_IMMEDIATE; } }; @@ -120,11 +123,11 @@ class WaitApiStackParser KernelObjectDescriptor ParseObjectDescriptor(const PartialStackFrame& stackFrame); PartialStackFrame ParseStackFrame(const std::string& line); std::vector* Parse(const std::string& lines); - - void GetHandlesAndAddresses(const std::vector* objectDescriptors, std::vector>& handles, std::vector>& addresses); + std::string get_name(const std::string& symbol_name); + void GetHandlesAndAddresses(const std::vector* objectDescriptors, std::vector>& handles, std::vector>& others); public: - void GetHandlesAndAddresses(const std::string& command_output, std::vector>& handles, std::vector>& addresses); + void GetHandlesAndAddresses(const std::string& command_output, std::vector>& handles, std::vector>& others); WaitApiStackParser(IMemoryReader *memory_reader, ILogger *logger) : _memory_reader(memory_reader), _logger(logger) diff --git a/dbgenginterface/dbgenginterface.vcxproj b/dbgenginterface/dbgenginterface.vcxproj index 566ac2c..ae53ef5 100644 --- a/dbgenginterface/dbgenginterface.vcxproj +++ b/dbgenginterface/dbgenginterface.vcxproj @@ -15,6 +15,8 @@ + + @@ -28,9 +30,15 @@ + + + + + + diff --git a/dbgenginterface/dbgenginterface.vcxproj.filters b/dbgenginterface/dbgenginterface.vcxproj.filters index a4bbbe0..4d7aad7 100644 --- a/dbgenginterface/dbgenginterface.vcxproj.filters +++ b/dbgenginterface/dbgenginterface.vcxproj.filters @@ -57,6 +57,18 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + @@ -89,5 +101,17 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + \ No newline at end of file diff --git a/dbgenginterface/inc/DumpHeapCommandOutput.h b/dbgenginterface/inc/DumpHeapCommandOutput.h new file mode 100644 index 0000000..0015a24 --- /dev/null +++ b/dbgenginterface/inc/DumpHeapCommandOutput.h @@ -0,0 +1,65 @@ +// Copyright (c) 2015 Kerem KAT +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files(the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Do not hesisate to contact me about usage of the code or to make comments +// about the code. Your feedback will be appreciated. +// +// http://dissipatedheat.com/ +// http://github.com/krk/ + +/** +\file DumpHeapOutput.h + +Defines the DumpHeapCommandOutput class. +*/ + +#ifndef __DUMPHEAPCOMMANDOUTPUT_H__ + +#define __DUMPHEAPCOMMANDOUTPUT_H__ + +#include + +/** +\class DumpHeapCommandOutput + +Represents output of the !dumpheap command. +*/ +class DumpHeapCommandOutput +{ +private: + std::vector *_addresses = nullptr; + +public: + DumpHeapCommandOutput() + { + + } + + DumpHeapCommandOutput(std::vector *addresses) + : _addresses(addresses) + { + + } + + std::vector* get_addresses() const; + + bool has_addresses() const { return _addresses != nullptr&& _addresses->size() > 0; } +}; + +#endif // #ifndef __DUMPHEAPCOMMANDOUTPUT_H__ \ No newline at end of file diff --git a/dbgenginterface/inc/DumpHeapCommandParser.h b/dbgenginterface/inc/DumpHeapCommandParser.h new file mode 100644 index 0000000..bbde2c5 --- /dev/null +++ b/dbgenginterface/inc/DumpHeapCommandParser.h @@ -0,0 +1,73 @@ +// Copyright (c) 2015 Kerem KAT +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files(the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Do not hesisate to contact me about usage of the code or to make comments +// about the code. Your feedback will be appreciated. +// +// http://dissipatedheat.com/ +// http://github.com/krk/ + +/** +\file DumpHeapCommandParser.h + +Defines the DumpHeapCommandParser class. +*/ + +#ifndef __DUMPHEAPCOMMANDPARSER_H__ + +#define __DUMPHEAPCOMMANDPARSER_H__ + +#include "MemoryRange.h" + +#include +#include +#include + +#include "IDebuggerCommandExecutor.h" +#include "ILogger.h" +#include "DumpHeapCommandOutput.h" + +/** +\class DumpHeapCommandParser + +Implements a parser for dumpheap outputs. +*/ +class DumpHeapCommandParser +{ +private: + const std::string _command = "!dumpheap -short -type"; + + IDebuggerCommandExecutor* _executor; + + std::vector* Parse(const std::string& lines); + +protected: + ILogger* _logger; + +public: + DumpHeapCommandParser(IDebuggerCommandExecutor* executor, ILogger* logger) + : _executor(executor), _logger(logger) + { + + } + + DumpHeapCommandOutput execute(const std::string& clr_partial_type_name); +}; + +#endif // #ifndef __DUMPHEAPCOMMANDPARSER_H__ \ No newline at end of file diff --git a/dbgenginterface/inc/SafeWaitHandleOutput.h b/dbgenginterface/inc/SafeWaitHandleOutput.h new file mode 100644 index 0000000..53150f8 --- /dev/null +++ b/dbgenginterface/inc/SafeWaitHandleOutput.h @@ -0,0 +1,65 @@ +// Copyright (c) 2015 Kerem KAT +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files(the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Do not hesisate to contact me about usage of the code or to make comments +// about the code. Your feedback will be appreciated. +// +// http://dissipatedheat.com/ +// http://github.com/krk/ + +/** +\file SafeWaitHandleOutput.h + +Defines the SafeWaitHandleOutput class. +*/ + +#ifndef __SAFEWAITHANDLEOUTPUT_H__ + +#define __SAFEWAITHANDLEOUTPUT_H__ + +#include +#include + +/** +\class SafeWaitHandleOutput + +Represents output of the SafeWaitHandleParser. +*/ +class SafeWaitHandleOutput +{ +private: + std::shared_ptr> _handle_address = nullptr; + +public: + SafeWaitHandleOutput() + { + + } + + SafeWaitHandleOutput(std::shared_ptr> handle_address) + : _handle_address(handle_address) + { + + } + std::shared_ptr> get_handle_addresses(); + + bool has_handle_addresses() { return _handle_address != nullptr && _handle_address->size() > 0; } +}; + +#endif // #ifndef __SAFEWAITHANDLEOUTPUT_H__ \ No newline at end of file diff --git a/dbgenginterface/inc/SafeWaitHandleParser.h b/dbgenginterface/inc/SafeWaitHandleParser.h new file mode 100644 index 0000000..cafaf08 --- /dev/null +++ b/dbgenginterface/inc/SafeWaitHandleParser.h @@ -0,0 +1,69 @@ +// Copyright (c) 2015 Kerem KAT +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files(the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Do not hesisate to contact me about usage of the code or to make comments +// about the code. Your feedback will be appreciated. +// +// http://dissipatedheat.com/ +// http://github.com/krk/ + +/** +\file SafeWaitHandleParser.h + +Defines the SafeWaitHandleParser class. +*/ + +#ifndef __SAFEWAITHANDLEPARSER_H__ + +#define __SAFEWAITHANDLEPARSER_H__ + +#include "MemoryRange.h" + +#include +#include + +#include "IMemoryReader.h" +#include "ILogger.h" +#include "DumpHeapCommandOutput.h" +#include "SafeWaitHandleOutput.h" + +/** +\class SafeWaitHandleParser + +Implements a parser for dumpheap outputs. +*/ +class SafeWaitHandleParser +{ +private: + IMemoryReader* _reader; + ILogger* _logger; + + std::map* parse(const std::vector& object_addresses); + +public: + SafeWaitHandleParser(IMemoryReader* reader, ILogger* logger) + : _reader(reader) + { + _logger = logger; + } + + SafeWaitHandleOutput execute(const DumpHeapCommandOutput& dump_heap_output); +}; + +#endif // #ifndef __SAFEWAITHANDLEPARSER_H__ \ No newline at end of file diff --git a/dbgenginterface/src/DumpHeapCommandOutput.cpp b/dbgenginterface/src/DumpHeapCommandOutput.cpp new file mode 100644 index 0000000..6b5253f --- /dev/null +++ b/dbgenginterface/src/DumpHeapCommandOutput.cpp @@ -0,0 +1,40 @@ +// Copyright (c) 2015 Kerem KAT +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files(the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Do not hesisate to contact me about usage of the code or to make comments +// about the code. Your feedback will be appreciated. +// +// http://dissipatedheat.com/ +// http://github.com/krk/ + +/** +\file DumpHeapCommandOutput.cpp + +Implements DumpHeapCommandOutput class that represents output of the !dumpheap command. +*/ + +#include "DumpHeapCommandOutput.h" + +/** +Returns the parsed addresses. +*/ +std::vector* DumpHeapCommandOutput::get_addresses() const +{ + return _addresses; +} diff --git a/dbgenginterface/src/DumpHeapCommandParser.cpp b/dbgenginterface/src/DumpHeapCommandParser.cpp new file mode 100644 index 0000000..a22da5a --- /dev/null +++ b/dbgenginterface/src/DumpHeapCommandParser.cpp @@ -0,0 +1,96 @@ +// Copyright (c) 2015 Kerem KAT +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files(the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Do not hesisate to contact me about usage of the code or to make comments +// about the code. Your feedback will be appreciated. +// +// http://dissipatedheat.com/ +// http://github.com/krk/ + +/** +\file EEHeapParser.cpp + +Implements EEHeapParser class that parses native !eeheap -gc output. +*/ + +#include +#include +#include +#include + +#include "DumpHeapCommandParser.h" + +/** +Executes address command and parses the output. + +\param handle Value of the handle. +*/ +DumpHeapCommandOutput DumpHeapCommandParser::execute(const std::string& clr_partial_type_name) +{ + std::string output; + + auto command = _command + " " + clr_partial_type_name; + + if (!_executor->ExecuteCommand(command, output)) + { + _logger->Log("Cannot get eeheap info.\n"); + + return DumpHeapCommandOutput(); + } + + auto ranges = Parse(output); + + return DumpHeapCommandOutput(ranges); +} + +/** +Parses lines of an dumpheap output to find the address information. + +\param lines DumpHeap output lines. +*/ +std::vector* DumpHeapCommandParser::Parse(const std::string& lines) +{ + auto ret = new std::vector(); + + std::istringstream iss(lines); + + std::string line; + + while (std::getline(iss, line)) + { + if (line.size() < 8) + { + continue; + } + + auto addressText = line.substr(0, 8); + + try{ + auto address = std::stoul(addressText, nullptr, 16); + + ret->push_back(address); + } + catch (std::invalid_argument) + { + _logger->Log("Address cannot be read: %s\n", line); + } + } + + return ret; +} \ No newline at end of file diff --git a/dbgenginterface/src/SafeWaitHandleOutput.cpp b/dbgenginterface/src/SafeWaitHandleOutput.cpp new file mode 100644 index 0000000..8969f55 --- /dev/null +++ b/dbgenginterface/src/SafeWaitHandleOutput.cpp @@ -0,0 +1,40 @@ +// Copyright (c) 2015 Kerem KAT +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files(the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Do not hesisate to contact me about usage of the code or to make comments +// about the code. Your feedback will be appreciated. +// +// http://dissipatedheat.com/ +// http://github.com/krk/ + +/** +\file SafeWaitHandleOutput.cpp + +Implements SafeWaitHandleOutput class that represents output of the SafeWaitHandleParser. +*/ + +#include "SafeWaitHandleOutput.h" + +/** +Returns the parsed type of the handle. +*/ +std::shared_ptr> SafeWaitHandleOutput::get_handle_addresses() +{ + return _handle_address; +} diff --git a/dbgenginterface/src/SafeWaitHandleParser.cpp b/dbgenginterface/src/SafeWaitHandleParser.cpp new file mode 100644 index 0000000..5d79aa3 --- /dev/null +++ b/dbgenginterface/src/SafeWaitHandleParser.cpp @@ -0,0 +1,84 @@ +// Copyright (c) 2015 Kerem KAT +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files(the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Do not hesisate to contact me about usage of the code or to make comments +// about the code. Your feedback will be appreciated. +// +// http://dissipatedheat.com/ +// http://github.com/krk/ + +/** +\file HandleCommandParser.cpp + +Implements HandleCommandParser class that parses the output of the !handle command. +*/ + +#include "SafeWaitHandleParser.h" +#include "SafeWaitHandleOutput.h" + +/** +Executes a htrace command and parses the output. + +\param handle Value of the handle. +*/ +SafeWaitHandleOutput SafeWaitHandleParser::execute(const DumpHeapCommandOutput& dump_heap_output) +{ + if (!dump_heap_output.has_addresses()) + { + return SafeWaitHandleOutput(); + } + + auto map = parse(*dump_heap_output.get_addresses()); + + auto handle_addresses = std::shared_ptr>(map); + + return SafeWaitHandleOutput(handle_addresses); +} + +/** +Build a map of SafeWaitHandle values to SafeWaitHandle object addresses. +*/ +std::map* SafeWaitHandleParser::parse(const std::vector& object_addresses) +{ + auto ret = new std::map(); + + for (auto address : object_addresses) + { + if (address == 0) + { + continue; + } + + unsigned long handle_value = 0; + + unsigned long bytes_read = 0; + + // read memory. + _reader->ReadMemory(address + 4, &handle_value, sizeof(unsigned long), &bytes_read); + + if (!bytes_read) + { + continue; + } + + (*ret)[handle_value] = address; + } + + return ret; +} \ No newline at end of file