metasm 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.hgtags +3 -0
  4. data/Gemfile +1 -0
  5. data/INSTALL +61 -0
  6. data/LICENCE +458 -0
  7. data/README +29 -21
  8. data/Rakefile +10 -0
  9. data/TODO +10 -12
  10. data/doc/code_organisation.txt +2 -0
  11. data/doc/core/DynLdr.txt +247 -0
  12. data/doc/core/ExeFormat.txt +43 -0
  13. data/doc/core/Expression.txt +220 -0
  14. data/doc/core/GNUExports.txt +27 -0
  15. data/doc/core/Ia32.txt +236 -0
  16. data/doc/core/SerialStruct.txt +108 -0
  17. data/doc/core/VirtualString.txt +145 -0
  18. data/doc/core/WindowsExports.txt +61 -0
  19. data/doc/core/index.txt +1 -0
  20. data/doc/style.css +6 -3
  21. data/doc/usage/debugger.txt +327 -0
  22. data/doc/usage/index.txt +1 -0
  23. data/doc/use_cases.txt +2 -2
  24. data/metasm.gemspec +22 -0
  25. data/{lib/metasm.rb → metasm.rb} +11 -3
  26. data/{lib/metasm → metasm}/compile_c.rb +13 -7
  27. data/metasm/cpu/arc.rb +8 -0
  28. data/metasm/cpu/arc/decode.rb +425 -0
  29. data/metasm/cpu/arc/main.rb +191 -0
  30. data/metasm/cpu/arc/opcodes.rb +588 -0
  31. data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
  32. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  33. data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
  34. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  35. data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
  36. data/metasm/cpu/arm/opcodes.rb +324 -0
  37. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  38. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  39. data/metasm/cpu/arm64.rb +15 -0
  40. data/metasm/cpu/arm64/debug.rb +38 -0
  41. data/metasm/cpu/arm64/decode.rb +289 -0
  42. data/metasm/cpu/arm64/encode.rb +41 -0
  43. data/metasm/cpu/arm64/main.rb +105 -0
  44. data/metasm/cpu/arm64/opcodes.rb +232 -0
  45. data/metasm/cpu/arm64/parse.rb +20 -0
  46. data/metasm/cpu/arm64/render.rb +95 -0
  47. data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
  48. data/metasm/cpu/bpf/decode.rb +142 -0
  49. data/metasm/cpu/bpf/main.rb +60 -0
  50. data/metasm/cpu/bpf/opcodes.rb +81 -0
  51. data/metasm/cpu/bpf/render.rb +41 -0
  52. data/metasm/cpu/cy16.rb +9 -0
  53. data/metasm/cpu/cy16/decode.rb +253 -0
  54. data/metasm/cpu/cy16/main.rb +63 -0
  55. data/metasm/cpu/cy16/opcodes.rb +78 -0
  56. data/metasm/cpu/cy16/render.rb +41 -0
  57. data/metasm/cpu/dalvik.rb +11 -0
  58. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
  59. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
  60. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
  61. data/metasm/cpu/ia32.rb +17 -0
  62. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
  63. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
  64. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
  65. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
  66. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  67. data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
  68. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  69. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
  70. data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
  71. data/metasm/cpu/mips.rb +14 -0
  72. data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
  73. data/metasm/cpu/mips/debug.rb +42 -0
  74. data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
  75. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  76. data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
  77. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
  78. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  79. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  80. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  81. data/metasm/cpu/msp430/decode.rb +247 -0
  82. data/metasm/cpu/msp430/main.rb +62 -0
  83. data/metasm/cpu/msp430/opcodes.rb +101 -0
  84. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  85. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  86. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  87. data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
  88. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
  89. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  90. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  91. data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
  92. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
  93. data/metasm/cpu/ppc/parse.rb +55 -0
  94. data/metasm/cpu/python.rb +8 -0
  95. data/metasm/cpu/python/decode.rb +136 -0
  96. data/metasm/cpu/python/main.rb +36 -0
  97. data/metasm/cpu/python/opcodes.rb +180 -0
  98. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  99. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
  100. data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
  101. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  102. data/metasm/cpu/x86_64.rb +15 -0
  103. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
  104. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  105. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
  106. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
  107. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
  108. data/metasm/cpu/x86_64/opcodes.rb +136 -0
  109. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
  110. data/metasm/cpu/x86_64/render.rb +35 -0
  111. data/metasm/cpu/z80.rb +9 -0
  112. data/metasm/cpu/z80/decode.rb +313 -0
  113. data/metasm/cpu/z80/main.rb +67 -0
  114. data/metasm/cpu/z80/opcodes.rb +224 -0
  115. data/metasm/cpu/z80/render.rb +59 -0
  116. data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
  117. data/{lib/metasm → metasm}/decode.rb +35 -4
  118. data/{lib/metasm → metasm}/decompile.rb +15 -16
  119. data/{lib/metasm → metasm}/disassemble.rb +201 -45
  120. data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
  121. data/{lib/metasm → metasm}/dynldr.rb +220 -133
  122. data/{lib/metasm → metasm}/encode.rb +10 -1
  123. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  124. data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
  125. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  126. data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
  127. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
  128. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
  129. data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
  130. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  131. data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
  132. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
  133. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
  134. data/metasm/exe_format/gb.rb +65 -0
  135. data/metasm/exe_format/javaclass.rb +424 -0
  136. data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
  137. data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
  138. data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
  139. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  140. data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
  141. data/metasm/exe_format/pyc.rb +167 -0
  142. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  143. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  144. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  145. data/metasm/exe_format/swf.rb +205 -0
  146. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  147. data/metasm/exe_format/zip.rb +335 -0
  148. data/metasm/gui.rb +13 -0
  149. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  150. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  151. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
  152. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  153. data/metasm/gui/dasm_graph.rb +1695 -0
  154. data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
  155. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  156. data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
  157. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  158. data/{lib/metasm → metasm}/gui/debug.rb +93 -27
  159. data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
  160. data/{lib/metasm → metasm}/gui/qt.rb +12 -2
  161. data/{lib/metasm → metasm}/gui/win32.rb +179 -42
  162. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  163. data/{lib/metasm → metasm}/main.rb +389 -264
  164. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  165. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  166. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  167. data/metasm/os/main.rb +330 -0
  168. data/{lib/metasm → metasm}/os/windows.rb +132 -42
  169. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  170. data/{lib/metasm → metasm}/parse.rb +26 -24
  171. data/{lib/metasm → metasm}/parse_c.rb +221 -116
  172. data/{lib/metasm → metasm}/preprocessor.rb +55 -40
  173. data/{lib/metasm → metasm}/render.rb +14 -38
  174. data/misc/hexdump.rb +2 -1
  175. data/misc/lint.rb +58 -0
  176. data/misc/txt2html.rb +9 -7
  177. data/samples/bindiff.rb +3 -4
  178. data/samples/dasm-plugins/bindiff.rb +15 -0
  179. data/samples/dasm-plugins/bookmark.rb +133 -0
  180. data/samples/dasm-plugins/c_constants.rb +57 -0
  181. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  182. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  183. data/samples/dasm-plugins/dasm_all.rb +70 -0
  184. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  185. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  186. data/samples/dasm-plugins/dump_text.rb +35 -0
  187. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  188. data/samples/dasm-plugins/findgadget.rb +75 -0
  189. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  190. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  191. data/samples/dasm-plugins/imm2off.rb +34 -0
  192. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  193. data/samples/dasm-plugins/patch_file.rb +95 -0
  194. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  195. data/samples/dasm-plugins/scanxrefs.rb +26 -0
  196. data/samples/dasm-plugins/selfmodify.rb +197 -0
  197. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  198. data/samples/dasmnavig.rb +1 -1
  199. data/samples/dbg-apihook.rb +24 -9
  200. data/samples/dbg-plugins/heapscan.rb +283 -0
  201. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  202. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  203. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  204. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  205. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  206. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  207. data/samples/dbg-plugins/trace_func.rb +214 -0
  208. data/samples/disassemble-gui.rb +35 -5
  209. data/samples/disassemble.rb +31 -6
  210. data/samples/dump_upx.rb +24 -12
  211. data/samples/dynamic_ruby.rb +12 -3
  212. data/samples/exeencode.rb +6 -5
  213. data/samples/factorize-headers-peimports.rb +1 -1
  214. data/samples/lindebug.rb +175 -381
  215. data/samples/metasm-shell.rb +1 -2
  216. data/samples/peldr.rb +2 -2
  217. data/tests/all.rb +1 -1
  218. data/tests/arc.rb +26 -0
  219. data/tests/dynldr.rb +22 -4
  220. data/tests/expression.rb +55 -0
  221. data/tests/graph_layout.rb +285 -0
  222. data/tests/ia32.rb +79 -26
  223. data/tests/mips.rb +9 -2
  224. data/tests/x86_64.rb +66 -18
  225. metadata +330 -218
  226. data/lib/metasm/arm/opcodes.rb +0 -177
  227. data/lib/metasm/gui.rb +0 -23
  228. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  229. data/lib/metasm/ia32.rb +0 -14
  230. data/lib/metasm/ia32/opcodes.rb +0 -873
  231. data/lib/metasm/ppc/parse.rb +0 -52
  232. data/lib/metasm/x86_64.rb +0 -12
  233. data/lib/metasm/x86_64/opcodes.rb +0 -118
  234. data/samples/gdbclient.rb +0 -583
  235. data/samples/rubstop.rb +0 -399
