2 * Copyright (C) 2006 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
25 #include "swfdec_debugger.h"
26 #include "swfdec_debug.h"
27 #include "swfdec_decoder.h"
28 #include "swfdec_player_internal.h"
29 #include "js/jsdbgapi.h"
31 /*** SwfdecDebuggerScript ***/
33 static SwfdecDebuggerScript
*
34 swfdec_debugger_script_new (JSScript
*script
, const char *name
,
35 SwfdecDebuggerCommand
*commands
, guint n_commands
)
37 SwfdecDebuggerScript
*ret
;
39 ret
= g_new0 (SwfdecDebuggerScript
, 1);
41 ret
->name
= g_strdup (name
);
42 ret
->commands
= commands
;
43 ret
->n_commands
= n_commands
;
49 swfdec_debugger_script_free (SwfdecDebuggerScript
*script
)
52 g_free (script
->commands
);
56 /*** SwfdecDebugger ***/
66 G_DEFINE_TYPE (SwfdecDebugger
, swfdec_debugger
, SWFDEC_TYPE_PLAYER
)
67 guint signals
[LAST_SIGNAL
] = { 0, };
70 swfdec_debugger_dispose (GObject
*object
)
72 SwfdecDebugger
*debugger
= SWFDEC_DEBUGGER (object
);
74 g_assert (g_hash_table_size (debugger
->scripts
) == 0);
75 g_hash_table_destroy (debugger
->scripts
);
76 if (debugger
->breakpoints
)
77 g_array_free (debugger
->breakpoints
, TRUE
);
79 G_OBJECT_CLASS (swfdec_debugger_parent_class
)->dispose (object
);
83 swfdec_debugger_class_init (SwfdecDebuggerClass
*klass
)
85 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
87 object_class
->dispose
= swfdec_debugger_dispose
;
89 signals
[SCRIPT_ADDED
] = g_signal_new ("script-added", G_TYPE_FROM_CLASS (klass
),
90 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, g_cclosure_marshal_VOID__POINTER
,
91 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
92 signals
[SCRIPT_REMOVED
] = g_signal_new ("script-removed", G_TYPE_FROM_CLASS (klass
),
93 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, g_cclosure_marshal_VOID__POINTER
,
94 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
95 signals
[BREAKPOINT_ADDED
] = g_signal_new ("breakpoint-added",
96 G_TYPE_FROM_CLASS (klass
), G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
,
97 g_cclosure_marshal_VOID__UINT
, G_TYPE_NONE
, 1, G_TYPE_UINT
);
98 signals
[BREAKPOINT_REMOVED
] = g_signal_new ("breakpoint-removed",
99 G_TYPE_FROM_CLASS (klass
), G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
,
100 g_cclosure_marshal_VOID__UINT
, G_TYPE_NONE
, 1, G_TYPE_UINT
);
104 swfdec_debugger_init (SwfdecDebugger
*debugger
)
106 debugger
->scripts
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
107 NULL
, (GDestroyNotify
) swfdec_debugger_script_free
);
111 * swfdec_debugger_new:
113 * Creates a #SwfdecPlayer that can be debugged.
115 * Returns: a new #SwfdecDebugger
118 swfdec_debugger_new (void)
120 SwfdecPlayer
*player
;
123 player
= g_object_new (SWFDEC_TYPE_DEBUGGER
, NULL
);
128 swfdec_debugger_add_script (SwfdecDebugger
*debugger
, JSScript
*jscript
, const char *name
,
129 SwfdecDebuggerCommand
*commands
, guint n_commands
)
131 SwfdecDebuggerScript
*dscript
= swfdec_debugger_script_new (jscript
, name
, commands
, n_commands
);
133 g_hash_table_insert (debugger
->scripts
, jscript
, dscript
);
134 g_signal_emit (debugger
, signals
[SCRIPT_ADDED
], 0, dscript
);
138 swfdec_debugger_remove_script (SwfdecDebugger
*debugger
, JSScript
*script
)
140 SwfdecDebuggerScript
*dscript
= g_hash_table_lookup (debugger
->scripts
, script
);
143 g_signal_emit (debugger
, signals
[SCRIPT_REMOVED
], 0, dscript
);
144 g_hash_table_remove (debugger
->scripts
, script
);
153 do_foreach (gpointer key
, gpointer value
, gpointer data
)
155 ForeachData
*fdata
= data
;
157 fdata
->func (value
, fdata
->data
);
161 swfdec_debugger_foreach_script (SwfdecDebugger
*debugger
, GFunc func
, gpointer data
)
163 ForeachData fdata
= { func
, data
};
164 g_hash_table_foreach (debugger
->scripts
, do_foreach
, &fdata
);
167 /*** BREAKPOINTS ***/
170 SwfdecDebuggerScript
* script
;
175 swfdec_debugger_handle_breakpoint (JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
176 jsval
*rval
, void *closure
)
178 return JSTRAP_CONTINUE
;
182 swfdec_debugger_set_breakpoint (SwfdecDebugger
*debugger
,
183 SwfdecDebuggerScript
*script
, guint line
)
186 Breakpoint
*br
= NULL
;
188 g_return_val_if_fail (SWFDEC_IS_DEBUGGER (debugger
), 0);
189 g_return_val_if_fail (script
!= NULL
, 0);
190 g_return_val_if_fail (line
< script
->n_commands
, 0);
192 if (debugger
->breakpoints
== NULL
)
193 debugger
->breakpoints
= g_array_new (FALSE
, FALSE
, sizeof (Breakpoint
));
194 if (script
->commands
[line
].breakpoint
!= 0)
195 return script
->commands
[line
].breakpoint
;
197 for (i
= 0; i
< debugger
->breakpoints
->len
; i
++) {
198 br
= &g_array_index (debugger
->breakpoints
, Breakpoint
, i
);
199 if (br
->script
== NULL
)
203 if (!JS_SetTrap (SWFDEC_PLAYER (debugger
)->jscx
, script
->script
,
204 script
->commands
[line
].code
, swfdec_debugger_handle_breakpoint
,
205 GUINT_TO_POINTER (i
)))
209 g_array_set_size (debugger
->breakpoints
, debugger
->breakpoints
->len
+ 1);
210 br
= &g_array_index (debugger
->breakpoints
, Breakpoint
,
211 debugger
->breakpoints
->len
- 1);
215 script
->commands
[line
].breakpoint
= i
+ 1;
216 g_signal_emit (debugger
, signals
[BREAKPOINT_ADDED
], 0, i
+ 1);
221 swfdec_debugger_unset_breakpoint (SwfdecDebugger
*debugger
, guint id
)
225 g_return_if_fail (SWFDEC_IS_DEBUGGER (debugger
));
226 g_return_if_fail (id
> 0);
228 if (debugger
->breakpoints
== NULL
)
230 if (id
> debugger
->breakpoints
->len
)
232 br
= &g_array_index (debugger
->breakpoints
, Breakpoint
, id
- 1);
233 if (br
->script
== NULL
)
236 JS_ClearTrap (SWFDEC_PLAYER (debugger
)->jscx
, br
->script
->script
,
237 br
->script
->commands
[br
->line
].code
, NULL
, NULL
);
238 g_signal_emit (debugger
, signals
[BREAKPOINT_REMOVED
], 0, id
);
239 br
->script
->commands
[br
->line
].breakpoint
= 0;
244 swfdec_debugger_get_breakpoint (SwfdecDebugger
*debugger
, guint id
,
245 SwfdecDebuggerScript
**script
, guint
*line
)
249 g_return_val_if_fail (SWFDEC_IS_DEBUGGER (debugger
), FALSE
);
250 g_return_val_if_fail (id
> 0, FALSE
);
252 if (debugger
->breakpoints
== NULL
)
254 if (id
> debugger
->breakpoints
->len
)
256 br
= &g_array_index (debugger
->breakpoints
, Breakpoint
, id
- 1);
257 if (br
->script
== NULL
)
261 *script
= br
->script
;
268 swfdec_debugger_get_n_breakpoints (SwfdecDebugger
*debugger
)
270 g_return_val_if_fail (SWFDEC_IS_DEBUGGER (debugger
), 0);
272 if (debugger
->breakpoints
== NULL
)
275 return debugger
->breakpoints
->len
;