Сгенерируйте / создайте файлы mdump для в моем приложении

Я ищу способ генерировать файлы минидампа в своих приложениях, аналогично тому, что ProcDump делает это, но предварительно с кодом и без необходимости извлекать для этого инструмент 3dparty.

Основные причины отказа от использования ProcDump:
1) Размер двоичного файла значительно увеличится (это проблема, потому что мои приложения бесплатны, а пропускная способность платная).
2) Кажется грязным.
3) Я не могу перенести это приложение для запуска inn Windows Mobile.

Мои требования:
1) Возможность создавать файлы mdump в случае фатального сбоя.
2) Возможность делать "паузу" в приложении, делать дамп, и contiune будет бонусом
.
Если это не вариант, есть ли способ получить значения локальных переменных в текущем контексте динамически?

Боковое примечание: я просмотрел эту статью, но она очень старая. поэтому я не решаюсь основывать свою работу на этом.
Похоже, проблема связана либо с IE 9, либо с сайтом, поэтому у меня были проблемы с тегами.


person EKS    schedule 20.09.2010    source источник
comment
какое-нибудь окончательное хорошее решение по этой проблеме? с хорошим примером исходного кода приложения в .NET?   -  person Kiquenet    schedule 05.09.2011


Ответы (2)


Итак, на ум приходит одно решение, отвечающее следующим целям:

  • Размер двоичного файла увеличится примерно на 300 КБ.
  • Возможность создания файлов mdump в случае фатального сбоя.
  • Возможность сделать "паузу" в приложении сделать дамп, а продолжение будет бонусом

Я дам этому требованию полное неизвестное:

  • Я никак не могу перенести это приложение для запуска inn Windows Mobile.

Так в чем же выход?

Интегрируйте необходимые части из образца Microsoft для MDbg.exe, чтобы предоставить вам своевременный отладчик, который подключается, выгружает и отключается от процесса сбоя.

Шаг 1. Начните с загрузки исходного кода на mdbg отсюда: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=38449a42-6b7a-4e28-80ce-c55645ab1310&DisplayLang=ru

Шаг 2 - Создайте обработчик сбоя, который запускает процесс отладчика и ожидает завершения. Я использовал следующие несколько строк кода, чтобы повторно запустить тот же exe с несколькими дополнительными аргументами, чтобы вызвать отладчик и вывести файл xml в std :: out.

string tempFile = Path.GetTempFileName();
Mutex handle = new Mutex(true, typeof(Program).Namespace + "-self-debugging");
try
{
    Process pDebug = Process.Start(typeof(Program).Assembly.Location,
        "debug-dump " + Process.GetCurrentProcess().Id + " " + tempFile);
    if (pDebug != null)
        pDebug.WaitForExit();
}
catch { }
finally
{
    handle.ReleaseMutex();
}

Console.WriteLine(File.ReadAllText(tempFile));

Шаг 3 - Напишите процедуру дампа отладки, она может быть в том же исполняемом файле или в другом исполняемом файле. Вам нужно будет указать (или включить исходный код) модули raw, corapi и mdbgeng из образца. Затем добавьте несколько строк в свой Main ():

public static void Main(string[] args)
{
    if (args.Length > 0 && args[0] == "debug-dump")
    {   //debug-dump process by id = args[1], output = args[2]
        using (XmlTextWriter wtr = new XmlTextWriter(args[2], Encoding.ASCII))
        {
            wtr.Formatting = Formatting.Indented;
            PerformDebugDump(Int32.Parse(args[1]), wtr);
        }
        return;
    }
    //... continue normal program execution
}

