Wed Jan 13 15:54:53 CET 2010 Paolo Molaro <lupus@ximian.com>
authorPaolo Molaro <lupus@oddwiz.org>
Wed, 13 Jan 2010 14:56:39 +0000 (14:56 -0000)
committerPaolo Molaro <lupus@oddwiz.org>
Wed, 13 Jan 2010 14:56:39 +0000 (14:56 -0000)
* jit.h, method-to-ir.c: added ability to set the policy for
inserting breakpoints from the break IL instruction or the
Debugger.Break () API call.

svn path=/trunk/mono/; revision=149472

mono/mini/ChangeLog
mono/mini/jit.h
mono/mini/method-to-ir.c

index eb35a80b88cb4e45412ee48e8f0772986dfb9610..cab9976135d1bbe66e34c928c691202ea125603a 100644 (file)
@@ -1,3 +1,10 @@
+
+Wed Jan 13 15:54:53 CET 2010 Paolo Molaro <lupus@ximian.com>
+
+       * jit.h, method-to-ir.c: added ability to set the policy for
+       inserting breakpoints from the break IL instruction or the
+       Debugger.Break () API call.
+
 2010-01-13  Zoltan Varga  <vargaz@gmail.com>
 
        * aot-runtime.c (load_aot_module): Add more comments to explain why referenced
index f78dd119de8fa234c3ba8b0b5a0cd595ef39168b..f5440ad895cb46ae486d2f7c761b65fcc332591a 100644 (file)
@@ -33,6 +33,25 @@ mono_set_signal_chaining   (gboolean chain_signals);
 void
 mono_jit_set_aot_only      (gboolean aot_only);
 
+/* Allow embedders to decide wherther to actually obey breakpoint instructions
+ * in specific methods (works for both break IL instructions and Debugger.Break ()
+ * method calls).
+ */
+typedef enum {
+       /* the default is to always obey the breakpoint */
+       MONO_BREAK_POLICY_ALWAYS,
+       /* a nop is inserted instead of a breakpoint */
+       MONO_BREAK_POLICY_NEVER,
+       /* the breakpoint is executed only if the program has ben started under
+        * the debugger (that is if a debugger was attached at the time the method
+        * was compiled).
+        */
+       MONO_BREAK_POLICY_ON_DBG
+} MonoBreakPolicy;
+
+typedef MonoBreakPolicy (*MonoBreakPolicyFunc) (MonoMethod *method);
+void mono_set_break_policy (MonoBreakPolicyFunc policy_callback);
+
 void
 mono_jit_parse_options     (int argc, char * argv[]);
 
index c050f854e68f646e5bc7fc300d4753a58dee6578..1f6242e4ee5614fc67b1c3e4eb3980b30acf75b8 100644 (file)
@@ -57,6 +57,7 @@
 #include "ir-emit.h"
 
 #include "jit-icalls.h"
+#include "jit.h"
 #include "debugger-agent.h"
 
 #define BRANCH_COST 100
@@ -3798,6 +3799,53 @@ mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, uns
        return addr;
 }
 
+static MonoBreakPolicy
+always_insert_breakpoint (MonoMethod *method)
+{
+       return MONO_BREAK_POLICY_ALWAYS;
+}
+
+static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
+
+/**
+ * mono_set_break_policy:
+ * policy_callback: the new callback function
+ *
+ * Allow embedders to decide wherther to actually obey breakpoint instructions
+ * (both break IL instructions and Debugger.Break () method calls), for example
+ * to not allow an app to be aborted by a perfectly valid IL opcode when executing
+ * untrusted or semi-trusted code.
+ *
+ * @policy_callback will be called every time a break point instruction needs to
+ * be inserted with the method argument being the method that calls Debugger.Break()
+ * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
+ * if it wants the breakpoint to not be effective in the given method.
+ * #MONO_BREAK_POLICY_ALWAYS is the default.
+ */
+void
+mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
+{
+       if (policy_callback)
+               break_policy_func = policy_callback;
+       else
+               break_policy_func = always_insert_breakpoint;
+}
+
+static gboolean
+should_insert_brekpoint (MonoMethod *method) {
+       switch (break_policy_func (method)) {
+       case MONO_BREAK_POLICY_ALWAYS:
+               return TRUE;
+       case MONO_BREAK_POLICY_NEVER:
+               return FALSE;
+       case MONO_BREAK_POLICY_ON_DBG:
+               return mono_debug_using_mono_debugger ();
+       default:
+               g_warning ("Incorrect value returned from break policy callback");
+               return FALSE;
+       }
+}
+
 static MonoInst*
 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -4166,7 +4214,10 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
        } else if (cmethod->klass->image == mono_defaults.corlib) {
                if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
                                && strcmp (cmethod->klass->name, "Debugger") == 0) {
-                       MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       if (should_insert_brekpoint (cfg->method))
+                               MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       else
+                               MONO_INST_NEW (cfg, ins, OP_NOP);
                        MONO_ADD_INS (cfg->cbb, ins);
                        return ins;
                }
@@ -5886,7 +5937,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MONO_ADD_INS (bblock, ins);
                        break;
                case CEE_BREAK:
-                       MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       if (should_insert_brekpoint (cfg->method))
+                               MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       else
+                               MONO_INST_NEW (cfg, ins, OP_NOP);
                        ip++;
                        MONO_ADD_INS (bblock, ins);
                        break;