Class: RMasm::Struct::Path

Inherits:
Object show all
Defined in:
lib/rmasm/struct.rb

Overview

A path through structure fields : MyStructure.field1.fieldOfSubStructure…etc. This class is used to calculate offset inside a struct and can be used inside any assembler instruction that support it

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(owner_struct, field) ⇒ Path

Returns a new instance of Path.



180
181
182
183
# File 'lib/rmasm/struct.rb', line 180

def initialize(owner_struct, field)
  @__path__ = [owner_struct, field]
  @offset = field.offset
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args) ⇒ Object

Method missing is used to resolve the path field



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/rmasm/struct.rb', line 229

def method_missing(sym, *args)
  # Last Field
  last_field = @__path__[-1]
  field_type = last_field.type

  # Does the type of the field respond to the method :sym ?
  if field_type.respond_to?(sym, false)
    return field_type.send(sym, *args)
  end

  # Is the last field a struct?
  if field_type.is_struct?
    # Does the type of the field has a field :sym ?
    subfield = field_type[sym]
    if subfield.nil?
      return Report.error(:R20E2, sym, self)
    end

    # If subfield is found, than add it to the path
    @offset += subfield.offset

    # update the path and return self
    @__path__ << subfield
    return self
  end

  # If the field type is a primitive just print a custom message
  if field_type.is_primitive?
    return Report.error(:R20F2, sym, self)
  end

  # else print an error
  return Report.error(:R20E2, sym, self)
end

Instance Attribute Details

#offsetObject (readonly)

Returns the value of attribute offset.



178
179
180
# File 'lib/rmasm/struct.rb', line 178

def offset
  @offset
end

Instance Method Details

#[](arg) ⇒ Object

Handle sub-array reference



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/rmasm/struct.rb', line 186

def [](arg)

  # Check that the last_field is an array
  field = @__path__[-1]
  if field.array_size.nil?
    return Report.error(:R20G3, arg, self, field.name)
  end

  # Check that the index is an integer
  if ! arg.is_a?(Integer)
    return Report.error(:R20H2, arg, self)
  end

  # Check that the array index is not larger than the size of the field array
  maximum_index = ((field.array_size ==0)? DWord::MAX : field.array_size) - 1
  if arg < 0 || arg > maximum_index
    return Report.error(:R20I3, arg, "0..#{maximum_index}", self)
  end

  # shift byte offset to the index in the array according to the size of the unitary field
  @offset += field.type.sizeof * arg

  # Create a new fake field that points to the array
  array_field_item = Field.new(field.type, "[#{arg}]", nil)

  # Add this field_array to the path
  @__path__ << array_field_item

  self
end

#sizeofObject

Calculate the sizeof this field



218
219
220
221
222
223
224
225
226
# File 'lib/rmasm/struct.rb', line 218

def sizeof()
  last_field = @__path__[-1]
  field_type = last_field.type
  size = field_type.sizeof
  if ! last_field.array_size.nil?
    size = size * last_field.array_size
  end
  size
end

#to_sObject



264
265
266
267
268
269
270
271
272
273
# File 'lib/rmasm/struct.rb', line 264

def to_s()
  str = "#{@__path__[0]}"
  @__path__[1..-1].each do |item|
    if item.name[0] != "["
      str << "."
    end
    str << "#{item.name}"
  end
  str
end