Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Post mortem C++ exception analysis in embedded applications

, 21 Aug 2009 CPOL
An article on analysing a program exception or software crash.
CallStackTest_src.zip
CallStackTest
CallStackTest
Ensor6 (x86)
Debug
Win32
Debug
Release
DiaTool
DiaTool
DiaTool.csproj.user
Properties
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DiaTool
{
    internal class ModuleInfo
    {
        public ModuleInfo(UInt64 baseAddress, UInt64 endAddress, string moduleName, string pdbName)
        {
            if (endAddress < baseAddress)
            {
                throw new Exception("ModuleInfo() endAddress < baseAddress is not allowed.");
            }
            m_baseAddress = baseAddress;
            m_endAddress = endAddress;
            m_moduleName = moduleName;
            m_pdbName = pdbName;
        }

        public UInt64 BaseAddress
        {
            get { return m_baseAddress; }
        }

        public UInt64 EndAddress
        {
            get { return m_endAddress; }
        }

        public string ModuleName
        {
            get { return m_moduleName; }
        }

        public string PdbName
        {
            get { return m_pdbName; }
        }

        public bool Contains(UInt64 address)
        {
            if ((m_baseAddress <= address) && (address <= m_endAddress))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        private UInt64 m_baseAddress;
        private UInt64 m_endAddress;
        private string m_moduleName;
        private string m_pdbName;
    }

    public class Dia
    {
        public Dia(List<string> filesToProcess, List<string> filesToAnalyze, string outputFile)
        {
            m_filesToProcess = filesToProcess;
            m_filesToAnalyze = filesToAnalyze;
            m_outputFile = outputFile;
            m_addressTable = new Dictionary< string, Dictionary<UInt64, string > >();
        }

        public void Process()
        {
            if (m_filesToProcess.Count == 0)
            {
                // Don't bother
                return;
            }

            using (System.IO.StreamWriter writer = new System.IO.StreamWriter(m_outputFile))
            {
                for (int i = 0; i < m_filesToProcess.Count; i++)
                {
                    string pdbPath = m_filesToProcess[i];
                    string pdbName = System.IO.Path.GetFileName(pdbPath);

                    Dia2Lib.DiaSourceClass dia = new Dia2Lib.DiaSourceClass();
                    dia.loadDataFromPdb(pdbPath);
                    Dia2Lib.IDiaSession session;
                    dia.openSession(out session);
                    Dia2Lib.IDiaSymbol globalScope = session.globalScope;
                    uint machineType = globalScope.machineType;

                    Dictionary< UInt64, string > addressTable = new Dictionary< UInt64, string >();
                    m_addressTable.Add(pdbName, addressTable);

                    Dia2Lib.IDiaEnumSymbols result;
                    session.findChildren(null, Dia2Lib.SymTagEnum.SymTagNull, null, 0, out result);
                    globalScope.findChildren(Dia2Lib.SymTagEnum.SymTagNull, null, 0, out result);
                    foreach (Dia2Lib.IDiaSymbol symbol in result)
                    {
                        if (symbol.function != 0)
                        {
                            if (addressTable.ContainsKey(symbol.relativeVirtualAddress) == true)
                            {
                                string name = addressTable[symbol.relativeVirtualAddress];
                                if (name != symbol.name)
                                {
                                    //throw new Exception("Address with multiple symbol names");
                                    // happended with std::logic_error, need to be investigated further
                                    // ??_Glogic_error@std@@UAEPAXI@Z
                                    // ??_Elogic_error@std@@UAEPAXI@Z
                                    continue;
                                } else
                                {
                                    continue;
                                }
                            }
                            addressTable.Add(symbol.relativeVirtualAddress, symbol.undecoratedName);
                            writer.WriteLine("{0:X8}\t{1}\t{2}", symbol.relativeVirtualAddress, pdbName, symbol.undecoratedName);
                        }
                    }
                }
            }
        }

        public void Analyze()
        {
            if (m_filesToProcess.Count == 0)
            {
                // Don't bother
                return;
            }

            if (m_filesToAnalyze.Count == 0)
            {
                // Don't bother
                return;
            }

            for (int i = 0; i < m_filesToAnalyze.Count; i++)
            {
                using (System.IO.StreamReader reader = new System.IO.StreamReader(m_filesToAnalyze[i]))
                {
                    using (System.IO.StreamWriter writer = new System.IO.StreamWriter(m_filesToAnalyze[i] + ".anl"))
                    {
                        // Search for mark point for modules list
                        while (reader.EndOfStream == false)
                        {
                            string line = reader.ReadLine().ToLower();
                            if (line.Contains("start modules dump") == true)
                            {
                                break;
                            }
                        }

                        // Read modules info
                        m_moduleInfo = new List<ModuleInfo>();
                        while (reader.EndOfStream == false)
                        {
                            string line = reader.ReadLine().ToLower();
                            if (line.Contains("end modules dump") == true)
                            {
                                break;
                            }

                            // "0x12345678 - 0x87654321    ModuleName"
                            UInt64 baseAddress = System.UInt64.Parse(line.Substring(2, 8) /* skip "0x" */, System.Globalization.NumberStyles.AllowHexSpecifier);
                            UInt64 endAddress = System.UInt64.Parse(line.Substring(15, 8) /* skip "0x" */, System.Globalization.NumberStyles.AllowHexSpecifier);
                            string moduleName = line.Substring(27);
                            string pdbName = null;

                            foreach (string file in m_filesToProcess)
                            {
                                if (file.Contains(System.IO.Path.GetFileNameWithoutExtension(moduleName)) && (System.IO.File.Exists(file) == true))
                                {
                                    pdbName = file;
                                    break;
                                }
                            }
                            m_moduleInfo.Add(new ModuleInfo(baseAddress, endAddress, moduleName, pdbName));
                        }

                        // Search for mark point for stack dump
                        while (reader.EndOfStream == false)
                        {
                            string line = reader.ReadLine().ToLower();
                            if (line.Contains("start stack dump") == true)
                            {
                                break;
                            }
                        }

                        // Find and extend info
                        while (reader.EndOfStream == false)
                        {
                            string line = reader.ReadLine().ToLower();
                            if (line.Contains("end stack dump") == true)
                            {
                                break;
                            }

                            UInt64 address = System.UInt64.Parse(line.Substring(2, 8) /* skip "0x" */, System.Globalization.NumberStyles.AllowHexSpecifier);
                            bool found = false;
                            // Now try to match the address in a module
                            foreach (ModuleInfo moduleInfo in m_moduleInfo)
                            {
                                if (moduleInfo.Contains(address) == true)
                                {
                                    if (moduleInfo.PdbName == null)
                                    {
                                        // We have no more info for it, though we now where it came from
                                        writer.WriteLine(line + "  -  " + moduleInfo.ModuleName + " : ----------");
                                        found = true;
                                        break;
                                    }
                                    UInt64 moduleAddress = address - moduleInfo.BaseAddress;
                                    Dia2Lib.DiaSourceClass dia = new Dia2Lib.DiaSourceClass();
                                    dia.loadDataFromPdb(moduleInfo.PdbName);
                                    Dia2Lib.IDiaSession session;
                                    dia.openSession(out session);

                                    Dia2Lib.IDiaSymbol diaSymbol = null;
                                    session.findSymbolByRVA((UInt32)moduleAddress, Dia2Lib.SymTagEnum.SymTagNull, out diaSymbol);
                                    if (diaSymbol != null)
                                    {
                                        // Found!!
                                        if (moduleAddress == diaSymbol.relativeVirtualAddress)
                                        {
                                            string name = (diaSymbol.undecoratedName != null) ? diaSymbol.undecoratedName : diaSymbol.name;
                                            writer.WriteLine(line + "  -  " + moduleInfo.ModuleName + " : " + name);
                                        }
                                        else
                                        {
                                            // We have no direct info, what about its parent?
                                            diaSymbol = diaSymbol.lexicalParent;
                                            string name = (diaSymbol.undecoratedName != null) ? diaSymbol.undecoratedName : diaSymbol.name;
                                            writer.WriteLine(line + "  -  " + moduleInfo.ModuleName + " : [" + name + "]");
                                        }
                                        found = true;
                                        break;
                                    }
                                }
                            }
                            if (found == false)
                            {
                                // Not found?
                                writer.WriteLine(line + " : ----------");
                            }
                        }
                    }
                }
            }
        }

        private List<string> m_filesToProcess;
        private List<string> m_filesToAnalyze;
        private string m_outputFile;
        //                     pdb,            address, source
        private Dictionary< string, Dictionary< UInt64, string > > m_addressTable;
        private List<ModuleInfo> m_moduleInfo;
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Werner Willemsens
Team Leader
Belgium Belgium
No Biography provided

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.1411023.1 | Last Updated 21 Aug 2009
Article Copyright 2009 by Werner Willemsens
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid