Class: GdbFlasher::ServerConnection

Inherits:
Object
  • Object
show all
Defined in:
lib/gdbflasher/server_connection.rb

Defined Under Namespace

Classes: StopReply

Instance Method Summary collapse

Constructor Details

#initializeServerConnection

Returns a new instance of ServerConnection.



14
15
16
# File 'lib/gdbflasher/server_connection.rb', line 14

def initialize
  @socket = nil
end

Instance Method Details

#closeObject



80
81
82
83
# File 'lib/gdbflasher/server_connection.rb', line 80

def close
  @socket.close
  @socket = nil
end

#connect(address) ⇒ Object

Raises:

  • (ArgumentError)


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/gdbflasher/server_connection.rb', line 18

def connect(address)
  raise "Already connected" unless @socket.nil?

  delimiter = address.rindex ':'
  raise ArgumentError, "Port must be specified" if delimiter.nil?
  host = address[0...delimiter]
  port = address[delimiter + 1..-1].to_i

  @buf = ""
  @features = {}
  @need_ack = true

  begin
    @socket = TCPSocket.new host, port
    @socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1

    # Query stub features
    command("qSupported").split(';').each do |feature|
      if feature[-1] == '-'
        @features.delete feature[0...-1].intern
      elsif feature[-1] == '+'
        @features[feature[0...-1].intern] = true
      else
        sep = feature.index '='

        if sep.nil?
          raise "Unexpected item in qSupported response: #{sep}"
        end

        @features[feature[0...sep].intern] = feature[sep + 1..-1]
      end
    end

    if @features[:PacketSize].nil?
      raise "PacketSize isn't present in qSupported response"
    end

    if @features[:QStartNoAckMode]
      response = command("QStartNoAckMode")

      if response != "OK"
        raise "Unable to enter NoAck mode: #{response}"
      end

      @need_ack = false
    end

    # Load target description
    if @features[:"qXfer:features:read"]
      description = read_xfer "features", "target.xml"

      # TODO: parse target description and use register map from it.
    end

  rescue Exception => e
    @socket.close unless @socket.nil?
    @socket = nil

    raise e
  end
end

#continueObject



167
168
169
# File 'lib/gdbflasher/server_connection.rb', line 167

def continue
  parse_stop_reply command("c")
end

#get_stop_replyObject



183
184
185
# File 'lib/gdbflasher/server_connection.rb', line 183

def get_stop_reply
  parse_stop_reply command("?")
end

#insert_breakpoint(type, address, kind) ⇒ Object



151
152
153
154
155
156
157
# File 'lib/gdbflasher/server_connection.rb', line 151

def insert_breakpoint(type, address, kind)
  response = command "Z#{type.to_s 16},#{address.to_s 16},#{kind.to_s 16}"

  if response != "OK"
    raise "Breakpoint insertion failed: #{response}"
  end
end

#read_memory(base, size) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/gdbflasher/server_connection.rb', line 125

def read_memory(base, size)
  max_size = (@features[:PacketSize].to_i - 19) & ~1
  offset = 0
  data = ""
  size *= 2

  while offset < size
    chunk_size = [ max_size, size - offset ].min

    response = command "m#{base.to_s 16},#{(chunk_size / 2).to_s 16}"

    if response[0] == "E"
      raise "Memory read failed: #{response}"
    end

    data += response

    base += chunk_size / 2
    offset += chunk_size
  end

  Array.new(data.length / 2) do |i|
    data[i * 2..i * 2 + 1].to_i 16
  end.pack("C*")
end

#read_registersObject



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/gdbflasher/server_connection.rb', line 85

def read_registers
  response = command "g"

  if (response[0] != 'E' || response.length != 3) && response.length % 8 != 0
    raise "Malformed 'g' response"
  end

  if response[0] == 'E'
    raise "GDB server error: #{response[1..2].to_i 16}"
  end

  Array.new response.length / 8 do |i|
    big2native response[i * 8...(i + 1) * 8].to_i(16)
  end
end

#remove_breakpoint(type, address, kind) ⇒ Object



159
160
161
162
163
164
165
# File 'lib/gdbflasher/server_connection.rb', line 159

def remove_breakpoint(type, address, kind)
  response = command "z#{type.to_s 16},#{address.to_s 16},#{kind.to_s 16}"

  if response != "OK"
    raise "Breakpoint removal failed: #{response}"
  end
end

#resetObject



175
176
177
178
179
180
181
# File 'lib/gdbflasher/server_connection.rb', line 175

def reset
  reply = command "r"

  if reply != "OK"
    raise "Reset failed: #{reply}"
  end
end

#stepObject



171
172
173
# File 'lib/gdbflasher/server_connection.rb', line 171

def step
  parse_stop_reply command("s")
end

#write_memory(base, string) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/gdbflasher/server_connection.rb', line 105

def write_memory(base, string)
  max_size = (@features[:PacketSize].to_i - 19) & ~1

  offset = 0
  data = string.unpack("C*").map { |byte| sprintf "%02X", byte }.join

  while offset < data.length
    chunk_size = [ max_size, data.length - offset ].min

    response = command "M#{base.to_s 16},#{(chunk_size / 2).to_s 16}:#{data[offset...offset + chunk_size]}"

    if response != "OK"
      raise "Memory write failed: #{response}"
    end

    base += chunk_size / 2
    offset += chunk_size
  end
end

#write_register(reg, value) ⇒ Object



187
188
189
190
191
192
193
# File 'lib/gdbflasher/server_connection.rb', line 187

def write_register(reg, value)
  reply = command sprintf("P%x=%08x", reg, big2native(value))

  if reply != "OK"
    raise "Register write failed: #{reply}"
  end
end

#write_registers(regs) ⇒ Object



101
102
103
# File 'lib/gdbflasher/server_connection.rb', line 101

def write_registers(regs)
  send_packet "G" + regs.map { |r| sprintf "%08x", native2big(r) }.join
end