@@ -9,7 +9,7 @@ class AsmOpcodeWidget < DrawableWidget
9
9
  attr_accessor :dasm
10
10
  # nr of raw data bytes to display next to decoded instructions
11
11
  attr_accessor :raw_data_length
12
-
12
+
13
13
  def initialize_widget(dasm, parent_widget)
14
14
  @dasm = dasm
15
15
  @parent_widget = parent_widget
@@ -22,9 +22,7 @@ class AsmOpcodeWidget < DrawableWidget
22
22
  @view_max = @dasm.sections.map { |s, e| s + e.length }.max rescue nil
23
23
  @view_addr = @dasm.prog_binding['entrypoint'] || @view_min || 0
24
24
 
25
- @default_color_association = { :comment => :darkblue, :label => :darkgreen, :text => :black,
26
- :instruction => :black, :address => :blue, :caret => :black, :raw_data => :black,
27
- :background => :white, :cursorline_bg => :paleyellow, :hl_word => :palered }
25
+ @default_color_association = ColorTheme.merge :raw_data => :black
28
26
  end
29
27
 
30
28
  def resized(w, h)
@@ -124,19 +122,7 @@ class AsmOpcodeWidget < DrawableWidget
124
122
  # must not include newline
125
123
  render = lambda { |str, color|
126
124
  fullstr << str
127
- if @hl_word
128
- stmp = str
129
- pre_x = 0
130
- while stmp =~ /^(.*?)(\b#{Regexp.escape @hl_word}\b)/
131
- s1, s2 = $1, $2
132
- pre_x += s1.length * @font_width
133
- hl_x = s2.length * @font_width
134
- draw_rectangle_color(:hl_word, x+pre_x, y, hl_x, @font_height)
135
- pre_x += hl_x
136
- stmp = stmp[s1.length+s2.length..-1]
137
- end
138
- end
139
- draw_string_color(color, x, y, str)
125
+ draw_string_hl(color, x, y, str)
140
126
  x += str.length * @font_width
141
127
  }
142
128
 
@@ -154,7 +140,7 @@ class AsmOpcodeWidget < DrawableWidget
154
140
 
155
141
  # draw text until screen is full
156
142
  while y < height
157
- if label = invb[curaddr]
143
+ if invb[curaddr]
158
144
  nl[]
159
145
  @dasm.label_alias[curaddr].to_a.each { |name|
160
146
  render["#{name}:", :label]
@@ -251,7 +237,7 @@ class AsmOpcodeWidget < DrawableWidget
251
237
  # redraws the caret, change the hilighted word, redraw if needed
252
238
  def update_caret
253
239
  if update_hl_word(@line_text[@caret_y], @caret_x) or @caret_y != @oldcaret_y
254
- redraw
240
+ redraw
255
241
  elsif @oldcaret_x != @caret_x
256
242
  invalidate_caret(@oldcaret_x, @oldcaret_y)
257
243
  invalidate_caret(@caret_x, @caret_y)
@@ -30,7 +30,7 @@ class DbgWidget < ContainerVBoxWidget
30
30
  oldcb = @code.bg_color_callback
31
31
  @code.bg_color_callback = lambda { |a|
32
32
  if a == @dbg.pc
33
- 'f88'
33
+ :red_bg
34
34
  # TODO breakpoints & stuff
35
35
  elsif oldcb; oldcb[a]
36
36
  end
@@ -48,8 +48,8 @@ class DbgWidget < ContainerVBoxWidget
48
48
 
49
49
  pc = @dbg.resolve_expr(@watchpoint[@code])
50
50
  graph = :graph if @dbg.disassembler.function_blocks(pc).to_a.length < 100
51
- @code.focus_addr(pc, graph)
52
- @mem.focus_addr(0, :hex)
51
+ @code.focus_addr(pc, graph, true)
52
+ @mem.focus_addr(0, :hex, true)
53
53
  end
54
54
 
55
55
  def swapin_tid
@@ -98,10 +98,16 @@ class DbgWidget < ContainerVBoxWidget
98
98
 
99
99
  # TODO check_target always, incl when :stopped
100
100
  def post_dbg_run
101
+ # focus currently stopped threads
102
+ if @dbg.state == :running and tt = @dbg.tid_stuff.find { |tid, tstuff| tstuff[:state] != :running }
103
+ @dbg.tid = tt[0]
104
+ end
105
+
101
106
  want_redraw = true
102
107
  return if @idle_checking ||= nil # load only one bg proc
103
108
  @idle_checking = true
104
109
  Gui.idle_add {
110
+ protect {
105
111
  @dbg.check_target
106
112
  if @dbg.state == :running
107
113
  redraw if want_redraw # redraw once if the target is running (less flicker with singlestep)
@@ -121,6 +127,7 @@ class DbgWidget < ContainerVBoxWidget
121
127
  }
122
128
  redraw
123
129
  false
130
+ }
124
131
  }
125
132
  end
126
133
 
@@ -166,7 +173,10 @@ class DbgWidget < ContainerVBoxWidget
166
173
  l = listwindow('running processes', list,
167
174
  :noshow => true,
168
175
  :color_callback => lambda { |le| [:grey, :palegrey] if le[0] == me }
169
- ) { |e| i.text = e[0] }
176
+ ) { |e|
177
+ i.text = e[0]
178
+ i.keypress(:enter) if l.destroyed?
179
+ }
170
180
  l.x += l.width
171
181
  l.show
172
182
  false
@@ -198,10 +208,28 @@ class DbgWidget < ContainerVBoxWidget
198
208
  case f
199
209
  when /\.(c|h|cpp)$/; @dbg.disassembler.parse_c_file(f)
200
210
  when /\.map$/; @dbg.load_map(f)
201
- when /\.rb$/; @dbg.load_plugin(f)
211
+ when /\.rb$/; @dbg.load_plugin(f) ; @console.add_log "loaded plugin #{File.basename(f, '.rb')}"
202
212
  else messagebox("unsupported file extension #{f}")
203
213
  end
204
214
  end
215
+
216
+ def extend_contextmenu(tg, menu, addr=nil)
217
+ if addr
218
+ bm = tg.new_menu
219
+ bl = @dbg.all_breakpoints(addr)
220
+ if not bl.empty?
221
+ tg.addsubmenu(bm, '_clear breakpoint') { bl.each { |b| @dbg.del_bp(b) } }
222
+ end
223
+ tg.addsubmenu(bm, '_go here') { @dbg.bpx(addr, true) ; dbg_continue }
224
+ tg.addsubmenu(bm, '_bpx') { @dbg.bpx(addr) }
225
+ tg.addsubmenu(bm, 'bpm _read') { @dbg.hwbp(addr, :r, 1) }
226
+ tg.addsubmenu(bm, 'bpm _write') { @dbg.hwbp(addr, :w, 1) }
227
+ tg.addsubmenu(menu, '_bp', bm)
228
+ end
229
+ if @parent_widget.respond_to?(:extend_contextmenu)
230
+ @parent_widget.extend_contextmenu(tg, menu, addr)
231
+ end
232
+ end
205
233
  end
206
234
 
207
235
 
@@ -221,10 +249,9 @@ class DbgRegWidget < DrawableWidget
221
249
  swapin_tid
222
250
 
223
251
  @reg_pos = [] # list of x y w h vx of the reg drawing on widget, vx is x of value
224
-
225
- @default_color_association = { :label => :black, :data => :blue, :write_pending => :darkred,
226
- :changed => :darkgreen, :caret => :black, :background => :white,
227
- :inactive => :palegrey }
252
+
253
+ @default_color_association = ColorTheme.merge :label => :text, :data => :blue, :write_pending => :darkred,
254
+ :changed => :green, :caret => :text, :inactive => :palegrey
228
255
  end
229
256
 
230
257
  def swapin_tid
@@ -262,7 +289,6 @@ class DbgRegWidget < DrawableWidget
262
289
  end
263
290
 
264
291
  def paint
265
- curaddr = 0
266
292
  x = 1
267
293
  y = 0
268
294
 
@@ -402,7 +428,7 @@ class DbgRegWidget < DrawableWidget
402
428
  @write_pending[reg] = v
403
429
  rsz = 1
404
430
  end
405
-
431
+
406
432
  if rsz == 1
407
433
  @caret_reg += 1
408
434
  @caret_reg = @registers.length if @caret_reg >= @registers.length + @flags.length
@@ -472,8 +498,8 @@ class DbgConsoleWidget < DrawableWidget
472
498
 
473
499
  @dbg.set_log_proc { |l| add_log l }
474
500
 
475
- @default_color_association = { :log => :palegrey, :curline => :white, :caret => :yellow,
476
- :background => :black, :status => :black, :status_bg => '088' }
501
+ @default_color_association = ColorTheme.merge :log => :palegrey, :curline => :white, :caret => :yellow,
502
+ :background => :black, :status => :black, :status_bg => '088'
477
503
 
478
504
  init_commands
479
505
  end
@@ -513,6 +539,21 @@ class DbgConsoleWidget < DrawableWidget
513
539
  clipboard_copy(txt)
514
540
  end
515
541
 
542
+ # copy/paste word under cursor (paste when on last line)
543
+ def rightclick(x, y)
544
+ y -= height % @font_height
545
+ y = y.to_i / @font_height
546
+ hc = height / @font_height
547
+ x /= @font_width
548
+ if y >= hc - 2
549
+ keypress_ctrl ?v
550
+ else
551
+ txt = @log.reverse[@log_offset + hc - y - 3].to_s
552
+ word = txt[0...x].to_s[/\w*$/] << txt[x..-1].to_s[/^\w*/]
553
+ clipboard_copy(word)
554
+ end
555
+ end
556
+
516
557
  def mouse_wheel(dir, x, y)
517
558
  case dir
518
559
  when :up; @log_offset += 3
@@ -531,12 +572,12 @@ class DbgConsoleWidget < DrawableWidget
531
572
 
532
573
  w_w = width
533
574
 
534
- y -= @font_height
575
+ y -= @font_height
535
576
  draw_rectangle_color(:status_bg, 0, y, w_w, @font_height)
536
577
  str = "#{@dbg.pid}:#{@dbg.tid} #{@dbg.state} #{@dbg.info}"
537
578
  draw_string_color(:status, w_w-str.length*@font_width-1, y, str)
538
579
  draw_string_color(:status, 1+@font_width, y, @statusline)
539
- y -= @font_height
580
+ y -= @font_height
540
581
 
541
582
  w_w_c = w_w/@font_width
542
583
  @caret_y = y
@@ -744,7 +785,7 @@ class DbgConsoleWidget < DrawableWidget
744
785
  def cmd_dd(addr, dlen=nil, len=nil)
745
786
  if addr.kind_of? String
746
787
  s = addr.strip
747
- addr = solve_expr!(s)
788
+ addr = solve_expr!(s) || @parent_widget.mem.curaddr
748
789
  if not s.empty?
749
790
  s = s[1..-1] if s[0] == ?,
750
791
  len ||= solve_expr(s)
@@ -757,7 +798,7 @@ class DbgConsoleWidget < DrawableWidget
757
798
  le = (@dbg.cpu.endianness == :little)
758
799
  data = '' if @dbg.memory.page_invalid?(addr)
759
800
  case dlen
760
- when nil; add_log "#{Expression[addr]} #{data.unpack('C*').map { |c| '%02X' % c }.join(' ').ljust(2*16+15)} #{data.tr("\0-\x1f\x7f-\xff", '.')}"
801
+ when nil; add_log "#{Expression[addr]} #{data.unpack('C*').map { |c| '%02X' % c }.join(' ').ljust(2*16+15)} #{data.tr("^\x20-\x7e", '.')}"
761
802
  when 1; add_log "#{Expression[addr]} #{data.unpack('C*').map { |c| '%02X' % c }.join(' ')}"
762
803
  when 2; add_log "#{Expression[addr]} #{data.unpack(le ? 'v*' : 'n*').map { |c| '%04X' % c }.join(' ')}"
763
804
  when 4; add_log "#{Expression[addr]} #{data.unpack(le ? 'V*' : 'N*').map { |c| '%08X' % c }.join(' ')}"
@@ -767,8 +808,12 @@ class DbgConsoleWidget < DrawableWidget
767
808
  len -= 16
768
809
  end
769
810
  else
770
- @parent_widget.mem.view(:hex).data_size = dlen if dlen
771
- @parent_widget.mem.focus_addr(solve_expr(addr)) if addr and addr != ''
811
+ if dlen
812
+ @parent_widget.mem.view(:hex).data_size = dlen
813
+ @parent_widget.mem.view(:hex).resized
814
+ @parent_widget.mem.showview(:hex)
815
+ end
816
+ @parent_widget.mem.focus_addr(solve_expr(addr))
772
817
  @parent_widget.mem.gui_update
773
818
  end
774
819
  end
@@ -783,6 +828,18 @@ class DbgConsoleWidget < DrawableWidget
783
828
  new_command('dw', 'dump/focus words in data window') { |arg| cmd_dd(arg, 2) }
784
829
  new_command('dd', 'dump/focus dwords in data window') { |arg| cmd_dd(arg, 4) }
785
830
  new_command('dq', 'dump/focus qwords in data window') { |arg| cmd_dd(arg, 8) }
831
+ new_command('dc', 'focus C struct in data window: <name> <addr>') { |arg|
832
+ name, addr = arg.strip.split(/\s+/, 2)
833
+ addr = (addr ? solve_expr(addr) : @parent_widget.mem.curaddr)
834
+ @parent_widget.mem.focus_addr(addr, :cstruct, false, name)
835
+ }
836
+ new_command('dC', 'dump C struct: dC <name> <addr>') { |arg|
837
+ name, addr = arg.strip.split(/\s+/, 2)
838
+ addr = (addr ? solve_expr(addr) : @parent_widget.mem.curaddr)
839
+ if st = @dbg.disassembler.c_parser.decode_c_struct(name, @dbg.memory, addr)
840
+ add_log st.to_s.gsub("\t", ' ')
841
+ end
842
+ }
786
843
  new_command('u', 'focus code window on an address') { |arg| p.code.focus_addr(solve_expr(arg)) }
787
844
  new_command('.', 'focus code window on current address') { p.code.focus_addr(solve_expr(@dbg.register_pc.to_s)) }
788
845
  new_command('wc', 'set code window height') { |arg|
@@ -828,12 +885,14 @@ class DbgConsoleWidget < DrawableWidget
828
885
  cb = lambda { a.split(';').each { |aaa| run_command(aaa) } } if a
829
886
  @dbg.bpx(solve_expr(e), o, cd, &cb)
830
887
  }
831
- new_command('hwbp', 'set a hardware breakpoint') { |arg|
832
- arg =~ /^(.*?)(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/i
833
- e, c, a = $1, ($2 || $4), $3
888
+ new_command('hwbp', 'set a hardware breakpoint (hwbp 0x2345 w)') { |arg|
889
+ arg =~ /^(.*?)( once)?( [rwx])?(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/i
890
+ e, o, t, c, a = $1, $2, $3, ($4 || $6), $5
891
+ o = o ? true : false
892
+ t = (t || 'x').strip.to_sym
834
893
  cd = parse_expr(c) if c
835
894
  cb = lambda { a.split(';').each { |aaa| run_command(aaa) } } if a
836
- @dbg.hwbp(solve_expr(e), :x, 1, false, cd, &cb)
895
+ @dbg.hwbp(solve_expr(e), t, 1, o, cd, &cb)
837
896
  }
838
897
  new_command('bpm', 'set a hardware memory breakpoint: bpm r 0x4800ff 16') { |arg|
839
898
  arg =~ /^(.*?)(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/i
@@ -846,7 +905,7 @@ class DbgConsoleWidget < DrawableWidget
846
905
  exp = solve_expr!(e)
847
906
  len = solve_expr(e) if e != ''
848
907
  len ||= 1
849
- @dbg.hwbp(exp, mode, len, false, cd, &cb)
908
+ @dbg.bpm(exp, mode, len, false, cd, &cb)
850
909
  }
851
910
  new_command('g', 'wait until target reaches the specified address') { |arg|
852
911
  arg =~ /^(.*?)(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/i
@@ -1038,7 +1097,7 @@ class DbgConsoleWidget < DrawableWidget
1038
1097
  add_log "#{t} #{stf[:state]} #{stf[:info]}"
1039
1098
  }
1040
1099
  }
1041
-
1100
+
1042
1101
  new_command('pid', 'select a pid') { |arg|
1043
1102
  if pid = solve_expr(arg)
1044
1103
  @dbg.pid = pid
@@ -1072,7 +1131,7 @@ class DbgConsoleWidget < DrawableWidget
1072
1131
  @dbg.ignore_newthread = false
1073
1132
  @dbg.ignore_endthread = false
1074
1133
  }
1075
- new_command('thread_event_ignore', 'ignore thread creation/termination') {
1134
+ new_command('thread_events_ignore', 'ignore thread creation/termination') {
1076
1135
  @dbg.ignore_newthread = true
1077
1136
  @dbg.ignore_endthread = true
1078
1137
  }
@@ -1101,6 +1160,12 @@ class DbgConsoleWidget < DrawableWidget
1101
1160
  @dbg.create_process(arg)
1102
1161
  }
1103
1162
 
1163
+ new_command('plugin', 'load', 'load a debugger plugin') { |arg|
1164
+ @dbg.load_plugin arg
1165
+ add_log "loaded plugin #{File.basename(arg, '.rb')}"
1166
+ }
1167
+
1168
+
1104
1169
  @dbg.ui_command_setup(self) if @dbg.respond_to? :ui_command_setup
1105
1170
  end
1106
1171
 
@@ -1122,12 +1187,13 @@ class DbgConsoleWidget < DrawableWidget
1122
1187
  end
1123
1188
 
1124
1189
  def run_command(cmd)
1190
+ cmd = cmd.sub(/^\s+/, '')
1125
1191
  cn = cmd.split.first
1126
1192
  if not @commands[cn]
1127
1193
  a = @commands.keys.find_all { |k| k[0, cn.length] == cn }
1128
1194
  cn = a.first if a.length == 1
1129
1195
  end
1130
- if pc = @commands[cn]
1196
+ if pc = @commands[cn]
1131
1197
  pc[cmd.split(/\s+/, 2)[1].to_s]
1132
1198
  else
1133
1199
  add_log 'unknown command'
@@ -145,7 +145,7 @@ end
145
145
  class DrawableWidget < Gtk::DrawingArea
146
146
  include Msgbox
147
147
 
148
- attr_accessor :parent_widget, :caret_x, :caret_y, :hl_word
148
+ attr_accessor :parent_widget, :caret_x, :caret_y, :hl_word, :hl_word_re
149
149
  # this hash is used to determine the colors of the Gui elements (background, caret, ...)
150
150
  # modifications to it are only useful before the widget is first rendered (IE before Gui.main)
151
151
  attr_accessor :default_color_association
@@ -153,7 +153,7 @@ class DrawableWidget < Gtk::DrawingArea
153
153
  # keypress event keyval traduction table
154
154
  Keyboard_trad = Gdk::Keyval.constants.grep(/^GDK_/).inject({}) { |h, cst|
155
155
  v = Gdk::Keyval.const_get(cst)
156
- key = cst.to_s.sub(/^GDK_/, '').sub(/^KP_/, '')
156
+ key = cst.to_s.sub(/^GDK_/, '').sub(/^KEY_/, '').sub(/^KP_/, '')
157
157
  if key.length == 1
158
158
  key = key[0] # ?a, ?b etc
159
159
  else
@@ -161,7 +161,7 @@ class DrawableWidget < Gtk::DrawingArea
161
161
  key = {
162
162
  :page_up => :pgup, :page_down => :pgdown, :next => :pgdown,
163
163
  :escape => :esc, :return => :enter, :l1 => :f11, :l2 => :f12,
164
- :prior => :pgup,
164
+ :prior => :pgup, :menu => :popupmenu,
165
165
 
166
166
  :space => ?\ ,
167
167
  :asciitilde => ?~, :quoteleft => ?`,
@@ -189,6 +189,15 @@ class DrawableWidget < Gtk::DrawingArea
189
189
  h.update v => key
190
190
  }
191
191
 
192
+ BasicColor = { :white => 'fff', :palegrey => 'ddd', :black => '000', :grey => '444',
193
+ :red => 'f44', :darkred => '800', :palered => 'faa',
194
+ :green => '4f4', :darkgreen => '080', :palegreen => 'afa',
195
+ :blue => '44f', :darkblue => '008', :paleblue => 'aaf',
196
+ :yellow => 'ff4', :darkyellow => '440', :paleyellow => 'ffa',
197
+ :orange => 'fc8',
198
+
199
+ }
200
+
192
201
  def initialize(*a, &b)
193
202
  @parent_widget = nil
194
203
 
@@ -226,7 +235,6 @@ class DrawableWidget < Gtk::DrawingArea
226
235
  grab_focus
227
236
  case ev.button
228
237
  when 1; protect { click(ev.x, ev.y) } if respond_to? :click
229
- when 3; protect { rightclick(ev.x, ev.y) } if respond_to? :rightclick
230
238
  end
231
239
  when Gdk::Event::Type::BUTTON2_PRESS
232
240
  case ev.button
@@ -245,8 +253,11 @@ class DrawableWidget < Gtk::DrawingArea
245
253
  } if respond_to? :mousemove
246
254
 
247
255
  signal_connect('button_release_event') { |w, ev|
248
- protect { mouserelease(ev.x, ev.y) } if ev.button == 1
249
- } if respond_to? :mouserelease
256
+ case ev.button
257
+ when 1; protect { mouserelease(ev.x, ev.y) } if respond_to? :mouserelease
258
+ when 3; protect { rightclick(ev.x, ev.y) } if respond_to? :rightclick
259
+ end
260
+ }
250
261
 
251
262
  signal_connect('scroll_event') { |w, ev|
252
263
  dir = case ev.direction
@@ -273,12 +284,7 @@ class DrawableWidget < Gtk::DrawingArea
273
284
  }
274
285
 
275
286
  signal_connect('realize') {
276
- { :white => 'fff', :palegrey => 'ddd', :black => '000', :grey => '444',
277
- :red => 'f00', :darkred => '800', :palered => 'fcc',
278
- :green => '0f0', :darkgreen => '080', :palegreen => 'cfc',
279
- :blue => '00f', :darkblue => '008', :paleblue => 'ccf',
280
- :yellow => 'ff0', :darkyellow => '440', :paleyellow => 'ffc',
281
- }.each { |tag, val|
287
+ BasicColor.each { |tag, val|
282
288
  @color[tag] = color(val)
283
289
  }
284
290
 
@@ -302,7 +308,11 @@ class DrawableWidget < Gtk::DrawingArea
302
308
  # create a color from a 'rgb' description
303
309
  def color(val)
304
310
  if not @color[val]
305
- @color[val] = Gdk::Color.new(*val.unpack('CCC').map { |c| (c.chr*4).hex })
311
+ v = case val.length
312
+ when 3; val.scan(/./).map { |c| (c*4).to_i(16) }
313
+ when 6; val.scan(/../).map { |c| (c+c).to_i(16) }
314
+ end
315
+ @color[val] = Gdk::Color.new(*v)
306
316
  window.colormap.alloc_color(@color[val], true, true)
307
317
  end
308
318
  @color[val]
@@ -325,20 +335,48 @@ class DrawableWidget < Gtk::DrawingArea
325
335
 
326
336
  # change the color association
327
337
  # arg is a hash function symbol => color symbol
328
- # color must be allocated
329
338
  # check #initialize/sig('realize') for initial function/color list
339
+ # if called before the widget is first displayed onscreen, will register a hook to re-call itself later
330
340
  def set_color_association(hash)
331
- hash.each { |k, v| @color[k] = color(v) }
332
- modify_bg Gtk::STATE_NORMAL, @color[:background]
333
- gui_update
341
+ if not realized?
342
+ sid = signal_connect('realize') {
343
+ signal_handler_disconnect(sid)
344
+ set_color_association(hash)
345
+ }
346
+ else
347
+ hord = Hash.new { |h, k| h[k] = (hash[k] ? h[hash[k]] + 1 : 0) }
348
+ hash.sort_by { |k, v| hord[k] }.each { |k, v| @color[k] = color(v) }
349
+ modify_bg Gtk::STATE_NORMAL, @color[:background]
350
+ gui_update
351
+ end
352
+ end
353
+
354
+ def new_menu
355
+ toplevel.new_menu
356
+ end
357
+ def addsubmenu(*a, &b)
358
+ toplevel.addsubmenu(*a, &b)
359
+ end
360
+ def popupmenu(m, x, y)
361
+ toplevel.popupmenu(m, (x+allocation.x).to_i, (y+allocation.y).to_i)
334
362
  end
335
363
 
336
364
  # update @hl_word from a line & offset, return nil if unchanged
337
- def update_hl_word(line, offset)
365
+ def update_hl_word(line, offset, mode=:asm)
338
366
  return if not line
339
367
  word = line[0...offset].to_s[/\w*$/] << line[offset..-1].to_s[/^\w*/]
340
368
  word = nil if word == ''
341
- @hl_word = word if @hl_word != word
369
+ if @hl_word != word
370
+ if word
371
+ if mode == :asm and defined?(@dasm) and @dasm
372
+ re = @dasm.gui_hilight_word_regexp(word)
373
+ else
374
+ re = Regexp.escape word
375
+ end
376
+ @hl_word_re = /^(.*?)(\b(?:#{re})\b)/
377
+ end
378
+ @hl_word = word
379
+ end
342
380
  end
343
381
 
344
382
  def paint
@@ -385,6 +423,20 @@ class DrawableWidget < Gtk::DrawingArea
385
423
  end
386
424
 
387
425
  def draw_rectangle(x, y, w, h)
426
+ # GTK clips coords around 0x8000
427
+ return if x > 0x7000 or y > 0x7000
428
+ if x < -0x7000
429
+ w += x + 100
430
+ x = -100
431
+ end
432
+ if y < -0x7000
433
+ h += y + 100
434
+ y = -100
435
+ end
436
+ return if w <= 0 or h <= 0
437
+ w = 0x7000 if w > 0x7000
438
+ h = 0x7000 if h > 0x7000
439
+
388
440
  @w.draw_rectangle(@gc, true, x, y, w, h)
389
441
  end
390
442
 
@@ -394,6 +446,29 @@ class DrawableWidget < Gtk::DrawingArea
394
446
  end
395
447
 
396
448
  def draw_line(x, y, ex, ey)
449
+ if x.abs > 0x7000
450
+ return if ex.abs > 0x7000 and ((ex < 0) == (x < 0))
451
+ ox = x
452
+ x = ((x > 0) ? 0x7000 : -0x7000)
453
+ y = ey+(x-ex)*(y-ey)/(ox-ex)
454
+ end
455
+ if ex.abs > 0x7000
456
+ oex = ex
457
+ ex = ((ex > 0) ? 0x7000 : -0x7000)
458
+ ey = y+(ex-x)*(ey-y)/(oex-x)
459
+ end
460
+ if y.abs > 0x7000
461
+ return if ey.abs > 0x7000 and ((ey < 0) == (y < 0))
462
+ oy = y
463
+ y = ((y > 0) ? 0x7000 : -0x7000)
464
+ x = ex+(y-ey)*(x-ex)/(oy-ey)
465
+ end
466
+ if ey.abs > 0x7000
467
+ oey = ey
468
+ ey = ((ey > 0) ? 0x7000 : -0x7000)
469
+ ex = x+(ey-y)*(ex-x)/(oey-y)
470
+ end
471
+
397
472
  @w.draw_line(@gc, x, y, ex, ey)
398
473
  end
399
474
 
@@ -403,6 +478,7 @@ class DrawableWidget < Gtk::DrawingArea
403
478
  end
404
479
 
405
480
  def draw_string(x, y, str)
481
+ return if x.abs > 0x7000 or y.abs > 0x7000
406
482
  @layout.text = str
407
483
  @w.draw_layout(@gc, x, y, @layout)
408
484
  end
@@ -412,6 +488,23 @@ class DrawableWidget < Gtk::DrawingArea
412
488
  draw_string(x, y, str)
413
489
  end
414
490
 
491
+ # same as draw_string_color + hilight @hl_word_re
492
+ def draw_string_hl(col, x, y, str)
493
+ if @hl_word
494
+ while str =~ @hl_word_re
495
+ s1, s2 = $1, $2
496
+ draw_string_color(col, x, y, s1)
497
+ x += s1.length*@font_width
498
+ hl_w = s2.length*@font_width
499
+ draw_rectangle_color(:hl_word_bg, x, y, hl_w, @font_height)
500
+ draw_string_color(:hl_word, x, y, s2)
501
+ x += hl_w
502
+ str = str[s1.length+s2.length..-1]
503
+ end
504
+ end
505
+ draw_string_color(col, x, y, str)
506
+ end
507
+
415
508
  def clipboard_copy(buf)
416
509
  clipboard = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
417
510
  clipboard.text = buf
@@ -477,15 +570,35 @@ class InputBox < Gtk::Dialog
477
570
  @textwidget = Gtk::TextView.new
478
571
  if opts[:text]
479
572
  @textwidget.buffer.text = opts[:text].to_s
480
- @textwidget.buffer.move_mark('selection_bound', @textwidget.buffer.start_iter)
481
- @textwidget.buffer.move_mark('insert', @textwidget.buffer.end_iter)
573
+ text_select_all
482
574
  end
483
575
 
576
+ @@history ||= {}
577
+ histkey = opts[:history] || str[0, 10]
578
+ @history = (@@history[histkey] ||= [])
579
+ @history_off = @history.length
580
+
484
581
  @textwidget.signal_connect('key_press_event') { |w, ev|
485
582
  key = DrawableWidget::Keyboard_trad[ev.keyval]
486
583
  case key
487
- when :escape; response(RESPONSE_REJECT) ; true
488
- when :enter; response(RESPONSE_ACCEPT) ; true
584
+ when :escape
585
+ response(RESPONSE_REJECT)
586
+ true
587
+ when :enter
588
+ @history << @textwidget.buffer.text.to_s
589
+ @history.pop if @history.last == ''
590
+ @history.pop if @history.last == @history[-2]
591
+ response(RESPONSE_ACCEPT)
592
+ true
593
+ when :up, :down
594
+ txt = @textwidget.buffer.text.to_s
595
+ if (@history_off < @history.length or @history.last != txt)
596
+ @history[@history_off] = txt
597
+ end
598
+ @history_off += (key == :up ? -1 : 1)
599
+ @history_off %= @history.length
600
+ @textwidget.buffer.text = @history[@history_off].to_s
601
+ text_select_all
489
602
  end
490
603
  }
491
604
 
@@ -502,9 +615,9 @@ class InputBox < Gtk::Dialog
502
615
  Gtk::Drag.dest_set(self,
503
616
  Gtk::Drag::DEST_DEFAULT_MOTION |
504
617
  Gtk::Drag::DEST_DEFAULT_DROP,
505
- [['text/plain', 0, 0], ['text/uri-list', 0, 0]],
618
+ [['text/plain', 0, 0], ['text/uri-list', 0, 0]],
506
619
  Gdk::DragContext::ACTION_COPY | Gdk::DragContext::ACTION_MOVE)
507
-
620
+
508
621
  signal_connect('drag_data_received') { |w, dc, x, y, data, info, time|
509
622
  dc.targets.each { |target|
510
623
  next if target.name != 'text/plain' and target.name != 'text/uri-list'
@@ -521,6 +634,11 @@ class InputBox < Gtk::Dialog
521
634
  present
522
635
  end
523
636
 
637
+ def text_select_all
638
+ @textwidget.buffer.move_mark('selection_bound', @textwidget.buffer.start_iter)
639
+ @textwidget.buffer.move_mark('insert', @textwidget.buffer.end_iter)
640
+ end
641
+
524
642
  def text ; @textwidget.buffer.text ; end
525
643
  def text=(nt) ; @textwidget.buffer.text = nt ; end
526
644
  end
@@ -604,7 +722,7 @@ class ListWindow < Gtk::Dialog
604
722
  tvc = Gtk::TreeViewColumn.new(col, crt)
605
723
  tvc.sort_column_id = i
606
724
  tvc.set_cell_data_func(crt) { |_tvc, _crt, model, iter|
607
- _crt.text = iter[i]
725
+ _crt.text = iter[i]
608
726
  if @color_callback
609
727
  fu = (0...cols.length).map { |ii| iter[ii] }
610
728
  fg, bg = @color_callback[fu]
@@ -635,7 +753,7 @@ class ListWindow < Gtk::Dialog
635
753
 
636
754
  remove vbox
637
755
  add Gtk::ScrolledWindow.new.add(treeview)
638
- toplevel.set_default_size cols.length*120, 400
756
+ toplevel.set_default_size cols.length*240, 400
639
757
 
640
758
  show if not h[:noshow]
641
759
 
@@ -666,6 +784,7 @@ class Window < Gtk::Window
666
784
  @menubar = Gtk::MenuBar.new
667
785
  @accel_group = Gtk::AccelGroup.new
668
786
 
787
+ set_gravity Gdk::Window::GRAVITY_STATIC
669
788
  @vbox.add @menubar, 'expand' => false
670
789
  @child = nil
671
790
  s = Gdk::Screen.default
@@ -678,14 +797,13 @@ class Window < Gtk::Window
678
797
  initialize_window(*a, &b)
679
798
  build_menu
680
799
  update_menu
681
-
682
-
800
+
683
801
  Gtk::Drag.dest_set(self,
684
802
  Gtk::Drag::DEST_DEFAULT_MOTION |
685
803
  Gtk::Drag::DEST_DEFAULT_DROP,
686
- [['text/plain', 0, 0], ['text/uri-list', 0, 0]],
804
+ [['text/plain', 0, 0], ['text/uri-list', 0, 0]],
687
805
  Gdk::DragContext::ACTION_COPY | Gdk::DragContext::ACTION_MOVE)
688
-
806
+
689
807
  signal_connect('drag_data_received') { |w, dc, x, y, data, info, time|
690
808
  dc.targets.each { |target|
691
809
  next if target.name != 'text/plain' and target.name != 'text/uri-list'
@@ -734,6 +852,13 @@ class Window < Gtk::Window
734
852
  l.grep(::Array).first if l
735
853
  end
736
854
 
855
+ def popupmenu(m, x, y)
856
+ mh = Gtk::Menu.new
857
+ m.each { |e| create_menu_item(mh, e) }
858
+ mh.show_all
859
+ mh.popup(nil, nil, 2, 0) { |_m, _x, _y, _p| [position[0]+x, position[1]+y, true] }
860
+ end
861
+
737
862
  # append stuff to a menu
738
863
  # arglist:
739
864
  # empty = menu separator
@@ -801,13 +926,10 @@ class Window < Gtk::Window
801
926
  key = accel[-1]
802
927
  if key == ?>
803
928
  key = accel[/<(.*)>/, 1]
804
- key = case key
805
- when 'enter'; Gdk::Keyval::GDK_Return
806
- when 'esc'; Gdk::Keyval::GDK_Escape
807
- when 'tab'; Gdk::Keyval::GDK_Tab
808
- when /^f(\d\d?)$/i; Gdk::Keyval.const_get("GDK_#{key.upcase}")
809
- else ??
810
- end
929
+ key = DrawableWidget::Keyboard_trad.index(case key
930
+ when 'enter', 'esc', 'tab', /^f(\d\d?)$/i; key.downcase.to_sym
931
+ else ??
932
+ end)
811
933
  end
812
934
  key = key.unpack('C')[0] if key.kind_of? String # yay rb19
813
935
  item.add_accelerator('activate', @accel_group, key, (accel[0] == ?^ ? Gdk::Window::CONTROL_MASK : 0), Gtk::ACCEL_VISIBLE)
@@ -815,7 +937,7 @@ class Window < Gtk::Window
815
937
  if action
816
938
  a = action
817
939
  if check
818
- a = lambda { item.active = action.call(item.active?) }
940
+ a = lambda { |it| it.active = action.call(it.active?) }
819
941
  end
820
942
  item.signal_connect('activate') { protect { a.call(item) } }
821
943
  end
@@ -838,7 +960,7 @@ class ToolWindow < Gtk::Dialog
838
960
  initialize_window(*a, &b)
839
961
  show_all
840
962
  end
841
-
963
+
842
964
  def widget=(w)
843
965
  remove @child if @child
844
966
  @child = w