Click here to Skip to main content
15,881,852 members
Articles / Mobile Apps / Windows Mobile

Post mortem C++ exception analysis in embedded applications

Rate me:
Please Sign up or sign in to vote.
4.96/5 (16 votes)
21 Aug 2009CPOL12 min read 54.1K   309   28  
An article on analysing a program exception or software crash.
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)


Written By
Team Leader
Belgium Belgium
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions