Reading binary file into structure

I am writing an application that must read ELF files and process the data using VB.net. The files are binary data and it must be read into a number of structures. I am presently trying to read the first block of data into the header structure but not able to get it to work. This is the header structure:

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure Elf32_Ehdr
        Public e_ident As elfIdentifier   ' File identifier
        Public e_type As UInt16         ' Object File Type
        Public e_machine As UInt16      ' Target Machine Architecture
        Public e_version As UInt32      ' Object File Version
        Public e_entry As UInt32        ' Executable Start Address (zero if not used)
        Public e_phoff As UInt32        ' Program Header File Offset (zero if not present)
        Public e_shoff As UInt32        ' Section Header Table File Offset (zero if not present)
        Public e_flags As UInt32        ' Processor Specific Flags
        Public e_ehsize As UInt16       ' Elf Header Size (in bytes)
        Public e_phentsize As UInt16    ' Entry size in File's Program Header Table (all same size)
        Public e_phnum As UInt16        ' Number of entries in the Program Header Table (zero if none present)
        Public e_shentsize As UInt16    ' Section Header Size in bytes (all same size)
        Public e_shnum As UInt16        ' Number of entries in the Section Header Table (zero if none present)
        Public e_shstrndx As UInt16     ' Section Header Table Index of the entry with the Section Name String Table )SHN_UNDEF if none)
    End Structure

Open in new window


And this is the code:

    Public Function Load(ByVal theFilename As String) As Boolean
        Dim fResult As Boolean = False
        Dim sStructure As New Elf32_Ehdr

        Dim headerSize As UInt32 = Marshal.SizeOf(sStructure)
        '
        ' Check the file exists
        '
        If IO.File.Exists(theFilename) = True Then      ' Proceed
            Try
                Dim inputFile As IO.FileStream = IO.File.OpenRead(theFilename)
                Dim inputBuffer() As Byte

                ReDim inputBuffer(headerSize - 1)
                inputFile.Read(inputBuffer, 0, headerSize)
                Dim gch = GCHandle.Alloc(inputBuffer, GCHandleType.Pinned)
                Dim ptr As IntPtr = gch.AddrOfPinnedObject
                sStructure = CType(Marshal.PtrToStructure(ptr, GetType(Elf32_Ehdr)), Elf32_Ehdr)
                gch.Free()
            Catch ex As Exception

            End Try

            fResult = True
        End If
        Return (fResult)
    End Function

Open in new window


The type conversion line is where I get an exception "The runtime has encountered a fatal error. The address of the error was at 0x733a5adb, on thread 0xed4. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack."

Please advise where my code is in error, thanks,
Sid
Sid PriceSoftware Systems Architect/DesignerAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Jacques Bourgeois (James Burger)PresidentCommented:
Have you thought of using a BinaryReader instead of a FileStream.

The BinaryReader has methods to read different types of binary values (ReadUInt32, ReadUInt16). It requires that you write one line of code for each of the structure fields, so it might require more code and be a bit slower. But this code is easier to read and makes things easier to debug because when a problem occurs, you know exactly on which value it happens.
Sid PriceSoftware Systems Architect/DesignerAuthor Commented:
Jacques, thank you for the suggestion. Indeed I have considered this approach, however I find it rather poor design because it requires the knowledge of the structure contents be stated in two places, not good design. Change the structure and then you break the reading from the file.

I would really like to know what is wrong with my implementation and fix it!
Sid
Jacques Bourgeois (James Burger)PresidentCommented:
This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code

There is not much you can do about that. This is one reason I suggested the BinaryReader.

And this is not as bad a design as you think. One also has to think about maintenance. If the structure changes, you won't be able to read older files with a direct CType, because it won't match what is in the file. Who knows, it might even be the root of your problem. How can you be sure that the format of the file you are trying to read match the structure?

With a binary reader however, you can easily implement a system that goes around the changes and is able to read files created with the old structure as well as files that have the changes. I do not know if you have access to the code that generates the file, but when I deal with binary files, the first piece of data is always a file version number. This enables me to control how the file needs to be read. If you wrap the reading/writing of the structure to and from the file in a class, it's easy to keep the knowledge of the structure contents in one place.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
OWASP: Threats Fundamentals

Learn the top ten threats that are present in modern web-application development and how to protect your business from them.

Mike TomlinsonHigh School Computer Science, Computer Applications, and Mathematics TeachersCommented:
The code ~looks~ okay.  I don't think anyone is going to be able to help you without an example file to work with and the additional "elfIdentifier" definition.

The only thing I can think of is that somehow you've got one of the data types wrong in the structure definitions and this is causing an error?
Sid PriceSoftware Systems Architect/DesignerAuthor Commented:
Jacques, seems I came to a similar conclusion as you and that is to wrap the structures (there are quite a few) in classes that have the read method built in and expose the header as a set of properties. This is a nice clean way of doing it.

Sid.
Jacques Bourgeois (James Burger)PresidentCommented:
If it can help you, here is how I do it.
			Using reader As BinaryReader = New BinaryReader(file)

				'Read the file version
				_FileVersion = reader.ReadInt32

				'Check that the version is still supported
				If FileVersion < MinimumFileVersion Then
					Throw New JBException(String.Format(My.Resources.MsgMinimumFileVersion, file.Name, FileVersion, MinimumFileVersion))
					Exit Sub
				End If

				With reader

					'Read the Document information
					Me.SentenceCase = .ReadBoolean
					Me.ProperCase = .ReadBoolean
					Me.TitleBackColor = Color.FromArgb(.ReadInt32)
					If FileVersion >= 18 Then 'Field that was added in version 18
						Me.DefaultBackColor = Color.FromArgb(.ReadInt32)
					End If
					Me.CurrentPageIndex = .ReadInt32
					If FileVersion < 22 Then
						.ReadInt32()  'Field that was removed in version 22
					End If

					typeID = DirectCast(.ReadByte, TypeID)

				End With

			End Using

Open in new window

Sid PriceSoftware Systems Architect/DesignerAuthor Commented:
Thank you Jacques, I wish I could use a version number but this long-time industry file format doesn't do it that way. The first entry in the file is the header seen above. The version is embedded in the header.
Sid.
Jacques Bourgeois (James Burger)PresidentCommented:
As long as you can extract the version from the header, the mechanism would work.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.