Генерация / создание файлов mdump для моего приложения - PullRequest
8 голосов
/ 21 сентября 2010

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

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

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

Примечание: я сделал fin d этой статьи,но он очень старый, поэтому я не решаюсь основывать свою работу на этом.
Кажется, что либо проблема с IE 9, либо с сайтом, поэтому у меня были проблемы с тегами.

Ответы [ 2 ]

6 голосов
/ 19 октября 2010

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

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

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

  • Ни в коем случае я не могу портировать это приложение для запуска inn windows mobile.

Так в чем же решение?

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

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

Шаг 2. Создайте обработчик 'crash', который запускает процесс отладчика и ожидает завершения.Я использовал следующие несколько строк кода, чтобы перезапустить тот же 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 - Написать отладкурутина дампа, это может быть в том же exe или в другом exe.Вам нужно будет сослаться (или включить источник) на модули «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

5 голосов
/ 13 октября 2010

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

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

Редактировать

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

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

...