2
2
"use strict" ;
3
3
4
4
const Util = {
5
- get_table : function ( thead , data ) {
5
+ get_table : function ( columns , data ) {
6
6
var result = [ "<table class='table table-striped table-bordered table-condensed'>" ] ;
7
7
result . push ( "<thead>" ) ;
8
8
result . push ( "<tr>" ) ;
9
- for ( let h of thead ) {
9
+ for ( let h of columns ) {
10
10
result . push ( `<th>${ h } </th>` ) ;
11
11
}
12
12
result . push ( "</tr>" ) ;
@@ -23,9 +23,27 @@ const Util = {
23
23
result . push ( "</table>" ) ;
24
24
return result . join ( '\n' ) ;
25
25
} ,
26
+ get_table_data : function ( objs ) {
27
+ // put keys of all objects into array
28
+ let all_keys = _ . flatten ( objs . map ( i => _ . keys ( i ) ) )
29
+ let columns = _ . uniq ( _ . flatten ( all_keys ) ) . sort ( )
30
+
31
+ let data = [ ]
32
+ for ( let s of objs ) {
33
+ let row = [ ]
34
+ for ( let k of columns ) {
35
+ row . push ( k in s ? s [ k ] : '' )
36
+ }
37
+ data . push ( row )
38
+ }
39
+ return [ columns , data ]
40
+ } ,
26
41
post_msg : function ( data ) {
27
- App . set_status ( _ . escape ( data . responseJSON . message ) )
28
- // Messenger().post(_.escape(data.responseJSON.message))
42
+ if ( data . responseJSON && data . responseJSON . message ) {
43
+ App . set_status ( _ . escape ( data . responseJSON . message ) )
44
+ } else {
45
+ App . set_status ( `${ data . statusText } (${ data . status } error)` )
46
+ }
29
47
} ,
30
48
escape : function ( s ) {
31
49
return s . replace ( / ( [ ^ \\ ] \\ n ) / g, '<br>' )
@@ -42,6 +60,8 @@ const Consts = {
42
60
43
61
jq_gdb_command_input : $ ( '#gdb_command' ) ,
44
62
jq_binary : $ ( '#binary' ) ,
63
+ jq_source_file_input : $ ( '#source_file_input' ) ,
64
+ jq_source_files_datalist : $ ( '#source_files_datalist' ) ,
45
65
jq_code : $ ( '#code_table' ) ,
46
66
jq_code_container : $ ( '#code_container' ) ,
47
67
js_gdb_controls : $ ( '.gdb_controls' ) ,
@@ -62,32 +82,36 @@ let App = {
62
82
init : function ( ) {
63
83
App . register_events ( ) ;
64
84
65
- Consts . jq_binary . val ( localStorage . getItem ( 'last_binary' ) )
66
85
try {
67
- App . state . history = JSON . parse ( localStorage . getItem ( 'history' ) )
86
+ App . state . past_binaries = _ . uniq ( JSON . parse ( localStorage . getItem ( 'past_binaries' ) ) )
87
+ Consts . jq_binary . val ( App . state . past_binaries [ 0 ] )
88
+ } catch ( err ) {
89
+ App . state . past_binaries = [ ]
90
+ }
91
+ App . render_past_binary_options_datalist ( )
92
+
93
+ try {
94
+ App . state . history = _ . uniq ( JSON . parse ( localStorage . getItem ( 'history' ) ) )
68
95
} catch ( err ) {
69
96
App . state . history = [ ]
70
97
}
71
- if ( _ . isArray ( App . state . history ) ) {
72
- App . state . history . map ( App . show_in_history_table )
73
- }
98
+ App . render_history_table ( )
74
99
} ,
75
100
onclose : function ( ) {
76
- console . log ( JSON . stringify ( App . state . history ) )
77
- console . log ( JSON . stringify ( App . state . history ) )
78
- console . log ( JSON . stringify ( App . state . history ) )
79
- localStorage . setItem ( 'last_binary' , Consts . jq_binary . val ( ) )
80
- localStorage . setItem ( 'history' , JSON . stringify ( App . state . history ) )
101
+ localStorage . setItem ( 'past_binaries' , JSON . stringify ( App . state . past_binaries ) || [ ] )
102
+ localStorage . setItem ( 'history' , JSON . stringify ( App . state . history ) || [ ] )
81
103
return null
82
104
} ,
83
105
set_status : function ( status ) {
84
106
Consts . jq_status . text ( status )
85
107
} ,
86
108
state : { 'breakpoints' : [ ] , // list of breakpoints
87
- 'source_files' : [ ] , // list of absolute paths, and their contents
109
+ 'source_files' : [ ] , // list of absolute paths
110
+ 'cached_source_files' : [ ] , // list of absolute paths, and their source code
88
111
'frame' : { } , // current "frame" in gdb. Has keys: line, fullname (path to file), among others.
89
112
'rendered_source_file' : { 'fullname' : null , 'line' : null } , // current source file displayed
90
- 'history' : [ ]
113
+ 'history' : [ ] ,
114
+ 'past_binaries' : [ ] ,
91
115
} ,
92
116
clear_state : function ( ) {
93
117
App . state = {
@@ -114,13 +138,45 @@ let App = {
114
138
}
115
139
) ;
116
140
$ ( '.gdb_cmd' ) . click ( function ( e ) { App . click_gdb_cmd_button ( e ) } ) ;
141
+ Consts . jq_source_file_input . keyup ( function ( e ) { App . keyup_source_file_input ( e ) } ) ;
117
142
$ ( '.clear_history' ) . click ( function ( e ) { App . clear_history ( e ) } ) ;
118
143
$ ( '.clear_console' ) . click ( function ( e ) { App . clear_console ( e ) } ) ;
144
+ $ ( '.get_gdb_response' ) . click ( function ( e ) { App . get_gdb_response ( e ) } ) ;
119
145
$ ( "body" ) . on ( "click" , ".breakpoint" , App . click_breakpoint ) ;
120
146
$ ( "body" ) . on ( "click" , ".no_breakpoint" , App . click_source_file_gutter_with_no_breakpoint ) ;
121
147
$ ( "body" ) . on ( "click" , ".sent_command" , App . click_sent_command ) ;
122
148
$ ( "body" ) . on ( "click" , ".resizer" , App . click_resizer_button ) ;
149
+
123
150
Consts . jq_refresh_disassembly_button . click ( App . refresh_disassembly ) ;
151
+ App . init_autocomplete ( )
152
+
153
+
154
+ } ,
155
+ init_autocomplete : function ( ) {
156
+
157
+ App . autocomplete_source_file_input = new Awesomplete ( '#source_file_input' , {
158
+ minChars : 0 ,
159
+ maxItems : 10000 ,
160
+ list : [ ] ,
161
+ sort : ( a , b ) => { return a < b ? - 1 : 1 ; }
162
+ } ) ;
163
+
164
+ Awesomplete . $ ( '.dropdown-btn' ) . addEventListener ( "click" , function ( ) {
165
+ if ( App . autocomplete_source_file_input . ul . childNodes . length === 0 ) {
166
+ App . autocomplete_source_file_input . minChars = 0 ;
167
+ App . autocomplete_source_file_input . evaluate ( ) ;
168
+ }
169
+ else if ( App . autocomplete_source_file_input . ul . hasAttribute ( 'hidden' ) ) {
170
+ App . autocomplete_source_file_input . open ( ) ;
171
+ }
172
+ else {
173
+ App . autocomplete_source_file_input . close ( ) ;
174
+ }
175
+ } )
176
+
177
+ Awesomplete . $ ( '#source_file_input' ) . addEventListener ( 'awesomplete-selectcomplete' , function ( e ) {
178
+ App . read_and_render_file ( e . currentTarget . value )
179
+ } ) ;
124
180
125
181
} ,
126
182
refresh_disassembly : function ( e ) {
@@ -137,8 +193,13 @@ let App = {
137
193
} ,
138
194
click_set_target_app_button : function ( e ) {
139
195
var binary = Consts . jq_binary . val ( ) ;
140
- App . run_gdb_command ( `file ${ binary } ` ) ;
141
- App . enable_gdb_controls ( ) ;
196
+ _ . remove ( App . state . past_binaries , i => i === binary )
197
+ App . state . past_binaries . unshift ( binary )
198
+ App . render_past_binary_options_datalist ( )
199
+ App . run_gdb_command ( `-file-exec-and-symbols ${ binary } ` ) ;
200
+ } ,
201
+ render_past_binary_options_datalist : function ( ) {
202
+ $ ( '#past_binaries' ) . html ( App . state . past_binaries . map ( b => `<option>${ b } </option` ) )
142
203
} ,
143
204
keydown_on_binary_input : function ( e ) {
144
205
if ( e . keyCode === 13 ) {
@@ -163,7 +224,6 @@ let App = {
163
224
}
164
225
} ,
165
226
click_resizer_button : function ( e ) {
166
- console . log ( e )
167
227
let jq_selection = $ ( e . currentTarget . dataset [ 'target_selector' ] )
168
228
let cur_height = jq_selection . height ( )
169
229
if ( e . currentTarget . dataset [ 'resize_type' ] === 'enlarge' ) {
@@ -205,9 +265,9 @@ let App = {
205
265
return
206
266
}
207
267
208
- App . set_status ( '' )
268
+ App . set_status ( `running command " ${ cmd } "` )
209
269
App . save_to_history ( cmd )
210
- App . show_in_history_table ( cmd )
270
+ App . render_history_table ( )
211
271
$ . ajax ( {
212
272
url : "/run_gdb_command" ,
213
273
cache : false ,
@@ -217,6 +277,15 @@ let App = {
217
277
error : Util . post_msg
218
278
} )
219
279
} ,
280
+ get_gdb_response : function ( ) {
281
+ App . set_status ( `Getting GDB response` )
282
+ $ . ajax ( {
283
+ url : "/get_gdb_response" ,
284
+ cache : false ,
285
+ success : App . receive_gdb_response ,
286
+ error : Util . post_msg
287
+ } )
288
+ } ,
220
289
clear_history : function ( ) {
221
290
App . state . history = [ ]
222
291
Consts . jq_command_history . html ( '' )
@@ -226,13 +295,15 @@ let App = {
226
295
} ,
227
296
save_to_history : function ( cmd ) {
228
297
if ( _ . isArray ( App . state . history ) ) {
229
- App . state . history . push ( cmd )
298
+ _ . remove ( App . state . history , i => i === cmd )
299
+ App . state . history . unshift ( cmd )
230
300
} else {
231
301
App . state . history = [ cmd ]
232
302
}
233
303
} ,
234
- show_in_history_table : function ( cmd ) {
235
- Consts . jq_command_history . prepend ( `<tr><td class="sent_command pointer" data-cmd="${ cmd } " style="padding: 0">${ cmd } </td></tr>` )
304
+ render_history_table : function ( ) {
305
+ let history_html = App . state . history . map ( cmd => `<tr><td class="sent_command pointer" data-cmd="${ cmd } " style="padding: 0">${ cmd } </td></tr>` )
306
+ Consts . jq_command_history . html ( history_html )
236
307
} ,
237
308
receive_gdb_response : function ( response_array ) {
238
309
const text_class = {
@@ -274,14 +345,21 @@ let App = {
274
345
App . render_cached_source_file ( ) ;
275
346
} else if ( 'stack' in r . payload ) {
276
347
App . render_stack ( r . payload . stack )
348
+
277
349
} else if ( 'register-values' in r . payload ) {
278
350
if ( App . register_names ) {
279
351
App . render_registers ( App . register_names , r . payload [ 'register-values' ] )
280
352
}
281
353
} else if ( 'register-names' in r . payload ) {
282
354
App . register_names = r . payload [ 'register-names' ]
355
+
283
356
} else if ( 'asm_insns' in r . payload ) {
284
357
App . render_disasembly ( r . payload . asm_insns )
358
+
359
+ } else if ( 'files' in r . payload ) {
360
+ App . source_files = _ . uniq ( r . payload . files . map ( f => f . fullname ) ) . sort ( )
361
+ App . autocomplete_source_file_input . list = App . source_files
362
+ App . autocomplete_source_file_input . evaluate ( )
285
363
}
286
364
287
365
} else if ( r . payload && typeof r . payload . frame !== 'undefined' ) {
@@ -307,20 +385,30 @@ let App = {
307
385
if ( r . message ) {
308
386
status . push ( r . message )
309
387
}
310
- if ( r . payload && r . payload . msg ) {
311
- status . push ( r . payload . msg )
312
- }
313
- if ( r . payload && r . payload . reason ) {
314
- status . push ( r . payload . reason )
388
+ if ( r . payload ) {
389
+ if ( r . payload . msg ) { status . push ( r . payload . msg ) }
390
+ if ( r . payload . reason ) { status . push ( r . payload . reason ) }
391
+ if ( r . payload . frame ) {
392
+ for ( let i of [ 'file' , 'func' , 'line' ] ) {
393
+ if ( i in r . payload . frame ) {
394
+ status . push ( `${ i } : ${ r . payload . frame [ i ] } ` )
395
+ }
396
+ }
397
+ }
315
398
}
316
- App . set_status ( status . join ( '. ' ) )
399
+ App . set_status ( status . join ( ', ' ) )
317
400
}
318
401
319
402
// scroll to the bottom
320
403
Consts . jq_stdout . animate ( { 'scrollTop' : Consts . jq_stdout . prop ( 'scrollHeight' ) } )
321
404
Consts . jq_gdb_mi_output . animate ( { 'scrollTop' : Consts . jq_gdb_mi_output . prop ( 'scrollHeight' ) } )
322
405
Consts . jq_console . animate ( { 'scrollTop' : Consts . jq_console . prop ( 'scrollHeight' ) } )
323
406
} ,
407
+ keyup_source_file_input : function ( e ) {
408
+ if ( e . keyCode === 13 ) {
409
+ App . read_and_render_file ( e . currentTarget . value )
410
+ }
411
+ } ,
324
412
render_disasembly : function ( asm_insns ) {
325
413
let thead = [ 'line' , 'function+offset address instruction' ]
326
414
let data = [ ]
@@ -332,23 +420,22 @@ let App = {
332
420
Consts . jq_disassembly_heading . html ( asm_insns [ 'fullname' ] )
333
421
} ,
334
422
render_stack : function ( stack ) {
335
- let thead = _ . keys ( stack [ 0 ] )
336
- let stack_array = stack . map ( b => _ . values ( b ) ) ;
337
- Consts . jq_stack . html ( Util . get_table ( thead , stack_array ) ) ;
423
+ let [ columns , data ] = Util . get_table_data ( stack )
424
+ Consts . jq_stack . html ( Util . get_table ( columns , data ) ) ;
338
425
} ,
339
426
render_registers ( names , values ) {
340
- let thead = [ 'name' , 'value' ]
427
+ let columns = [ 'name' , 'value' ]
341
428
let register_array = values . map ( v => [ names [ v [ 'number' ] ] , v [ 'value' ] ] ) ;
342
- Consts . jq_registers . html ( Util . get_table ( thead , register_array ) ) ;
429
+ Consts . jq_registers . html ( Util . get_table ( columns , register_array ) ) ;
343
430
} ,
344
431
read_and_render_file : function ( fullname , highlight_line = 0 ) {
345
- if ( fullname === null ) {
432
+ if ( fullname === null || fullname === undefined ) {
346
433
return
347
434
}
348
435
349
- if ( App . state . source_files . some ( f => f . fullname === fullname ) ) {
436
+ if ( App . state . cached_source_files . some ( f => f . fullname === fullname ) ) {
350
437
// We have this cached locally, just use it!
351
- let f = _ . find ( App . state . source_files , i => i . fullname === fullname ) ;
438
+ let f = _ . find ( App . state . cached_source_files , i => i . fullname === fullname ) ;
352
439
App . render_source_file ( fullname , f . source_code , highlight_line ) ;
353
440
return
354
441
}
@@ -359,7 +446,7 @@ let App = {
359
446
type : 'GET' ,
360
447
data : { path : fullname } ,
361
448
success : function ( response ) {
362
- App . state . source_files . push ( { 'fullname' : fullname , 'source_code' : response . source_code } )
449
+ App . state . cached_source_files . push ( { 'fullname' : fullname , 'source_code' : response . source_code } )
363
450
App . render_source_file ( fullname , response . source_code , highlight_line ) ;
364
451
} ,
365
452
error : Util . post_msg
@@ -407,9 +494,8 @@ let App = {
407
494
App . state . breakpoints . push ( breakpoint ) ;
408
495
} ,
409
496
render_breakpoint_table : function ( ) {
410
- const thead = _ . keys ( App . state . breakpoints [ 0 ] ) ;
411
- let bkpt_array = App . state . breakpoints . map ( b => _ . values ( b ) ) ;
412
- Consts . jq_breakpoints . html ( Util . get_table ( thead , bkpt_array ) ) ;
497
+ let [ columns , data ] = Util . get_table_data ( App . state . breakpoints )
498
+ Consts . jq_breakpoints . html ( Util . get_table ( columns , data ) )
413
499
} ,
414
500
enable_gdb_controls : function ( ) {
415
501
Consts . js_gdb_controls . removeClass ( 'disabled' ) ;
0 commit comments