[Mono-dev] Howto Marshal IntPtr to Elf32_Phdr[] ?

Tom Spink tspink at gmail.com
Mon Mar 28 03:29:58 EDT 2011


Hi,

> Still I was hoping for a less-hackish method via MarshalAs.

Unfortunately, MarshalAs almost helps you out, by giving you a
SizeParamIndex property, to indicate to the marshaller which parameter
to get size information from when marshalling an LPArray.  But - this
is only for methods (that have a signature with a parameter indicating
the size of the array), not for structures, so it doesn't really help.

> sounds awfully x86 specific, maybe even x86-32 specific

Well, it's just pointer arithmetic - your not actually manipulating
memory here, or doing anything clever at all.  You're just reading
from a certain location.  It's up to the API how it presents the
memory - in this case, a C-style array, which is compiler specific not
platform specific.

> [MarshalAs(UnmanagedType.LPStr)]

Good point on marshalling your string, with LPStr.  I was going to
mention it - but forgot.


On 27 March 2011 22:20, Quandary <quandary82 at hailmail.net> wrote:
> Hi Tom,
>
> Thank you, that works.
>
> Still I was hoping for a less-hackish method via MarshalAs.
>
> address + j * sizeof(mystruct_t)
> sounds awfully x86 specific, maybe even x86-32 specific
> But then again, so is struct Elf32_Phdr the way I did it.
>
>
> As a side-note to other potential users:
> If I/you apply
> [MarshalAs(UnmanagedType.LPStr)]
> to
> public System.IntPtr dlpi_name;
> and instead call it
> public string dlpi_name;
> then I needn't marshall it in the callback.
>
>
> Kind regards
>
> Stefan
>
>
> On 03/27/2011 06:23 PM, Tom Spink wrote:
>> Hi Quandry,
>>
>> You've almost got it - you just need to do a bit of pointer arithmetic.
>>
>> In your for loop, you've got this:
>>
>> ///
>> for (j = 0; j < info.dlpi_phnum; j++)
>>             Console.WriteLine("\t\t header {0}: address={1}\n", j, 22);
>> ///
>>
>> Not sure what that 22 is... but if you do this:
>>
>> ///
>> for (int j = 0; j < info.dlpi_phnum; j++) {
>>     var ptr = new IntPtr(info.dlpi_phdr.ToInt64() + (j *
>> Marshal.SizeOf(typeof(Elf32_Phdr))));
>>     var hdr = (Elf32_Phdr)Marshal.PtrToStructure(ptr, typeof(Elf32_Phdr));
>>
>>     Console.WriteLine("\t\t header {0}: address={1}: offset={2}\n", j,
>> info.dlpi_phdr, hdr.p_offset);
>> }
>> ///
>>
>> Inside your for loop, you've now got the 'hdr' variable, which is the
>> Elf32_Phdr struct of the 'current element' in the array.  This works
>> because info.dlpi_phdr is a pointer to the base address of the array -
>> where the array is just a sequential list of Elf32_Phdr structures.
>> So, by taking the base address, then adding on the index into the
>> array (multiplied by the size of the array's element type), you'll get
>> the base address of that particular element.  Once you've got this
>> base address, all you have to do is marshal that pointer, to the right
>> structure type.
>>
>> Also, make sure you mark your structures with the following attribute:
>>
>> [StructLayout(LayoutKind.Sequential)]
>>
>> Hope this helps!
>>
>> -- Tom
>>
>> On 27 March 2011 16:43, Quandary <quandary82 at hailmail.net> wrote:
>>> Hi everyone,
>>>
>>> I have a problem with dl_iterate_phdr.
>>> (man 3 dl_iterate_phdr)
>>>
>>> You find the (till now unanswered) question on stackoverflow, I'm not
>>> inclined to retype everything here again, so below the link:
>>> http://stackoverflow.com/questions/5447282/c-howto-marshal-intptr-to-an-array-of-struct
>>>
>>> In a nutshell, the problem is the struct dl_phdr_info you see below.
>>>
>>> It seems I need to Marshal
>>> public System.IntPtr dlpi_phdr;
>>> to
>>> public Elf32_Phdr[] dlpi_phdr;
>>> somehow.
>>>
>>> Or maybe I did translate it to managed code the wrong way.
>>> Can anybody have a look at it ?
>>>
>>> All necessary code/structs to get the sample running you find on the
>>> stackoverflow link.
>>>
>>>
>>> Here's the C struct:
>>>
>>>  struct dl_phdr_info {
>>>            ElfW(Addr)        dlpi_addr;  /* Base address of object */
>>>            const char       *dlpi_name;  /* (Null-terminated) name of
>>>                                             object */
>>>            const ElfW(Phdr) *dlpi_phdr;  /* Pointer to array of
>>>                                             ELF program headers
>>>                                             for this object */
>>>            ElfW(Half)        dlpi_phnum; /* # of items in dlpi_phdr */
>>>        };
>>>
>>> Here's my C# translation of the above struct:
>>>
>>>   public struct dl_phdr_info
>>>     {
>>>         public System.UInt32 dlpi_addr; /* Base address of object */
>>>
>>>         // TODO: String, MarshalAs Pointer
>>>         public System.IntPtr dlpi_name;  /* (Null-terminated) name of
>>> object*/
>>>
>>>         /* Pointer to array of ELF program headers for this object */
>>>         public System.IntPtr dlpi_phdr; // Hackish, cannot read it, but then
>>> at least the rest works
>>>
>>>         // This way it throws an exception at runtime.
>>>
>>> //[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStruct)]
>>>         //public Elf32_Phdr[] dlpi_phdr;
>>>
>>>         public System.UInt16  dlpi_phnum; /* # of items in 'dlpi_phdr' */
>>>     }
>>>
>>>
>>> _______________________________________________
>>> Mono-devel-list mailing list
>>> Mono-devel-list at lists.ximian.com
>>> http://lists.ximian.com/mailman/listinfo/mono-devel-list
>>>
>>>
>>
>>
>
>



-- 
Tom Spink


More information about the Mono-devel-list mailing list