Microsoft Diagnostics Runtime crash.dmp analysis (C#) - c#

I'm trying to read in a crash.dmp using the functionality in Microsoft.Diagnostics.Runtime .NET componenet (also known as ClrMD).
I have a crash.dmp in a known location (in a string called pathToFile) so that's not the issue. The rest of the code looks like this.
DataTarget dataTarget = DataTarget.LoadCrashDump(pathToFile);
ClrInfo clrInfo = dataTarget.ClrVersions[0];
string dacLocation = clrInfo.TryGetDacLocation();
When testing this code, I get the following error in the command window:
Error processing directory: System.ArgumentOutOfRangeException. Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index.
I'm assuming it's something to do with the ClrVersions[0] bit but can't for the life of me pin it down.
Any help would be appreciated.
Current Status
When running the following command (which fails)
ClrRuntime rt = dataTarget.CreateRuntime("path\to\mscordawks.dll");
I receive the following error in cmd
mismatched architecture between this process and the dac
Cheers
Anyone?

If the TryGetDacLocation succeeded then you should be able to do
ClrRuntime rt = dataTarget.CreateRuntime(dacLocation);
so you get the correct dacLocation.
Was the dump you are analysing generated on same machine where you are analysing it?
Also what are the bitnesses of the process the dump was generated from, the process in which the CLRMD code is running and the debugger utility used to generate the dump?
Generally you want to be matching the bitnesses all round (x86/x64).
Doug

I was having the same issue reading a dump file generated on the same computer. There were two problems, first bitness (should have been 64, was running in 32) and the second harder problem that the proper DLL could not be located. To fix the second problem I created a method that tries all of the properly named DLLs it can find:
private static ClrRuntime GetRuntime(DataTarget target)
{
ClrInfo version = target.ClrVersions[0];
string dacLocation = version.TryGetDacLocation();
// If we don't have the dac installed, we will use the long-name dac in the same folder.
if (!string.IsNullOrEmpty(dacLocation))
dacLocation = version.DacInfo.FileName;
try // try the one it should be
{
return target.CreateRuntime(dacLocation);
}
catch (Exception e)
{
}
// can't find the one it should be, try'em all
string fileName = "mscordacwks.dll";
string[] searchLocations = new[]
{
#"C:\Windows\Microsoft.NET\",
#"C:\Windows\winsxs\"
};
foreach (string searchLocation in searchLocations)
{
foreach (string file in Directory.GetFiles(searchLocation, fileName, SearchOption.AllDirectories))
{
try
{
return target.CreateRuntime(file);
}
catch (Exception e)
{
}
}
}
throw new Exception("No found valid runtimes");
}

I followed this artificial to get the mscordacwks.dll when dealing with platform differences between where the dmp file was taken and the machine doing the analysis.
http://chentiangemalc.wordpress.com/2014/04/16/obtaining-correct-mscordacwks-dll-for-net-windbging/#comment-3380
and followed the steps including renaming the file to include the architecture and version information.
After that I just http://chentiangemalc.wordpress.com/2014/04/16/obtaining-correct-mscordacwks-dll-for-net-windbging/#comment-3380ut the full path of the file as dacLocation in the script.
After that it worked!
I suspect that putting it on the path could be made to work.

Related

Directory exists is producing inconsistant results on desktop vs server

I have a C# program which checks if a specific directory exists.
It is simply doing:
Directory.Exists(path).
I tried other ways as well. Using DirectoryInfo and using AlphaFS
On my local machine, the path exists. When I run the same program on a server with the same credentials it doesn't exist.
I wonder if it is a group policy issue. But I am able to go up one level and see it.
\server\volume\share\sub directory - Doesn't exist remotely but on my desktop it does
\server\volume\share - Does exist both on my desktop and remote server
Update
I forgot to mention, that since I had access to my desktop, I got the ACL information.
None of the groups were able to translate.
I really just want to get this application to behave the same way is on the server and find out why it is behaving differently.
Update 2
These are physical servers.
My desktop is Liquid VDI
Below is the code:
var path = txtPath.Text;
using (var user = new Impersonation(fuserdomain, fc_user, fc_pass))
{
var alphaExists = Alphaleonis.Win32.Filesystem.Directory.Exists(path);
var alphaDIExists = new Alphaleonis.Win32.Filesystem.DirectoryInfo(path).Exists;
var SystemExists = System.IO.Directory.Exists(path);
var SystemDIExists = new System.IO.DirectoryInfo(path).Exists;
var AlphaHasFiles = false;
var AlphaDIHasFiles = false;
var SystemHasFiles = false;
var SystemDIHasFiles = false;
try
{
Directory.GetFiles(path);
AlphaHasFiles = true;
}
catch { }
try
{
new DirectoryInfo(path).GetFiles();
AlphaDIHasFiles = true;
}
catch { }
try
{
System.IO.Directory.GetFiles(path);
SystemHasFiles = true;
}
catch { }
try
{
new System.IO.DirectoryInfo(path).GetFiles();
SystemDIHasFiles = true;
}
catch { }
MessageBox.Show(string.Format("alphaExists: {0}\nalphaDIExists: {1}\nSystemExists: {2}\nSystemDIExists: {3}\nAlphaGetFiles: {4}\nAlphaDIGetFiles: {5}\nSystemGetFiles: {6}\nSystemDIGetFiles: {7}\n", alphaExists, alphaDIExists, SystemExists, SystemDIExists, AlphaHasFiles, AlphaDIHasFiles, SystemHasFiles, SystemDIHasFiles));
}
Update 3
Although I have workaround this issue; I am still not sure why I would have a difference between my desktop and server. Is there any tool that can help me see where the issue may be?
I've seen the same thing with File.Exists. I never found an answer and finally threw in the towel, I simply try to use it and catch the exception.
Robust code has to catch it anyway, all the test does is avoid trying if the file or directory is not there. (And the PITA that Visual Studio no longer as any way to ignore an exception on a certain line. No problem runtime, annoying in development.)
This is a complete shot in the dark, since we don't have any specific details to go on. e.g. Is the server you're talking about physically yours, or is it a cloud-based server service?
I'd guess that your machine is an older operating system than the server, and the folder that you're trying to access is one of those special folders that has become more locked down with more recent operating systems (particularly on server operating systems) like the "Program Files" folder. So even though the folder exists on both, the method works on your machine but not on the server, due to permissions.
Hope this helps.
As far as I can tell, the Impersonation class in your code is not part of the dot net framework. Googling finds a couple of implementations. Where does it come from and How confident are you that it actually works in your scenario?
For example, if you remove the Impersonation code, and actually run it as that user, does that make it work?
One other clarification... When you say
\server\volume\share
Do you mean this is a network location (e.g. a UNC location), so is the same network path you are trying to access from both machines? If so, this would open up new possibilities for problems like firewalls, etc... Is that location on either of the two machines that we know about from the question, or a different location?

Exception related to relative paths

I am working on a C# sharp console application. I ran into the following error related to relative paths tried changing the debug settings from anyCPU to x86 as well, but that didn't work. Can someone point me in the right direction. Thanks
public static void ReadOrders(string pOrderDirectory)
{
// This exception is already thrown by <code>Directory.GetFiles()</code> but caught earlier here to allow
// the option of throwing an app-specific exception
if (!Directory.Exists(pOrderDirectory))
{
throw new DirectoryNotFoundException("Unable to find input directory for orders: " + pOrderDirectory); //ran into the exception here.
}
// Process the list of files found in the directory.
string[] oOrderFilenames = Directory.GetFiles(pOrderDirectory, SalesTaxHelper.GetConfigurationValue(CONFIG_KEY_FILE_SEARCH_PATTERN));
if (oOrderFilenames.Length < 1)
{
throw new IOException("No orders found in input directory");
}
foreach (var oOrderFile in oOrderFilenames)
{
var oOrderProcessor = new Order();
var oOrderLineItems = File.ReadAllLines(oOrderFile);
foreach (var oLineItem in oOrderLineItems)
{
oOrderProcessor.AddLineItem(oLineItem);
}
Console.WriteLine(oOrderProcessor.PrintInvoice());
}
Console.WriteLine("======================================");
Console.WriteLine("PROCESSED ALL INPUT FILES IN DIRECTORY");
}
Exception: Unable to find input directory for orders:
Thanks,
Hari
Okay so make sure your folder named exactly input is placed in the bin > Debug folder of your project and if you set
pOrderDirectory = "input"
it should find the folder. The reason it will find the folder is because you're building in Debug mode so when you specify a path with just a simple string like I did it will be the default location where it will go search for the folder.
Note that it won't find your folder if you change to Release because your folder is in Debug.

Cannot create DICOMDIR file using GDCM library

I am using GDCM library to create a DICOMDIR file. I implemented the code as shown in GDCM docs:
http://gdcm.sourceforge.net/html/GenerateDICOMDIR_8cs-example.html
In the code:
private int GenerateDicomDir(string directory, string outFileName)
{
gdcm.Directory d = new gdcm.Directory();
uint nfiles = d.Load(directory, true);
if (nfiles == 0) return 1;
string descriptor = "Descriptor";
FilenamesType filenames = d.GetFilenames();
gdcm.Trace.DebugOn();
gdcm.DICOMDIRGenerator gen = new DICOMDIRGenerator();
gen.SetFilenames(filenames);
gen.SetDescriptor(descriptor);
if (!gen.Generate())
{
return 1;
}
gdcm.FileMetaInformation.SetSourceApplicationEntityTitle("GenerateDICOMDIR");
gdcm.Writer writer = new Writer();
writer.SetFile(gen.GetFile());
writer.SetFileName(outFileName);
if (!writer.Write())
{
return 1;
}
return 0;
}
The function returns and does not generate a DICOMDIR file. I have added trace debug on but still cannot debug or get any output message.
Is there any way to generate DICOMDIR file for bunch of DICOM files ?
As per the documentation, did you made sure that:
Warning: : PS 3.11 - 2008 / D.3.1 SOP Classes and Transfer Syntaxes
Composite Image & Stand-alone Storage are required to be stored as
Explicit VR Little Endian Uncompressed (1.2.840.10008.1.2.1). When a
DICOM file is found using another Transfer Syntax the generator will
simply stops. Input files should be Explicit VR Little Endian
filenames should be valid VR::CS value (16 bytes, upper case ...)
If you turn verbose debugging you could log the exact error message, see gdcm::Trace for usage.
As per the documentation of gdcm::Trace, you need to pay attention to the following:
Warning: All string messages are removed during compilation time when
compiled with CMAKE_BUILD_TYPE being set to either: Release MinSizeRel
It is recommended to compile with RelWithDebInfo and/or Debug during
prototyping of applications.
You could also use gdcm::Trace::SetStreamToFile, to properly redirect any messages to a file (instead of stdout by default).
Since you use the recursion option of gdcm.Directory, you need to also pay attention that sub-directory name are valid (VR::CS, 16bytes, upper case...).
See also the gdcmgendir man page for more info.

Why does System.IO.File.Exists(string path) return false?

System.IO.File.Exists(string path)
returns always false, even when the file exists on the specified path. What could be the possible solution?
It could well be a permission problem. From the documentation:
The Exists method returns false if any error occurs while trying to determine if the specified file exists. This can occur in situations that raise exceptions such as passing a file name with invalid characters or too many characters, a failing or missing disk, or if the caller does not have permission to read the file.
One way of seeing what's happening is to just try to read the file (e.g. with File.OpenRead). I'd be surprised if that succeeds - but if it fails, the exception should give you more information.
Hiding file endings in windows can sometimes cause confusion: you KNOW your file is named file.txt when it is actually named file.txt.txt because the last 4 characters have been hidden by the OS.
One possibility not mentioned in any of the answers here is 'File System Redirection' on Windows 8.1 onward.
For example, if your program is a 32-bit application and you're running on 64-bit Windows then an attempt to access %windir%\System32 would be redirected to %windir%\SysWOW64. And if the file you're trying to access doesn't exist in %windir%\SysWOW64 then System.IO.File.Exists(string path) would return False.
Link to a nice article explaining this behavior
I was puzzling over this as well, then realized I was using File.Exists when I should have been using Directory.Exists.
in my case, a different "dash" in file name causes the issue.
var f1 = "4-37R.pdf";
var f2 = "4‐37R.pdf";
var r = f1==f2?"same":"diff";
Console.Write(r); //diff
turns out
var c1 = '-';
var c2 = '‐';
Console.WriteLine((int)c1); //45
Console.WriteLine((int)c2); //8208
use the same '-' fixes the issue.
How I got around this was using Server.MapPath(fileName) as it kept trying to find the file somewhere else.
System.IO.File.Exists(Server.MapPath(string path))
This had me stumped for a while while I was debugging a service locally, I was running File.Exists("U:\dir1") against a server location mapped on my workstation as (U:). I replaced the U:\dir1 to "\\serverPath\dir1" and File.Exists then returned true.
I was experiencing this myself too. In my case, I was deleting the file and re-creating it. In the process that was deleting the file, I forgot to add in WaitForExit() before using File.Exists later on
I just learned today that System.IO.File.Exists will return false if the file exists but is empty
System.IO.File.Exists(string path) returned false for me while trying to read C:\OpenSSL\bin\file.txt.
Running the application in Administrator mode did not help.
(I was logged on the administrator account, Windows 10)
Once I moved the file to C:\Users\MyUser\Desktop\file.txt, File.Exists() returned true.
Here's one more, which took me far too long to twig to.
The file name was in a constructed variable that was use to write the file, then the same variable used to check that it had been successfully written, so it could not have been different versions of '-'. I am running mono on Linux and debugging as a different user than the program is normally run by/as. Many of these types of errors are related to permissions and I spent a while banging my head on that. When File.OpenRead also threw "file not found" I finally noticed my file name had a space character at the end. I only saw this when I copied the exception message, which showed quote marks around the file name string, revealing the included space.
Apparently you can write a file name with a trailing space, but File.Exists trims that off and doesn't recognize it. When I eliminated the trailing space File.Exists worked as expected.
There can be requirement to use the DirectoryProvider Refresh() process to get the correct result from the Exists function.
e.g. code as per:
private DirectoryInfo CreateDirectory(string folderPath, int code, string message)
{
DirectoryInfo di;
try
{
di = DirectoryProvider.CreateDirectory(folderPath);
}
catch
{
throw new WebServiceException(code, HttpStatusCode.BadRequest, message);
}
di.Refresh();
if (!DirectoryProvider.Exists(di))
{
throw new WebServiceException(code, HttpStatusCode.BadRequest, message);
}
return di;
}
I was using System.IO.Path.Combine and assuming it would remove any trailing white space. For the life of me I could figure out why System.IO.File.Exists(path) was returning false.
I used the below snippet to test why it was failing
Turns out that a trailing white space was introduced causing an
"The filename, directory name, or volume label syntax is incorrect inside batch"
Hopefully someone will avoid the same stupid mistake as me
bool FileExists(string path){
try
{
using var stream = File.Open(path, FileMode.Open);
return true;
}
catch (FileNotFoundException)
{
return false;
}
catch (DirectoryNotFoundException)
{
return false;
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine(ex.message);
throw;
}
catch (Exception ex)
{
Console.WriteLine(ex.message);
throw;
}
}

Issues about files or folders in use: get the name of another Process that use file or folder

I using C# .NET , vs 2008 , .net 3.5
For me, is difficult, but I need sample code in C# for this:
Check if a file or a folder is in use
If file or a folder is in use, the name of Process that use it
For example, in my issue.
I try delete file, and I get "The process cannot access the file 'XYZ' because it is being used by another process." Exception.
File.Delete(infoFichero.Ruta);
I want check if a file is in use, and the name of Process that use it.
I need sample code, source code, please. I dont want use c++, I dont know c, c++, unmanaged code, or WinApi. I want use only C# code (managed code .net).
I have read several references but not get sample code source,
How to check if a file is in use?
Emulate waiting on File.Open in C# when file is locked
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/9dabc172-237a-42db-850e-ada08885a5d5
How to check if a file is in use?
Easiest way to read text file which is locked by another application
Using C# is it possible to test if a lock is held on a file
EDIT:
From Yan Jun - MSFT
string path = "D:\\temp2.xlsx";
foreach (Process c in Process.GetProcesses()) {
if (c.MainWindowTitle.Contains(Path.GetFileName(path))){
MessageBox.Show(c.ProcessName);
return;
}
}
try{
FileInfo f = new FileInfo(path);
f.Delete();
}
catch (Exception ex){
MessageBox.Show(ex.Message);
}
...
But it is difficult get solution for all 100% issues.
Problem if c.MainWindowTitle == null or not contains filename.
Problem for shared folder in another machine, PC, server,... like:
File.Delete(#\desiis\TEmporal\Project\script.targets);
any sample code, I ask for help gurus, MVPs, anyone.
UPDATE: the same issue for a folder
There's not going to be a way to find the process that has the file opened without stepping into the WinApi, I don't think. And as far as checking whether its in use, the only thing you can really do, as the SO questions you linked to state, is to wrap the file access attempts in a try/catch block.
The code to find which file has it opened is likely to be ugly, but there may be an API out there that wraps this up nicely. There are 3rd party utilities that will tell you this (Unlocker being the best known example). You can also use ProcessExplorer to search for open file handles by the filename. Those don't really help you though.
The short answer of what I'm trying to get across here is you have the answer for the first part of your question in the SO questions you already linked, and the second part would probably require WIN32 calls, which you want to avoid, but you're probably going to have to get your hands dirty in Win32... Still want help?
EDIT: You could shell out to sysinternals Handle utility. You would need to get the output of that command and parse it yourself. You can read the executed process's output like this
string result = proc.StandardOutput.ReadToEnd();
The issue with this is you're going to get a license agreement popup the first time you run the Handle utility. Not to mention the whole licensing issues if this is something you hope to deploy...
If you're still interested, I can show you how you'd go about this.
EDIT: Here's a runnable program that will find the exe name and pid of any program that has an open handle to a file. I added comments, but can elaborate further if necessary. I use Regular Expressions here to parse the output as that makes the most sense given the task at hand.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ProcessStartInfo si = new ProcessStartInfo();
si.FileName = "handle.exe"; //name of the handle program from sysinternals
//assumes that its in the exe directory or in your path
//environment variable
//the following three lines are required to be able to read the output (StandardOutput)
//and hide the exe window.
si.RedirectStandardOutput = true;
si.WindowStyle = ProcessWindowStyle.Hidden;
si.UseShellExecute = false;
si.Arguments = "test.xlsx"; //this is the file you're trying to access that is locked
//these 4 lines create a process object, start it, then read the output to
//a new string variable "s"
Process p = new Process();
p.StartInfo = si;
p.Start();
string s = p.StandardOutput.ReadToEnd();
//this will use regular expressions to search the output for process name
//and print it out to the console window
string regex = #"^\w*\.EXE";
MatchCollection matches = Regex.Matches(s, regex, RegexOptions.Multiline);
foreach (var match in matches)
{
Console.WriteLine(match);
}
//this will use regex to search the output for the process id (pid)
//and print it to the console window.
regex = #"pid: (?<pid>[0-9]*)";
matches = Regex.Matches(s, regex, RegexOptions.Multiline);
foreach (var obj in matches)
{
Match match = (Match)obj; //i have to cast to a Match object
//to be able to get the named group out
Console.WriteLine(match.Groups["pid"].Value.ToString());
}
Console.Read();
}
}
}
There is no purely managed way to do this. You have to use some low-level APIs through P/invoke or similar.
There's good information here on a way to do it, but it's C++ code. You'd have to do the porting yourself.
http://www.codeproject.com/KB/shell/OpenedFileFinder.aspx
Note there are some complex issues with this, namely the issues around kernel vs. userspace memory. This is not a simple problem you're trying to solve.
Try the windows Process Explorer:
http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx
Won't let you do it from code, but at least you can figure out what the source of your locks are.

Categories