diff --git a/doc/openocd.texi b/doc/openocd.texi
index ffa92c61b11fec057f25259f0867451cef8c753a..8c935583d25fa2d20b532ae3b760f3955852d906 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -737,7 +737,9 @@ the @command{reset init} command will interfere with debugging
 early boot code, which performs some of the same actions
 that the @code{reset-init} event handler does.
 Likewise, the @command{arm9tdmi vector_catch} command (or
-its @command{xscale vector_catch} sibling) can be a timesaver
+@cindex vector_catch
+its siblings @command{xscale vector_catch}
+and @command{cortex_m3 vector_catch}) can be a timesaver
 during some debug sessions, but don't make everyone use that either.
 Keep those kinds of debugging aids in your user config file,
 along with messaging and tracing setup.
@@ -4738,6 +4740,7 @@ Such cores include the ARM920T, ARM926EJ-S, and ARM966.
 
 @anchor{arm9tdmi vector_catch}
 @deffn Command {arm9tdmi vector_catch} [@option{all}|@option{none}|list]
+@cindex vector_catch
 Vector Catch hardware provides a sort of dedicated breakpoint
 for hardware events such as reset, interrupt, and abort.
 You can use this to conserve normal breakpoint resources,
@@ -4927,6 +4930,7 @@ The image @var{type} may be one of
 
 @anchor{xscale vector_catch}
 @deffn Command {xscale vector_catch} [mask]
+@cindex vector_catch
 Display a bitmask showing the hardware vectors to catch.
 If the optional parameter is provided, first set the bitmask to that value.
 @end deffn
@@ -5016,6 +5020,33 @@ Disassembles @var{count} Thumb2 instructions starting at @var{address}.
 Control masking (disabling) interrupts during target step/resume.
 @end deffn
 
+@deffn Command {cortex_m3 vector_catch} [@option{all}|@option{none}|list]
+@cindex vector_catch
+Vector Catch hardware provides dedicated breakpoints
+for certain hardware events.
+
+Parameters request interception of
+@option{all} of these hardware event vectors,
+@option{none} of them,
+or one or more of the following:
+@option{hard_err} for a HardFault exception;
+@option{mm_err} for a MemManage exception;
+@option{bus_err} for a BusFault exception;
+@option{irq_err},
+@option{state_err},
+@option{chk_err}, or
+@option{nocp_err} for various UsageFault exceptions; or
+@option{reset}.
+If NVIC setup code does not enable them,
+MemManage, BusFault, and UsageFault exceptions
+are mapped to HardFault.
+UsageFault checks for
+divide-by-zero and unaligned access
+must also be explicitly enabled.
+
+This finishes by listing the current vector catch configuration.
+@end deffn
+
 @anchor{Software Debug Messages and Tracing}
 @section Software Debug Messages and Tracing
 @cindex Linux-ARM DCC support
diff --git a/src/target/cortex_m3.c b/src/target/cortex_m3.c
index 8875dddc685ee0edee97005c0f291dd51564d121..626157431f995a838b1291af900edb87d24a80e6 100644
--- a/src/target/cortex_m3.c
+++ b/src/target/cortex_m3.c
@@ -37,6 +37,9 @@
 #include "arm_disassembler.h"
 
 
+#define ARRAY_SIZE(x)	((int)(sizeof(x)/sizeof((x)[0])))
+
+
 /* cli handling */
 int cortex_m3_register_commands(struct command_context_s *cmd_ctx);
 int handle_cortex_m3_mask_interrupts_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -174,7 +177,7 @@ int cortex_m3_clear_halt(target_t *target)
 
 	/* Read Debug Fault Status Register */
 	mem_ap_read_atomic_u32(swjdp, NVIC_DFSR, &cortex_m3->nvic_dfsr);
-	/* Write Debug Fault Status Register to enable processing to resume ?? Try with and without this !! */
+	/* Clear Debug Fault Status */
 	mem_ap_write_atomic_u32(swjdp, NVIC_DFSR, cortex_m3->nvic_dfsr);
 	LOG_DEBUG(" NVIC_DFSR 0x%" PRIx32 "", cortex_m3->nvic_dfsr);
 
@@ -307,8 +310,6 @@ int cortex_m3_examine_debug_reason(target_t *target)
 	if ((target->debug_reason != DBG_REASON_DBGRQ)
 		&& (target->debug_reason != DBG_REASON_SINGLESTEP))
 	{
-		/*  INCOMPLETE */
-
 		if (cortex_m3->nvic_dfsr & DFSR_BKPT)
 		{
 			target->debug_reason = DBG_REASON_BREAKPOINT;
@@ -317,6 +318,10 @@ int cortex_m3_examine_debug_reason(target_t *target)
 		}
 		else if (cortex_m3->nvic_dfsr & DFSR_DWTTRAP)
 			target->debug_reason = DBG_REASON_WATCHPOINT;
+		else if (cortex_m3->nvic_dfsr & DFSR_VCATCH)
+			target->debug_reason = DBG_REASON_BREAKPOINT;
+		else /* EXTERNAL, HALTED, DWTTRAP w/o BKPT */
+			target->debug_reason = DBG_REASON_UNDEFINED;
 	}
 
 	return ERROR_OK;
