metasm 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.hgtags +3 -0
- data/Gemfile +1 -0
- data/INSTALL +61 -0
- data/LICENCE +458 -0
- data/README +29 -21
- data/Rakefile +10 -0
- data/TODO +10 -12
- data/doc/code_organisation.txt +2 -0
- data/doc/core/DynLdr.txt +247 -0
- data/doc/core/ExeFormat.txt +43 -0
- data/doc/core/Expression.txt +220 -0
- data/doc/core/GNUExports.txt +27 -0
- data/doc/core/Ia32.txt +236 -0
- data/doc/core/SerialStruct.txt +108 -0
- data/doc/core/VirtualString.txt +145 -0
- data/doc/core/WindowsExports.txt +61 -0
- data/doc/core/index.txt +1 -0
- data/doc/style.css +6 -3
- data/doc/usage/debugger.txt +327 -0
- data/doc/usage/index.txt +1 -0
- data/doc/use_cases.txt +2 -2
- data/metasm.gemspec +22 -0
- data/{lib/metasm.rb → metasm.rb} +11 -3
- data/{lib/metasm → metasm}/compile_c.rb +13 -7
- data/metasm/cpu/arc.rb +8 -0
- data/metasm/cpu/arc/decode.rb +425 -0
- data/metasm/cpu/arc/main.rb +191 -0
- data/metasm/cpu/arc/opcodes.rb +588 -0
- data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
- data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
- data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
- data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
- data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
- data/metasm/cpu/arm/opcodes.rb +324 -0
- data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
- data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
- data/metasm/cpu/arm64.rb +15 -0
- data/metasm/cpu/arm64/debug.rb +38 -0
- data/metasm/cpu/arm64/decode.rb +289 -0
- data/metasm/cpu/arm64/encode.rb +41 -0
- data/metasm/cpu/arm64/main.rb +105 -0
- data/metasm/cpu/arm64/opcodes.rb +232 -0
- data/metasm/cpu/arm64/parse.rb +20 -0
- data/metasm/cpu/arm64/render.rb +95 -0
- data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
- data/metasm/cpu/bpf/decode.rb +142 -0
- data/metasm/cpu/bpf/main.rb +60 -0
- data/metasm/cpu/bpf/opcodes.rb +81 -0
- data/metasm/cpu/bpf/render.rb +41 -0
- data/metasm/cpu/cy16.rb +9 -0
- data/metasm/cpu/cy16/decode.rb +253 -0
- data/metasm/cpu/cy16/main.rb +63 -0
- data/metasm/cpu/cy16/opcodes.rb +78 -0
- data/metasm/cpu/cy16/render.rb +41 -0
- data/metasm/cpu/dalvik.rb +11 -0
- data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
- data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
- data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
- data/metasm/cpu/ia32.rb +17 -0
- data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
- data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
- data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
- data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
- data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
- data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
- data/metasm/cpu/ia32/opcodes.rb +1424 -0
- data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
- data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
- data/metasm/cpu/mips.rb +14 -0
- data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
- data/metasm/cpu/mips/debug.rb +42 -0
- data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
- data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
- data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
- data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
- data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
- data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
- data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
- data/metasm/cpu/msp430/decode.rb +247 -0
- data/metasm/cpu/msp430/main.rb +62 -0
- data/metasm/cpu/msp430/opcodes.rb +101 -0
- data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
- data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
- data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
- data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
- data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
- data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
- data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
- data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
- data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
- data/metasm/cpu/ppc/parse.rb +55 -0
- data/metasm/cpu/python.rb +8 -0
- data/metasm/cpu/python/decode.rb +136 -0
- data/metasm/cpu/python/main.rb +36 -0
- data/metasm/cpu/python/opcodes.rb +180 -0
- data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
- data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
- data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
- data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
- data/metasm/cpu/x86_64.rb +15 -0
- data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
- data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
- data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
- data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
- data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
- data/metasm/cpu/x86_64/opcodes.rb +136 -0
- data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
- data/metasm/cpu/x86_64/render.rb +35 -0
- data/metasm/cpu/z80.rb +9 -0
- data/metasm/cpu/z80/decode.rb +313 -0
- data/metasm/cpu/z80/main.rb +67 -0
- data/metasm/cpu/z80/opcodes.rb +224 -0
- data/metasm/cpu/z80/render.rb +59 -0
- data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
- data/{lib/metasm → metasm}/decode.rb +35 -4
- data/{lib/metasm → metasm}/decompile.rb +15 -16
- data/{lib/metasm → metasm}/disassemble.rb +201 -45
- data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
- data/{lib/metasm → metasm}/dynldr.rb +220 -133
- data/{lib/metasm → metasm}/encode.rb +10 -1
- data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
- data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
- data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
- data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
- data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
- data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
- data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
- data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
- data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
- data/metasm/exe_format/gb.rb +65 -0
- data/metasm/exe_format/javaclass.rb +424 -0
- data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
- data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
- data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
- data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
- data/metasm/exe_format/pyc.rb +167 -0
- data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
- data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
- data/metasm/exe_format/shellcode_rwx.rb +114 -0
- data/metasm/exe_format/swf.rb +205 -0
- data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
- data/metasm/exe_format/zip.rb +335 -0
- data/metasm/gui.rb +13 -0
- data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
- data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
- data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
- data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
- data/metasm/gui/dasm_graph.rb +1695 -0
- data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
- data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
- data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
- data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
- data/{lib/metasm → metasm}/gui/debug.rb +93 -27
- data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
- data/{lib/metasm → metasm}/gui/qt.rb +12 -2
- data/{lib/metasm → metasm}/gui/win32.rb +179 -42
- data/{lib/metasm → metasm}/gui/x11.rb +59 -59
- data/{lib/metasm → metasm}/main.rb +389 -264
- data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
- data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
- data/{lib/metasm → metasm}/os/linux.rb +628 -151
- data/metasm/os/main.rb +330 -0
- data/{lib/metasm → metasm}/os/windows.rb +132 -42
- data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
- data/{lib/metasm → metasm}/parse.rb +26 -24
- data/{lib/metasm → metasm}/parse_c.rb +221 -116
- data/{lib/metasm → metasm}/preprocessor.rb +55 -40
- data/{lib/metasm → metasm}/render.rb +14 -38
- data/misc/hexdump.rb +2 -1
- data/misc/lint.rb +58 -0
- data/misc/txt2html.rb +9 -7
- data/samples/bindiff.rb +3 -4
- data/samples/dasm-plugins/bindiff.rb +15 -0
- data/samples/dasm-plugins/bookmark.rb +133 -0
- data/samples/dasm-plugins/c_constants.rb +57 -0
- data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
- data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
- data/samples/dasm-plugins/dasm_all.rb +70 -0
- data/samples/dasm-plugins/demangle_cpp.rb +31 -0
- data/samples/dasm-plugins/deobfuscate.rb +251 -0
- data/samples/dasm-plugins/dump_text.rb +35 -0
- data/samples/dasm-plugins/export_graph_svg.rb +86 -0
- data/samples/dasm-plugins/findgadget.rb +75 -0
- data/samples/dasm-plugins/hl_opcode.rb +32 -0
- data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
- data/samples/dasm-plugins/imm2off.rb +34 -0
- data/samples/dasm-plugins/match_libsigs.rb +93 -0
- data/samples/dasm-plugins/patch_file.rb +95 -0
- data/samples/dasm-plugins/scanfuncstart.rb +36 -0
- data/samples/dasm-plugins/scanxrefs.rb +26 -0
- data/samples/dasm-plugins/selfmodify.rb +197 -0
- data/samples/dasm-plugins/stringsxrefs.rb +28 -0
- data/samples/dasmnavig.rb +1 -1
- data/samples/dbg-apihook.rb +24 -9
- data/samples/dbg-plugins/heapscan.rb +283 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
- data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
- data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
- data/samples/dbg-plugins/heapscan/winheap.h +174 -0
- data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
- data/samples/dbg-plugins/trace_func.rb +214 -0
- data/samples/disassemble-gui.rb +35 -5
- data/samples/disassemble.rb +31 -6
- data/samples/dump_upx.rb +24 -12
- data/samples/dynamic_ruby.rb +12 -3
- data/samples/exeencode.rb +6 -5
- data/samples/factorize-headers-peimports.rb +1 -1
- data/samples/lindebug.rb +175 -381
- data/samples/metasm-shell.rb +1 -2
- data/samples/peldr.rb +2 -2
- data/tests/all.rb +1 -1
- data/tests/arc.rb +26 -0
- data/tests/dynldr.rb +22 -4
- data/tests/expression.rb +55 -0
- data/tests/graph_layout.rb +285 -0
- data/tests/ia32.rb +79 -26
- data/tests/mips.rb +9 -2
- data/tests/x86_64.rb +66 -18
- metadata +330 -218
- data/lib/metasm/arm/opcodes.rb +0 -177
- data/lib/metasm/gui.rb +0 -23
- data/lib/metasm/gui/dasm_graph.rb +0 -1354
- data/lib/metasm/ia32.rb +0 -14
- data/lib/metasm/ia32/opcodes.rb +0 -873
- data/lib/metasm/ppc/parse.rb +0 -52
- data/lib/metasm/x86_64.rb +0 -12
- data/lib/metasm/x86_64/opcodes.rb +0 -118
- data/samples/gdbclient.rb +0 -583
- 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 =
|
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
|
-
|
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
|
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
|
-
|
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|
|
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 =
|
226
|
-
|
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 =
|
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
|
-
|
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
|
-
|
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("
|
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
|
-
|
771
|
-
|
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,
|
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),
|
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.
|
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('
|
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
|
-
|
249
|
-
|
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
|
-
{
|
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
|
-
|
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
|
-
|
332
|
-
|
333
|
-
|
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
|
-
|
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
|
-
|
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
|
488
|
-
|
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
|
-
|
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
|
-
|
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*
|
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
|
-
|
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
|
-
|
806
|
-
|
807
|
-
|
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 {
|
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
|