From 2e87e2150e04c37595c02095c410decadfb9977e Mon Sep 17 00:00:00 2001 From: drbrain Date: Wed, 30 May 2012 22:48:42 +0000 Subject: * ext/dl: Added documentation. Patch by Vincent Batts. [ruby-trunk - Bug #6496] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35846 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/dl/dl.c | 48 +++++++++++++++++++++++++++++++++++++-- ext/dl/lib/dl.rb | 1 + ext/dl/lib/dl/cparser.rb | 37 ++++++++++++++++++++++++++++++ ext/dl/lib/dl/import.rb | 6 +++++ ext/dl/lib/dl/struct.rb | 59 +++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 148 insertions(+), 3 deletions(-) (limited to 'ext/dl') diff --git a/ext/dl/dl.c b/ext/dl/dl.c index cd4e0c1030..49fa7c81ac 100644 --- a/ext/dl/dl.c +++ b/ext/dl/dl.c @@ -49,6 +49,21 @@ ID rbdl_id_stdcall; #endif #define DLTYPE_UINTPTR_T (-DLTYPE_INTPTR_T) +/* + * call-seq: DL.dlopen(so_lib) + * + * An interface to the dynamic linking loader + * + * This is a shortcut to DL::Handle.new and takes the same arguments. + * + * Example: + * + * libc_so = "/lib64/libc.so.6" + * => "/lib64/libc.so.6" + * + * libc = DL.dlopen(libc_so) + * => # + */ VALUE rb_dl_dlopen(int argc, VALUE argv[], VALUE self) { @@ -56,7 +71,7 @@ rb_dl_dlopen(int argc, VALUE argv[], VALUE self) } /* - * call-seq: DL.malloc + * call-seq: DL.malloc(size) * * Allocate +size+ bytes of memory and return the integer memory address * for the allocated memory. @@ -103,6 +118,22 @@ rb_dl_free(VALUE self, VALUE addr) return Qnil; } +/* + * call-seq: DL.dlunwrap(addr) + * + * Returns the hexadecimal representation of a memory pointer address +addr+ + * + * Example: + * + * lib = DL.dlopen('/lib64/libc-2.15.so') + * => # + * + * lib['strcpy'].to_s(16) + * => "7f59de6dd240" + * + * DL.dlunwrap(DL.dlwrap(lib['strcpy'].to_s(16))) + * => "7f59de6dd240" + */ VALUE rb_dl_ptr2value(VALUE self, VALUE addr) { @@ -110,6 +141,19 @@ rb_dl_ptr2value(VALUE self, VALUE addr) return (VALUE)NUM2PTR(addr); } +/* + * call-seq: DL.dlwrap(val) + * + * Returns a memory pointer of a function's hexadecimal address location +val+ + * + * Example: + * + * lib = DL.dlopen('/lib64/libc-2.15.so') + * => # + * + * DL.dlwrap(lib['strcpy'].to_s(16)) + * => 25522520 + */ VALUE rb_dl_value2ptr(VALUE self, VALUE val) { @@ -489,7 +533,7 @@ Init_dl(void) /* Document-const: SIZEOF_UINTPTR_T * - * size of a intptr_t + * size of a uintptr_t */ rb_define_const(rb_mDL, "SIZEOF_UINTPTR_T", INT2NUM(sizeof(uintptr_t))); diff --git a/ext/dl/lib/dl.rb b/ext/dl/lib/dl.rb index 80d46b685a..b34bb82f41 100644 --- a/ext/dl/lib/dl.rb +++ b/ext/dl/lib/dl.rb @@ -6,6 +6,7 @@ rescue LoadError end module DL + # Returns true if DL is using Fiddle, the libffi wrapper. def self.fiddle? Object.const_defined?(:Fiddle) end diff --git a/ext/dl/lib/dl/cparser.rb b/ext/dl/lib/dl/cparser.rb index 7aae9ea4eb..e70e0f1dc1 100644 --- a/ext/dl/lib/dl/cparser.rb +++ b/ext/dl/lib/dl/cparser.rb @@ -1,5 +1,13 @@ module DL + # Methods for parsing C struct and C prototype signatures. module CParser + # Parses a C struct's members + # + # Example: + # + # parse_struct_signature(['int i', 'char c']) + # => [[DL::TYPE_INT, DL::TYPE_CHAR], ["i", "c"]] + # def parse_struct_signature(signature, tymap=nil) if( signature.is_a?(String) ) signature = signature.split(/\s*,\s*/) @@ -35,6 +43,16 @@ module DL return tys, mems end + # Parses a C prototype signature + # + # Example: + # + # include DL::CParser + # => Object + # + # parse_signature('double sum(double, double)') + # => ["sum", DL::TYPE_DOUBLE, [DL::TYPE_DOUBLE, DL::TYPE_DOUBLE]] + # def parse_signature(signature, tymap=nil) tymap ||= {} signature = signature.gsub(/\s+/, " ").strip @@ -56,6 +74,25 @@ module DL end end + # Given a String of C type +ty+, return the corresponding DL constant. + # + # +ty+ can also accept an Array of C type Strings, and will returned in a + # corresponding Array. + # + # If Hash +tymap+ is provided, +ty+ is expected to be the key, and the + # value will be the C type to be looked up. + # + # Example: + # + # parse_ctype('int') + # => DL::TYPE_INT + # + # parse_ctype('double') + # => DL::TYPE_DOUBLE + # + # parse_ctype('unsigned char') + # => -DL::TYPE_CHAR + # def parse_ctype(ty, tymap=nil) tymap ||= {} case ty diff --git a/ext/dl/lib/dl/import.rb b/ext/dl/lib/dl/import.rb index eec65cdfd6..a318430b73 100644 --- a/ext/dl/lib/dl/import.rb +++ b/ext/dl/lib/dl/import.rb @@ -179,11 +179,17 @@ module DL f end + # Creates a class to wrap the C struct described by +signature+. + # + # MyStruct = struct ['int i', 'char c'] def struct(signature) tys, mems = parse_struct_signature(signature, @type_alias) DL::CStructBuilder.create(CStruct, tys, mems) end + # Creates a class to wrap the C union described by +signature+. + # + # MyUnion = union ['int i', 'char c'] def union(signature) tys, mems = parse_struct_signature(signature, @type_alias) DL::CStructBuilder.create(CUnion, tys, mems) diff --git a/ext/dl/lib/dl/struct.rb b/ext/dl/lib/dl/struct.rb index b8becca6b6..27f6b42fd2 100644 --- a/ext/dl/lib/dl/struct.rb +++ b/ext/dl/lib/dl/struct.rb @@ -2,19 +2,50 @@ require 'dl' require 'dl/pack.rb' module DL + # C struct shell class CStruct + # accessor to DL::CStructEntity def CStruct.entity_class() CStructEntity end end + # C union shell class CUnion + # accessor to DL::CUnionEntity def CUnion.entity_class() CUnionEntity end end + # Used to construct C classes (CUnion, CStruct, etc) + # + # DL::Importer#struct and DL::Importer#union wrap this functionality in an + # easy-to-use manner. module CStructBuilder + # Construct a new class given a C: + # * class +klass+ (CUnion, CStruct, or other that provide an + # #entity_class) + # * +types+ (DL:TYPE_INT, DL::TYPE_SIZE_T, etc., see the C types + # constants) + # * corresponding +members+ + # + # DL::Importer#struct and DL::Importer#union wrap this functionality in an + # easy-to-use manner. + # + # Example: + # + # require 'dl/struct' + # require 'dl/cparser' + # + # include DL::CParser + # + # types, members = parse_struct_signature(['int i','char c']) + # + # MyStruct = DL::CStructBuilder.create(CUnion, types, members) + # + # obj = MyStruct.allocate + # def create(klass, types, members) new_class = Class.new(klass){ define_method(:initialize){|addr| @@ -43,15 +74,23 @@ module DL module_function :create end + # A C struct wrapper class CStructEntity < CPtr include PackInfo include ValueUtil + # Allocates a C struct the +types+ provided. The C function +func+ is + # called when the instance is garbage collected. def CStructEntity.malloc(types, func = nil) addr = DL.malloc(CStructEntity.size(types)) CStructEntity.new(addr, types, func) end + # Given +types+, returns the offset for the packed sizes of those types + # + # DL::CStructEntity.size([DL::TYPE_DOUBLE, DL::TYPE_INT, DL::TYPE_CHAR, + # DL::TYPE_VOIDP]) + # => 24 def CStructEntity.size(types) offset = 0 max_align = 0 @@ -76,15 +115,22 @@ module DL offset end + # Wraps the C pointer +addr+ as a C struct with the given +types+. The C + # function +func+ is called when the instance is garbage collected. + # + # See also DL::CPtr.new def initialize(addr, types, func = nil) set_ctypes(types) super(addr, @size, func) end + # Set the names of the +members+ in this C struct def assign_names(members) @members = members end + # Given +types+, calculate the offsets and sizes for the types in the + # struct. def set_ctypes(types) @ctypes = types @offset = [] @@ -112,6 +158,7 @@ module DL @size = offset end + # Fetch struct member +name+ def [](name) idx = @members.index(name) if( idx.nil? ) @@ -145,6 +192,7 @@ module DL end end + # Set struct member +name+, to value +val+ def []=(name, val) idx = @members.index(name) if( idx.nil? ) @@ -164,19 +212,27 @@ module DL end end - def to_s() + def to_s() # :nodoc: super(@size) end end + # A C union wrapper class CUnionEntity < CStructEntity include PackInfo + # Allocates a C union the +types+ provided. The C function +func+ is + # called when the instance is garbage collected. def CUnionEntity.malloc(types, func=nil) addr = DL.malloc(CUnionEntity.size(types)) CUnionEntity.new(addr, types, func) end + # Given +types+, returns the size needed for the union. + # + # DL::CUnionEntity.size([DL::TYPE_DOUBLE, DL::TYPE_INT, DL::TYPE_CHAR, + # DL::TYPE_VOIDP]) + # => 8 def CUnionEntity.size(types) size = 0 types.each_with_index{|t,i| @@ -191,6 +247,7 @@ module DL } end + # Given +types+, calculate the necessary offset and for each union member def set_ctypes(types) @ctypes = types @offset = [] -- cgit v1.2.3