static void PerformDebugDump(int process, XmlWriter x)
{
    x.WriteStartElement("process");
    x.WriteAttributeString("id", process.ToString());
    x.WriteAttributeString("time", XmlConvert.ToString(DateTime.Now, XmlDateTimeSerializationMode.RoundtripKind));

    MDbgEngine e = new MDbgEngine();
    MDbgProcess me = e.Attach(process);
    me.Go().WaitOne();

    try
    {
        x.WriteStartElement("modules");
        foreach (MDbgModule mod in me.Modules)
            x.WriteElementString("module", mod.CorModule.Name);
        x.WriteEndElement();

        foreach (MDbgThread thread in me.Threads)
        {
            x.WriteStartElement("thread");
            x.WriteAttributeString("id", thread.Id.ToString());
            x.WriteAttributeString("number", thread.Number.ToString());
            int ixstack = -1;

            foreach (MDbgFrame frame in thread.Frames)
            {
                x.WriteStartElement("frame");
                x.WriteAttributeString("ix", (++ixstack).ToString());
                x.WriteAttributeString("loc", frame.ToString(String.Empty));
                string valueText = null;

                x.WriteStartElement("args");
                try
                {
                    foreach (MDbgValue value in frame.Function.GetArguments(frame))
                    {
                        x.WriteStartElement(value.Name);
                        x.WriteAttributeString("type", value.TypeName);
                        try { x.WriteAttributeString("value", value.GetStringValue(1, false)); }
                        finally { x.WriteEndElement(); }
                    }
                }
                catch { }
                x.WriteEndElement();

                x.WriteStartElement("locals");
                try
                {
                    foreach (MDbgValue value in frame.Function.GetActiveLocalVars(frame))
                    {
                        x.WriteStartElement(value.Name);
                        x.WriteAttributeString("type", value.TypeName);
                        try { x.WriteAttributeString("value", value.GetStringValue(1, false)); }
                        finally { x.WriteEndElement(); }
                    }
                }
                catch { }
                x.WriteEndElement();
                x.WriteEndElement();
            }
            x.WriteEndElement();
        }
    }
    finally
    {
        me.Detach().WaitOne();
    }

    x.WriteEndElement();
}

Пример вывода

<process id="8276" time="2010-10-18T16:03:59.3781465-05:00">
<modules>
<module>C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll</module>
...etc
</modules>
<thread id="17208" number="0">
<frame ix="0" loc="System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop (source line information unavailable)">
    <args>
        <this type="System.Windows.Forms.Application.ComponentManager" value="System.Windows.Forms.Application.ComponentManager&#xA;    oleComponents=System.Collections.Hashtable&#xA; cookieCounter=1&#xA;    activeComponent=System.Windows.Forms.Application.ThreadContext&#xA; trackingComponent=&lt;null&gt;&#xA; currentState=0" />
        <dwComponentID type="N/A" value="&lt;N/A&gt;" />
        <reason type="System.Int32" value="-1" />
        <pvLoopData type="System.Int32" value="0" />
    </args>
    <locals>
        <local_0 type="System.Int32" value="0" />
        <local_1 type="System.Boolean" value="True" />
        <local_2 type="System.Windows.Forms.UnsafeNativeMethods.IMsoComponent" value="&lt;null&gt;" />
        <local_3 type="N/A" value="&lt;N/A&gt;" />
        <local_4 type="N/A" value="&lt;N/A&gt;" />
        <local_5 type="N/A" value="&lt;N/A&gt;" />
        <local_6 type="System.Windows.Forms.Application.ThreadContext" value="System.Windows.Forms.Application.ThreadContext&#xA;   contextHash=System.Collections.Hashtable&#xA;   tcInternalSyncObject=System.Object&#xA; totalMessageLoopCount=1&#xA;    baseLoopReason=-1&#xA;  currentThreadContext=System.Windows.Forms.Application.ThreadContext&#xA;    threadExceptionHandler=System.Threading.ThreadExceptionEventHandler&#xA;    idleHandler=&lt;null&gt;&#xA;   enterModalHandler=&lt;null&gt;&#xA; leaveModalHandler=&lt;null&gt;&#xA; applicationContext=System.Windows.Forms.ApplicationContext&#xA; parkingWindow=&lt;null&gt;&#xA; marshalingControl=System.Windows.Forms.Application.MarshalingControl&#xA;   culture=&lt;null&gt;&#xA;   messageFilters=&lt;null&gt;&#xA;    messageFilterSnapshot=&lt;null&gt;&#xA; handle=912&#xA; id=17208&#xA;   messageLoopCount=1&#xA; threadState=1&#xA;  modalCount=0&#xA;   activatingControlRef=&lt;null&gt;&#xA;  componentManager=System.Windows.Forms.Application.ComponentManager&#xA; externalComponentManager=False&#xA; fetchingComponentManager=False&#xA; componentID=1&#xA;  currentForm=Program.MainForm&#xA;   threadWindows=&lt;null&gt;&#xA; tempMsg=System.Windows.Forms.NativeMethods.MSG&#xA; disposeCount=0&#xA; ourModalLoop=False&#xA; messageLoopCallback=&lt;null&gt;&#xA;   __identity=&lt;null&gt;" />
        <local_7 type="N/A" value="&lt;N/A&gt;" />
        <local_8 type="N/A" value="&lt;N/A&gt;" />
        <local_9 type="N/A" value="&lt;N/A&gt;" />
        <local_10 type="N/A" value="&lt;N/A&gt;" />
        <local_11 type="N/A" value="&lt;N/A&gt;" />
        <local_12 type="N/A" value="&lt;N/A&gt;" />
        <local_13 type="System.Boolean" value="False" />
        <local_14 type="System.Windows.Forms.NativeMethods.MSG[]" value="array [1]&#xA; [0] = System.Windows.Forms.NativeMethods.MSG" />
    </locals>