@@ -1703,6 +1708,73 @@ handle_cortex_m3_disassemble_command(struct command_context_s *cmd_ctx,
 	return ERROR_OK;
 }
 
+static const struct {
+	char name[10];
+	unsigned mask;
+} vec_ids[] = {
+	{ "hard_err",	VC_HARDERR, },
+	{ "int_err",	VC_INTERR, },
+	{ "bus_err",	VC_BUSERR, },
+	{ "state_err",	VC_STATERR, },
+	{ "chk_err",	VC_CHKERR, },
+	{ "nocp_err",	VC_NOCPERR, },
+	{ "mm_err",	VC_MMERR, },
+	{ "reset",	VC_CORERESET, },
+};
+
+static int
+handle_cortex_m3_vector_catch_command(struct command_context_s *cmd_ctx,
+		char *cmd, char **argv, int argc)
+{
+	target_t *target = get_current_target(cmd_ctx);
+	armv7m_common_t *armv7m = target->arch_info;
+	swjdp_common_t *swjdp = &armv7m->swjdp_info;
+	uint32_t demcr = 0;
+	int i;
+
+	mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &demcr);
+
+	if (argc > 0) {
+		unsigned catch = 0;
+
+		if (argc == 1) {
+			if (strcmp(argv[0], "all") == 0) {
+				catch = VC_HARDERR | VC_INTERR | VC_BUSERR
+					| VC_STATERR | VC_CHKERR | VC_NOCPERR
+					| VC_MMERR | VC_CORERESET;
+				goto write;
+			} else if (strcmp(argv[0], "none") == 0) {
+				goto write;
+			}
+		}
+		while (argc-- > 0) {
+			for (i = 0; i < ARRAY_SIZE(vec_ids); i++) {
+				if (strcmp(argv[argc], vec_ids[i].name) != 0)
+					continue;
+				catch |= vec_ids[i].mask;
+				break;
+			}
+			if (i == ARRAY_SIZE(vec_ids)) {
+				LOG_ERROR("No CM3 vector '%s'", argv[argc]);
+				return ERROR_INVALID_ARGUMENTS;
+			}
+		}
+write:
+		demcr &= ~0xffff;
+		demcr |= catch;
+
+		/* write, but don't assume it stuck */
+		mem_ap_write_u32(swjdp, DCB_DEMCR, demcr);
+		mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &demcr);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(vec_ids); i++)
+		command_print(cmd_ctx, "%9s: %s", vec_ids[i].name,
+			(demcr & vec_ids[i].mask) ? "catch" : "ignore");
+
+	return ERROR_OK;
+}
+
 int cortex_m3_register_commands(struct command_context_s *cmd_ctx)
 {
 	int retval;
@@ -1719,6 +1791,9 @@ int cortex_m3_register_commands(struct command_context_s *cmd_ctx)
 	register_command(cmd_ctx, cortex_m3_cmd, "maskisr",
 			handle_cortex_m3_mask_interrupts_command, COMMAND_EXEC,
 			"mask cortex_m3 interrupts ['on'|'off']");
+	register_command(cmd_ctx, cortex_m3_cmd, "vector_catch",
+			handle_cortex_m3_vector_catch_command, COMMAND_EXEC,
+			"catch hardware vectors ['all'|'none'|<list>]");
 
 	return retval;
 }
diff --git a/src/target/cortex_m3.h b/src/target/cortex_m3.h
index e6714d0077fde554af5453a4692f3e5cc167cbc8..4e8cd1116ccd992e480924b75489bc44a608f3c5 100644
--- a/src/target/cortex_m3.h
+++ b/src/target/cortex_m3.h
@@ -80,7 +80,12 @@ extern char* cortex_m3_state_strings[];
 /* DCB_DEMCR bit and field definitions */
 #define	TRCENA			(1 << 24)
 #define	VC_HARDERR		(1 << 10)
+#define	VC_INTERR		(1 << 9)
 #define	VC_BUSERR		(1 << 8)
+#define	VC_STATERR		(1 << 7)
+#define	VC_CHKERR		(1 << 6)
+#define	VC_NOCPERR		(1 << 5)
+#define	VC_MMERR		(1 << 4)
 #define	VC_CORERESET	(1 << 0)
 
 #define NVIC_ICTR		0xE000E004