[Tool] Added option to directly enter the log string accepted/tizen/unified/20210407.010215 submit/tizen/20210406.101617
authorj-h.choi <j-h.choi@samsung.com>
Wed, 24 Feb 2021 07:07:54 +0000 (16:07 +0900)
committer조웅석/Common Platform Lab(SR)/Principal Engineer/삼성전자 <ws77.cho@samsung.com>
Tue, 6 Apr 2021 00:07:05 +0000 (09:07 +0900)
Change-Id: I7d73d17dfd7eb283675d639b7079e5d685d86196

tools/Extractor/README.md
tools/Extractor/dotnet-extractor/dotnet-extractor/CodeBlock.cs
tools/Extractor/dotnet-extractor/dotnet-extractor/Extractor.cs
tools/Extractor/dotnet-extractor/dotnet-extractor/LineNumber.cs

index 360656d..b777807 100644 (file)
@@ -3,50 +3,70 @@
 ### Usage
 
 ```
-dotnet-extractor line-number [Log] [Options]
+dotnet-extractor [Commands]
 ```
 
-#### Log
-* Filepath
-   Path to the exception log file (Filename extension: xxxxx.log)
+```
+dotnet-extractor convert [Options]
+```
+
+#### Commands
+* convert  
+   Get the line number from the token value in the stacktrace
+
+#### Interactive shell
+* Input string  
+   Input the exception log string directly
 
 #### Options
 * -h, --help  
     Show this help message
 
+* -i, --input  [Input path]  
+   Path to the exception log file (File extension: xxxxx.log)
+
 * -a, --assembly  [Path1:Path2:...]  
     Multiple paths with assembly directories separated by colon(':')
 
 * -p, --pdb  [Pdb path]  
     Path to the pdb directory (Can be omitted if it is the same as the assembly directory path)
 
-* -o, --out  [Output path]  
+* -o, --output  [Output path]  
     Path to the output file (Default: Output to console. If omitted, the xxxxx.out file is created in the same location as the log file)
    
 #### Example
+* If you enter the exception log string directly
+```
+ # dotnet extractor convert
+ ### Dotnet Extractor Tool (v1.0) ###
+ Enter the exception log string:
+  I/DOTNET_LAUNCHER(12345):    at TestApp.Program.TestMethod1() in TestApp.Tizen.dll: token 0x6000001+0x5
+  I/DOTNET_LAUNCHER(12345):    at TestApp.Program.OnCreate() in TestApp.Tizen.dll: token 0x6000002+0x1
+```
+
 * If both assembly and pdb are in the current directory
 ```
- # dotnet extractor line-number /tmp/Exception1.log
+ # dotnet extractor convert --input /tmp/Exception1.log
 ```
 
 * If both assembly and pdb are in the same directory specified
 ```
- # dotnet extractor /tmp/Exception2.log --assembly /opt/usr/globalapps/org.tizen.example.TestApp/:/usr/share/dotnet.tizen/
+ # dotnet extractor convert --input /tmp/Exception2.log --assembly /opt/usr/globalapps/org.tizen.example.TestApp.Tizen/:/usr/share/dotnet.tizen/
 ```
 
 * If assembly and pdb are separated in each directory
 ```
- # dotnet extractor /tmp/Exception3.log --assembly /usr/share/dotnet.tizen/framework/ --pdb /tmp/pdbs/
+ # dotnet extractor convert --input /tmp/Exception3.log --assembly /usr/share/dotnet.tizen/framework/ --pdb /tmp/pdbs/
 ```
 
 #### Others
 * Log format
 ```
- I/DOTNET_LAUNCHER(27298): System.NullReferenceException: Object reference not set to an instance of an object.
- I/DOTNET_LAUNCHER(27298):    at TestApp.Program.TestMethod() in TestApp.dll: method_token(0x6000001), il_offset(0x5)
- I/DOTNET_LAUNCHER(27298):    at TestApp.Program.OnCreate() in TestApp.dll: method_token(0x6000002), il_offset(0x1)
+ I/DOTNET_LAUNCHER(12345): System.NullReferenceException: Object reference not set to an instance of an object.
+ I/DOTNET_LAUNCHER(12345):    at TestApp.Program.TestMethod1() in TestApp.Tizen.dll: token 0x6000001+0x5
+ I/DOTNET_LAUNCHER(12345):    at TestApp.Program.OnCreate() in TestApp.Tizen.dll: token 0x6000002+0x1
   ------- Format -------
- I/DOTNET_LAUNCHER(00000):    at {typeName}.{methodName}() in {moduleName}: method_token{methodToken}, il_offset{ilOffset}
+ I/DOTNET_LAUNCHER(00000):    at {typeName}.{methodName}({parameters}) in {moduleName}: token {methodToken}+{ilOffset}
 ```
 
 ----
@@ -54,19 +74,19 @@ dotnet-extractor line-number [Log] [Options]
 #### Sample
 ```
 sh-3.2# cat /tmp/Exception.log 
-I/DOTNET_LAUNCHER(27298): System.NullReferenceException: Object reference not set to an instance of an object.
-I/DOTNET_LAUNCHER(27298):    at LineNumberExtract.Program.ExceptionMethod2() in LineNumberExtract.Tizen.dll: method_token(0x6000001), il_offset(0x5)
-I/DOTNET_LAUNCHER(27298):    at LineNumberExtract.Program.ExceptionMethod1() in LineNumberExtract.Tizen.dll: method_token(0x6000002), il_offset(0x1)
-I/DOTNET_LAUNCHER(27298):    at LineNumberExtract.Program.OnCreate() in LineNumberExtract.Tizen.dll: method_token(0x6000004), il_offset(0x15)
+I/DOTNET_LAUNCHER(12345): System.NullReferenceException: Object reference not set to an instance of an object.
+I/DOTNET_LAUNCHER(12345):    at TestApp.Program.TestMethod1() in TestApp.Tizen.dll: token 0x6000001+0x5
+I/DOTNET_LAUNCHER(12345):    at TestApp.Program.TestMethod2() in TestApp.Tizen.dll: token 0x6000002+0x1
+I/DOTNET_LAUNCHER(12345):    at TestApp.Program.OnCreate() in TestApp.Tizen.dll: token 0x6000004+0x15
 sh-3.2# 
-sh-3.2# dotnet eExtractor /tmp/Exception.log --assembly /opt/usr/globalapps/org.tizen.example.LineNumberExtract.Tizen/
+sh-3.2# dotnet extractor convert --input /tmp/Exception.log --assembly /opt/usr/globalapps/org.tizen.example.TestApp.Tizen/
 
 ##### Line Number Extractor Tool (v1.0) #####
 
 Extraction result:      
- at LineNumberExtract.Program.ExceptionMethod2(i) in U:\PTX\LineNumberExtract\LineNumberExtract\LineNumberExtract.Tizen\LineNumberExtract.Tizen.cs:line 14
- at LineNumberExtract.Program.ExceptionMethod1(t) in U:\PTX\LineNumberExtract\LineNumberExtract\LineNumberExtract.Tizen\LineNumberExtract.Tizen.cs:line 19
- at LineNumberExtract.Program.OnCreate() in U:\PTX\LineNumberExtract\LineNumberExtract\LineNumberExtract.Tizen\LineNumberExtract.Tizen.cs:line 58
+ at TestApp.Program.TestMethod1() in U:\TestApp\TestApp\TestApp.Tizen\TestApp.Tizen.cs:line 14
+ at TestApp.Program.TestMethod2() in U:\TestApp\TestApp\TestApp.Tizen\TestApp.Tizen.cs:line 19
+ at TestApp.Program.OnCreate() in U:\TestApp\TestApp\TestApp.Tizen\TestApp.Tizen.cs:line 58
 
 Output: /tmp/Exception.out
 
index d4e7db5..26c91a7 100644 (file)
@@ -1,7 +1,4 @@
 using System;\r
-using System.IO;\r
-using System.Text;\r
-using System.Xml;\r
 \r
 namespace Tizen.Runtime.Tools\r
 {\r
@@ -13,7 +10,7 @@ namespace Tizen.Runtime.Tools
 \r
         public void CodeBlocks()\r
         {\r
-            Console.WriteLine("Not implemented yet");\r
+            Console.WriteLine("Not implemented yet\n");\r
         }\r
     }\r
 }
\ No newline at end of file
index b13e0ce..757b1b8 100644 (file)
@@ -23,7 +23,7 @@ namespace Tizen.Runtime.Tools
                             UsageCommand();\r
                             Environment.Exit(0);\r
                             break;\r
-                        case "line-number":\r
+                        case "convert":\r
                             command = "line";\r
                             break;\r
                         case "code-block":\r
@@ -47,7 +47,7 @@ namespace Tizen.Runtime.Tools
                 }\r
                 else if (command == "code")\r
                 {\r
-                    //new CodeBlock().CodeBlocks();\r
+                    new CodeBlock().CodeBlocks();\r
                 }\r
             }\r
             catch (Exception e)\r
@@ -60,7 +60,7 @@ namespace Tizen.Runtime.Tools
         {\r
             string UsageMsg = "Usage: dotnet-extractor [Command]\n\n"\r
                               + "Commands:\n"\r
-                              + " line-number           Get line number\n";\r
+                              + " convert               Get the line number from the token value in the stacktrace\n";\r
                               //+ " code-block            Get code block\n";\r
             Console.WriteLine(UsageMsg);\r
         }\r
index 792792a..085d960 100644 (file)
@@ -1,6 +1,7 @@
 using Microsoft.DiaSymReader.Tools;\r
 using System;\r
 using System.Collections.Generic;\r
+using System.Globalization;\r
 using System.IO;\r
 using System.Text;\r
 using System.Text.RegularExpressions;\r
@@ -12,44 +13,47 @@ namespace Tizen.Runtime.Tools
     {\r
         private static readonly string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());\r
 \r
-        public LineNumber()\r
-        {\r
-        }\r
-\r
         internal sealed class Args\r
         {\r
             public readonly string[] AssemblyPaths;\r
             public readonly string[] PdbPaths;\r
             public readonly string ExceptionPath;\r
+            public readonly List<string> ExceptionString;\r
             public readonly string OutputPath;\r
 \r
-            public Args(string[] assemblyPaths, string[] pdbPaths, string exceptionPath, string outputPath)\r
+            public Args(string[] assemblyPaths, string[] pdbPaths, string exceptionPath, List<string> exceptionString, string outputPath)\r
             {\r
                 AssemblyPaths = assemblyPaths;\r
                 PdbPaths = pdbPaths;\r
                 ExceptionPath = exceptionPath;\r
+                ExceptionString = exceptionString;\r
                 OutputPath = outputPath;\r
             }\r
         }\r
 \r
         public static void UsageLine()\r
         {\r
-            string UsageMsg = "Usage: dotnet-extractor line-number [Log] [Options]\n\n"\r
-                              + "Log:\n"\r
-                              + "<Filepath>                             Path to the exception log file (Filename extension: xxxxx.log)\n\n"\r
-                              //+ "<String>                               Input the log message directly\n\n"\r
+            string UsageMsg = "Usage: dotnet-extractor convert [Options]\n\n"\r
+                              + "Interactive shell:\n"\r
+                              + "<Input string>                         Input the exception log string directly\n\n"\r
                               + "Options:\n"\r
                               + " -h, --help                            Show this help message\n"\r
+                              + " -i, --input <Input path>              Path to the exception log file (File extension: xxxxx.log)\n"\r
                               + " -a, --assembly <Path1:Path2:...>      Multiple paths with assembly directories separated by colon(':')\n"\r
                               + " -p, --pdb <Pdb path>                  Path to the pdb directory (Can be omitted if it is the same as the assembly directory path)\n"\r
-                              + " -o, --out <Output path>               Path to the output file (Default: Output to console. If omitted, the xxxxx.out file is created in the same location as the log file)\n\n"\r
+                              + " -o, --output <Output path>            Path to the output file (Default: Output to console. If omitted, the xxxxx.out file is created in the same location as the log file)\n\n"\r
                               + "Example:\n"\r
-                              + "1. If both assembly and pdb are in the current directory\n"\r
-                              + " # dotnet extractor line-number /tmp/Exception1.log\n"\r
-                              + "2. If both assembly and pdb are in the same directory specified\n"\r
-                              + " # dotnet extractor line-number /tmp/Exception2.log --assembly /opt/usr/globalapps/org.tizen.example.TestApp/:/usr/share/dotnet.tizen/\n"\r
-                              + "3. If assembly and pdb are separated in each directory\n"\r
-                              + " # dotnet extractor line-number /tmp/Exception3.log --assembly /usr/share/dotnet.tizen/framework/ --pdb /tmp/pdbs/\n";\r
+                              + "1. If you enter the exception log string directly\n"\r
+                              + " # dotnet extractor convert\n"\r
+                              + "  Enter the exception log string:\n"\r
+                              + "   I/DOTNET_LAUNCHER(12345):    at TestApp.Program.TestMethod() in TestApp.Tizen.dll: token 0x6000001+0x5\n"\r
+                              + "   I/DOTNET_LAUNCHER(12345):    at TestApp.Program.OnCreate() in TestApp.Tizen.dll: token 0x6000002+0x1\n\n"\r
+                              + "2. If both assembly and pdb are in the current directory\n"\r
+                              + " # dotnet extractor convert --input /tmp/Exception1.log\n\n"\r
+                              + "3. If both assembly and pdb are in the same directory specified\n"\r
+                              + " # dotnet extractor convert --input /tmp/Exception2.log --assembly /opt/usr/globalapps/org.tizen.example.TestApp.Tizen/:/usr/share/dotnet.tizen/\n\n"\r
+                              + "4. If assembly and pdb are separated in each directory\n"\r
+                              + " # dotnet extractor convert --input /tmp/Exception3.log --assembly /usr/share/dotnet.tizen/framework/ --pdb /tmp/pdbs/\n";\r
             Console.WriteLine(UsageMsg);\r
         }\r
 \r
@@ -72,6 +76,7 @@ namespace Tizen.Runtime.Tools
             string[] assemblyPaths = null;\r
             string[] pdbPaths = null;\r
             string exceptionPath = null;\r
+            List<string> exceptionString = new List<string>();\r
             string outputPath = null;\r
 \r
             int i = 1;\r
@@ -86,38 +91,56 @@ namespace Tizen.Runtime.Tools
                         UsageLine();\r
                         Environment.Exit(0);\r
                         break;\r
+                    case "-i":\r
+                    case "--input":\r
+                        exceptionPath = ReadValue();\r
+                        break;\r
+                    case "-a":\r
+                    case "--assembly":\r
+                        assemblyPaths = ReadValue().Split(":");\r
+                        break;\r
                     case "-p":\r
                     case "--pdb":\r
                         pdbPaths = ReadValue().Split(":");\r
                         break;\r
                     case "-o":\r
-                    case "--out":\r
+                    case "--output":\r
                         outputPath = ReadValue();\r
                         break;\r
-                    case "-a":\r
-                    case "--assembly":\r
-                        assemblyPaths = ReadValue().Split(":");\r
-                        break;\r
                     default:\r
-                        if (arg.Contains("-"))\r
-                        {\r
-                            UsageLine();\r
-                            Console.WriteLine($"Unknown option [{arg}]\n");\r
-                            Environment.Exit(0);\r
-                            break;\r
-                        }\r
-                        exceptionPath ??= arg;\r
-                        if (!File.Exists(exceptionPath))\r
-                        {\r
-                            throw new FileNotFoundException("Log file not found\n");\r
-                        }\r
+                        UsageLine();\r
+                        Console.WriteLine($"Unknown option [{arg}]\n");\r
+                        Environment.Exit(0);\r
                         break;\r
                 }\r
             }\r
             if (exceptionPath == null)\r
             {\r
-                throw new InvalidDataException("Missing exception log path\n");\r
+                Console.WriteLine("Enter the exception log string:");\r
+                string line;\r
+                while ((line = Console.ReadLine()) != null && line != "")\r
+                {\r
+                    if (!line.Contains(":"))\r
+                    {\r
+                        exceptionPath = line;\r
+                        exceptionString.Clear();\r
+                        break;\r
+                    }\r
+                    exceptionString.Add(line);\r
+                }\r
+            }\r
+            if (exceptionString.Count == 0)\r
+            {\r
+                if (exceptionPath == null)\r
+                {\r
+                    throw new InvalidDataException("Missing exception log path or log string\n");\r
+                }\r
+                else if (!File.Exists(exceptionPath))\r
+                {\r
+                    throw new FileNotFoundException("Exception log file not found\n");\r
+                }\r
             }\r
+\r
             assemblyPaths ??= new string[] { Directory.GetCurrentDirectory() };\r
             pdbPaths ??= assemblyPaths;\r
             try\r
@@ -133,6 +156,7 @@ namespace Tizen.Runtime.Tools
                 assemblyPaths: assemblyPaths,\r
                 pdbPaths: pdbPaths,\r
                 exceptionPath: exceptionPath,\r
+                exceptionString: exceptionString,\r
                 outputPath: outputPath);\r
         }\r
 \r
@@ -181,12 +205,8 @@ namespace Tizen.Runtime.Tools
                 {\r
                     if (Path.GetFileNameWithoutExtension(peFile) == Path.GetFileNameWithoutExtension(pdbFile))\r
                     {\r
-                        string xmlPath = Path.ChangeExtension(peFile, "xml");\r
-                        if (xmlPath.Contains("/usr/share/dotnet"))\r
-                        {\r
-                            xmlPath = tempDirectory + "/" + Path.GetFileName(xmlPath);\r
-                        }\r
-                        GetXmlFromPdb(peFile, pdbFile, xmlPath);\r
+                        string xmlPath = Path.Combine(tempDirectory, Path.GetFileName(Path.ChangeExtension(peFile, "xml")));\r
+                        GenXmlFromPdb(peFile, pdbFile, xmlPath);\r
                         xmlList.Add(xmlPath);\r
                         break;\r
                     }\r
@@ -195,7 +215,7 @@ namespace Tizen.Runtime.Tools
             return xmlList;\r
         }\r
 \r
-        private static void GetXmlFromPdb(string assemblyPath, string pdbPath, string xmlPath)\r
+        private static void GenXmlFromPdb(string assemblyPath, string pdbPath, string xmlPath)\r
         {\r
             using var peStream = new FileStream(assemblyPath, FileMode.Open, FileAccess.Read);\r
             using var pdbStream = new FileStream(pdbPath, FileMode.Open, FileAccess.Read);\r
@@ -206,25 +226,28 @@ namespace Tizen.Runtime.Tools
             PdbToXmlConverter.ToXml(sw, pdbStream, peStream, options);\r
         }\r
 \r
+        private static void RemoveTempDirectory()\r
+        {\r
+            if (Directory.Exists(tempDirectory))\r
+            {\r
+                Directory.Delete(tempDirectory, true);\r
+            }\r
+        }\r
+\r
         /*\r
          * Extract\r
          */\r
         private static void Extract(Args args, List<string> xmlList)\r
         {\r
-            string logFile = args.ExceptionPath;\r
-            string outputPath = args.OutputPath;\r
-\r
             if (xmlList.Count == 0)\r
             {\r
+                RemoveTempDirectory();\r
                 throw new FileNotFoundException("Xml file not found\n");\r
             }\r
 \r
-            GetLineFromLog(logFile, xmlList, outputPath);\r
+            GetLineFromLog(args, xmlList);\r
 \r
-            if (Directory.Exists(tempDirectory))\r
-            {\r
-                Directory.Delete(tempDirectory, true);\r
-            }\r
+            RemoveTempDirectory();\r
         }\r
 \r
         internal sealed class StackTraceInfo\r
@@ -242,58 +265,93 @@ namespace Tizen.Runtime.Tools
             public string EndLine;\r
         }\r
 \r
-        private static void GetLineFromLog(string logPath, List<string> xmlList, string outputPath)\r
+        private static string GetRegex(string line, List<string> xmlList)\r
         {\r
-            Console.WriteLine("Extraction result:      ");\r
-            try\r
+            string ret = line;\r
+            string logtagStr = Regex.Match(line, "(?<splitdata>.*?) at").Groups["splitdata"].Value;\r
+            if (logtagStr.Length != 0)\r
             {\r
-                using StreamReader fsr = new StreamReader(new FileStream(logPath, FileMode.Open, FileAccess.Read));\r
-                using StreamWriter fsw = new StreamWriter(new FileStream(outputPath, FileMode.Create, FileAccess.Write));\r
+                ret = line.Replace(logtagStr, "");\r
+            }\r
+            string typeMethodStr = Regex.Match(line, "at (?<splitdata>.*?)\\((.*)\\)").Groups["splitdata"].Value;\r
+            string methodStr = typeMethodStr.Split(".")[^1];\r
+            string typenameStr = typeMethodStr.Replace("." + methodStr, "");\r
+            string parameterStr = Regex.Match(line, methodStr + "\\((?<splitdata>.*?)\\)").Groups["splitdata"].Value;\r
+            string assemblyStr = Regex.Match(line, " in (?<splitdata>.*?)\\: ").Groups["splitdata"].Value;\r
+            string[] tokenOffsetStr = Regex.Match(line, "\\: token (?<splitdata>.*)?").Groups["splitdata"].Value.Split("+");\r
+            string xmlStr = assemblyStr.Contains(".ni.dll") ? assemblyStr.Replace(".ni.dll", ".xml") : assemblyStr.Replace(".dll", ".xml");\r
 \r
-                bool isParsed = false;\r
-                while (!fsr.EndOfStream)\r
+            if (tokenOffsetStr.Length != 2 || methodStr == "" || typenameStr == "" || assemblyStr == "")\r
+            {\r
+                return ret;\r
+            }\r
+\r
+            StackTraceInfo stInfo = new StackTraceInfo() { Type = typenameStr, Method = methodStr, Assembly = assemblyStr, Token = tokenOffsetStr[0], Offset = tokenOffsetStr[1] };\r
+\r
+            foreach (var xmlPath in xmlList)\r
+            {\r
+                if (xmlPath.Contains(xmlStr))\r
                 {\r
-                    string line = fsr.ReadLine();\r
-                    if (!line.Contains(" at "))\r
+                    GetLineFromXml(xmlPath, stInfo);\r
+                    if (stInfo.Filepath != null && stInfo.StartLine != null)\r
                     {\r
-                        continue;\r
+                        ret = $" at {stInfo.Type}.{stInfo.Method}({parameterStr}) in {stInfo.Filepath}:line {stInfo.StartLine}";\r
+                        break;\r
                     }\r
-                    string typeMethodStr = Regex.Match(line, " at (?<splitdata>.*?)\\(\\)").Groups["splitdata"].Value;\r
-                    string methodStr = typeMethodStr.Split(".")[^1];\r
-                    string typenameStr = typeMethodStr.Replace("." + methodStr, "");\r
-                    string assemblyStr = Regex.Match(line, " in (?<splitdata>.*?)\\: ").Groups["splitdata"].Value;\r
-                    string tokenStr = Regex.Match(line, " method_token\\((?<splitdata>.*?)\\)\\,").Groups["splitdata"].Value;\r
-                    string offsetStr = Regex.Match(line, " il_offset\\((?<splitdata>.*?)\\)").Groups["splitdata"].Value;\r
-                    string xmlStr = assemblyStr.Replace(".dll", ".xml");\r
+                }\r
+            }\r
+            return ret;\r
+        }\r
 \r
-                    StackTraceInfo stInfo = new StackTraceInfo() { Type = typenameStr, Method = methodStr, Assembly = assemblyStr, Token = tokenStr, Offset = offsetStr/*, Xml = xmlStr*/ };\r
+        private static void GetLineFromLog(Args args, List<string> xmlList)\r
+        {\r
+            Console.WriteLine("Extraction result:      ");\r
 \r
-                    foreach (var xmlPath in xmlList)\r
+            try\r
+            {\r
+                List<string> result = new List<string>();\r
+                if (args.ExceptionPath == null)\r
+                {\r
+                    // <Exception String>\r
+                    foreach (var line in args.ExceptionString)\r
                     {\r
-                        if (xmlPath.Contains(xmlStr))\r
+                        if (!line.Contains("at "))\r
                         {\r
-                            isParsed = true;\r
-                            GetLineFromXml(xmlPath, stInfo);\r
-                            if (stInfo.Filepath == null || stInfo.StartLine == null)\r
-                            {\r
-                                Console.WriteLine("    ===== PARSE ERROR FOR EXCEPTION LOG IN THIS LINE. PLEASE RECHECK THE EXCEPTION LOG =====");\r
-                                break;\r
-                            }\r
-                            string ret = $" at {stInfo.Type}.{stInfo.Method}({stInfo.Param}) in {stInfo.Filepath}:line {stInfo.StartLine}";\r
-                            fsw.WriteLine(ret);\r
-                            Console.WriteLine(ret);\r
+                            continue;\r
                         }\r
+                        string ret = GetRegex(line, xmlList);\r
+                        result.Add(ret);\r
+                        Console.WriteLine(ret);\r
                     }\r
                 }\r
-                if (!isParsed)\r
+                else\r
                 {\r
-                    Console.WriteLine(" There is no content matching the exception log.");\r
-                    Console.WriteLine(" Please recheck the assembly and pdb directory path.\n");\r
+                    // <Exception Path>\r
+                    using StreamReader fsr = new StreamReader(new FileStream(args.ExceptionPath, FileMode.Open, FileAccess.Read));\r
+                    while (!fsr.EndOfStream)\r
+                    {\r
+                        string line = fsr.ReadLine();\r
+                        if (!line.Contains(" at "))\r
+                        {\r
+                            continue;\r
+                        }\r
+                        string ret = GetRegex(line, xmlList);\r
+                        result.Add(ret);\r
+                        Console.WriteLine(ret);\r
+                    }\r
                 }\r
-                else\r
+\r
+                string output = string.Empty;\r
+                if (args.OutputPath != null)\r
                 {\r
-                    Console.WriteLine($"\nOutput: {outputPath}\n");\r
+                    using StreamWriter fsw = new StreamWriter(new FileStream(args.OutputPath, FileMode.Create, FileAccess.Write));\r
+                    foreach (var ret in result)\r
+                    {\r
+                        fsw.WriteLine(ret);\r
+                    }\r
+                    output = $"\nOutput: {args.OutputPath}\n";\r
                 }\r
+                Console.WriteLine($"{output}");\r
             }\r
             catch (Exception e)\r
             {\r
@@ -393,25 +451,40 @@ namespace Tizen.Runtime.Tools
             }\r
         }\r
 \r
+        private static int HexToInt(string value)\r
+        {\r
+            // strip the leading 0x\r
+            if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase))\r
+            {\r
+                value = value.Substring(2);\r
+            }\r
+            return Int32.Parse(value, NumberStyles.HexNumber);\r
+        }\r
+\r
         private static void ParseEntry(XmlNodeList xn, StackTraceInfo stInfo)\r
         {\r
             try\r
             {\r
+                XmlNode bestPointSoFar = null;\r
+                int ilOffset = HexToInt(stInfo.Offset);\r
                 foreach (XmlNode node in xn)\r
                 {\r
-                    if (stInfo.Offset == node.Attributes["offset"].Value)\r
+                    // If the attribute is not 'startLine', but 'hidden', select the best value so far\r
+                    if (HexToInt(node.Attributes["offset"].Value) > ilOffset)\r
                     {\r
-                        if (node.Attributes.Item(1).Name == "startLine")\r
-                        {\r
-                            stInfo.StartLine = node.Attributes["startLine"].Value;\r
-                        }\r
-                        if (node.Attributes.Item(3).Name == "endLine")\r
-                        {\r
-                            stInfo.EndLine = node.Attributes["endLine"].Value;\r
-                        }\r
-                        stInfo.Document = node.Attributes["document"].Value;\r
+                        break;\r
+                    }\r
+                    if (node.Attributes["startLine"] != null)\r
+                    {\r
+                        bestPointSoFar = node;\r
                     }\r
                 }\r
+                if (bestPointSoFar != null)\r
+                {\r
+                    stInfo.StartLine = bestPointSoFar.Attributes["startLine"].Value;\r
+                    stInfo.EndLine = bestPointSoFar.Attributes["endLine"].Value;\r
+                    stInfo.Document = bestPointSoFar.Attributes["document"].Value;\r
+                }\r
             }\r
             catch (ArgumentException e)\r
             {\r