</frame>
<frame ix="1" loc="System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner (source line information unavailable)">
    <args>
        <this type="System.Windows.Forms.Application.ThreadContext" value="System.Windows.Forms.Application.ThreadContext&#xA;  contextHash=System.Collections.Hashtable&#xA;   tcInternalSyncObject=System.Object&#xA; totalMessageLoopCount=1&#xA;    baseLoopReason=-1&#xA;  currentThreadContext=System.Windows.Forms.Application.ThreadContext&#xA;    threadExceptionHandler=System.Threading.ThreadExceptionEventHandler&#xA;    idleHandler=&lt;null&gt;&#xA;   enterModalHandler=&lt;null&gt;&#xA; leaveModalHandler=&lt;null&gt;&#xA; applicationContext=System.Windows.Forms.ApplicationContext&#xA; parkingWindow=&lt;null&gt;&#xA; marshalingControl=System.Windows.Forms.Application.MarshalingControl&#xA;   culture=&lt;null&gt;&#xA;   messageFilters=&lt;null&gt;&#xA;    messageFilterSnapshot=&lt;null&gt;&#xA; handle=912&#xA; id=17208&#xA;   messageLoopCount=1&#xA; threadState=1&#xA;  modalCount=0&#xA;   activatingControlRef=&lt;null&gt;&#xA;  componentManager=System.Windows.Forms.Application.ComponentManager&#xA; externalComponentManager=False&#xA; fetchingComponentManager=False&#xA; componentID=1&#xA;  currentForm=Program.MainForm&#xA;   threadWindows=&lt;null&gt;&#xA; tempMsg=System.Windows.Forms.NativeMethods.MSG&#xA; disposeCount=0&#xA; ourModalLoop=False&#xA; messageLoopCallback=&lt;null&gt;&#xA;   __identity=&lt;null&gt;" />
        <reason type="System.Int32" value="-1" />
        <context type="System.Windows.Forms.ApplicationContext" value="System.Windows.Forms.ApplicationContext&#xA; mainForm=Program.MainForm&#xA;  userData=&lt;null&gt;&#xA;  ThreadExit=System.EventHandler" />
    </args>
    <locals>
        <local_0 type="System.Windows.Forms.Form" value="&lt;null&gt;" />
        <local_1 type="System.Boolean" value="False" />
        <local_2 type="N/A" value="&lt;N/A&gt;" />
        <local_3 type="N/A" value="&lt;N/A&gt;" />
        <local_4 type="N/A" value="&lt;N/A&gt;" />
    </locals>
</frame>
... etc
</thread>
</process>

Поскольку у вас есть все возможности отладчика, ничто не мешает вам писать столько или меньше, сколько захотите, но приведенный выше пример должен помочь вам начать работу.

ОБНОВЛЕНИЕ

Это работает со средой выполнения .Net 2.0 и / или 3.5 без каких-либо дополнительных зависимостей.

Это может отлаживать код .Net 2.0 / 3.5, работающий в процессе .Net 4.0; однако он не работает с 4.0 (пока).

Для 4.0 CLR см. Это сообщение: http://blogs.msdn.com/b/rmbyers/archive/2008/10/27/icordebug-re-architecture-in-clr-4-0.aspx

person csharptest.net    schedule 18.10.2010
comment
@ csharptest.net - согласно странице, на которую вы указали ссылку, для него требуется установка .Net 2.0 SDK, который может быть недоступен на клиентском компьютере. Кроме того, поддерживает ли он программы .Net 4? - person Giorgi; 19.10.2010
comment
это реальная вещь, которую следует учитывать - может быть, кто-то знает минимальные требования для развертывания конечного пользователя? - person Daniel Mošmondor; 19.10.2010
comment
Хотя я не проверял это, я не верю, что есть какие-либо требования, кроме среды выполнения .net. Что касается .net 4.0, вам понадобится только образец из этой версии SDK (при условии, что MS обновила его? IDK, он может даже работать, так как все он основан на COM. Я попробую его без установленного SDK, когда я приступлю к работе . - person csharptest.net; 19.10.2010
comment
@ csharptest.net - Я играл с ним, и значения локальных переменных большую часть времени N / A (как в вашем примере). Есть идеи, почему это происходит и как этого избежать? - person Giorgi; 25.10.2010
comment
@Giorgi, вы можете сделать это отдельным вопросом. Разместите ссылку на следующий вопрос здесь, и я посмотрю, что я могу придумать за это время. - person csharptest.net; 25.10.2010
comment
@ csharptest.net - Я играю с ним, поэтому, если сам ничего не найду, то задам вопрос. - person Giorgi; 25.10.2010
comment
Вот одно обсуждение темы: social.msdn.microsoft.com/Forums/en-US/netfxtoolsdev/thread/ Похоже, это может быть результатом JIT-оптимизации, поскольку вы не запускаете процесс с помощью отладчика. - person csharptest.net; 25.10.2010

Вы можете вызвать MiniDumpWriteDump из AppDomain.UnhandledException или Application.ThreadException обработчик событий для создания минидампа. В этой статье подробно описывается функция: Эффективные минидампы

Вы также можете использовать эту библиотеку, которая также имеет другие функции: Поймайте все ошибки с помощью BugTrap!

Изменить

Похоже, получить полезный минидамп не так-то просто. В первую очередь sos.dll жалуется на неполный дамп (размер полных дампов составляет около 100-150 МБ). Во-вторых, не рекомендуется писать дамп в блоке catch: Получение хороших дампов при возникновении исключения.

Если у вас есть приложение winforms, в этом вопросе есть полезная информация: Как работает SetUnhandledExceptionFilter работать в приложениях .NET WinForms?

person Giorgi    schedule 12.10.2010
comment
Я уже перехватываю необработанные Exeptions, но мне нужно получить значения локальных переменных. И я в основном ищу способ сделать это динамически. И я не думаю, что могу создавать полные дампы, если это единственный вариант, я сделаю это, но предпочел бы мини-дампы, да. - person EKS; 16.10.2010
comment
@EKS - для этого вам понадобится дамп. - person Giorgi; 16.10.2010
comment
Я подумал об этом, собираюсь проверить то, что ты опубликовал завтра. В банкомате локальной вечеринки :) - person EKS; 17.10.2010
comment
не могли бы вы взглянуть на это: stackoverflow.com/questions/3963542/ У меня есть все дескрипторы исключений, но они все равно не отлавливаются .... есть опыт? - person Daniel Mošmondor; 19.10.2010