diff --git a/doc/man/sieve-dump.1.in b/doc/man/sieve-dump.1.in
index 10c381c8744d9afcd9f5a9d10b58c6468b96701d..d553b5a299ee25b681d3b6d9d84c61552d53acc7 100644
--- a/doc/man/sieve-dump.1.in
+++ b/doc/man/sieve-dump.1.in
@@ -40,6 +40,10 @@ the binary.
 .BI \-c\  config\-file
 Alternative Dovecot configuration file path.
 .TP
+.B \-h
+Produce per-block hexdump output of the whole binary instead of the normal
+human-readable output. 
+.TP
 .BI \-x\  extensions
 Set the available extensions. The parameter is a space\-separated list of the
 active extensions. By prepending the extension identifiers with \fB+\fP or
diff --git a/src/lib-sieve-tool/sieve-tool.c b/src/lib-sieve-tool/sieve-tool.c
index 80dca2e6c60cb72ac130ed9bb337c83802253268..359ab715dbbd2efd97260a6926be5a8a2a9dad9d 100644
--- a/src/lib-sieve-tool/sieve-tool.c
+++ b/src/lib-sieve-tool/sieve-tool.c
@@ -547,7 +547,8 @@ struct sieve_binary *sieve_tool_script_open
 	return sbin;
 }
 
-void sieve_tool_dump_binary_to(struct sieve_binary *sbin, const char *filename)	
+void sieve_tool_dump_binary_to
+(struct sieve_binary *sbin, const char *filename, bool hexdump)	
 {
 	struct ostream *dumpstream;
 
@@ -555,7 +556,10 @@ void sieve_tool_dump_binary_to(struct sieve_binary *sbin, const char *filename)
 
 	dumpstream = sieve_tool_open_output_stream(filename);
 	if ( dumpstream != NULL ) {
-		(void) sieve_dump(sbin, dumpstream, FALSE);
+		if ( hexdump ) 
+			(void) sieve_hexdump(sbin, dumpstream);
+		else
+			(void) sieve_dump(sbin, dumpstream, FALSE);
 		o_stream_destroy(&dumpstream);
 	} else {
 		i_fatal("Failed to create stream for sieve code dump.");
diff --git a/src/lib-sieve-tool/sieve-tool.h b/src/lib-sieve-tool/sieve-tool.h
index da1e4a91fcea40dfe3ddff0647cd8de32c1f461c..ec0365049ee91f625e6594441f2d1d83679090ca 100644
--- a/src/lib-sieve-tool/sieve-tool.h
+++ b/src/lib-sieve-tool/sieve-tool.h
@@ -87,7 +87,7 @@ struct sieve_binary *sieve_tool_script_compile
 struct sieve_binary *sieve_tool_script_open
 	(struct sieve_instance *svinst, const char *filename);
 void sieve_tool_dump_binary_to
-	(struct sieve_binary *sbin, const char *filename);
+	(struct sieve_binary *sbin, const char *filename, bool hexdump);
 
 /*
  * Command line option parsing
diff --git a/src/lib-sieve/sieve-binary-dumper.c b/src/lib-sieve/sieve-binary-dumper.c
index f86a861ac2da9376b4d7303d550295763eb96c92..d1812e5b4b325cb3d2052cf35de357adb3c9fc05 100644
--- a/src/lib-sieve/sieve-binary-dumper.c
+++ b/src/lib-sieve/sieve-binary-dumper.c
@@ -4,13 +4,15 @@
 #include "lib.h"
 #include "str.h"
 #include "ostream.h"
+#include "array.h"
+#include "buffer.h"
 
 #include "sieve-common.h"
 #include "sieve-extensions.h"
-#include "sieve-binary.h"
-
 #include "sieve-dump.h"
 
+#include "sieve-binary-private.h"
+
 /*
  * Binary dumper object
  */ 
@@ -180,3 +182,91 @@ bool sieve_binary_dumper_run
 
 	return TRUE;
 }
+
+/*
+ * Hexdump production
+ */
+
+void sieve_binary_dumper_hexdump
+(struct sieve_binary_dumper *dumper, struct ostream *stream)
+{
+	struct sieve_binary *sbin = dumper->dumpenv.sbin;
+	struct sieve_dumptime_env *denv = &(dumper->dumpenv);
+	int count, i;
+	
+	dumper->dumpenv.stream = stream;
+
+	count = sieve_binary_block_count(sbin);
+
+	/* Block overview */
+
+	sieve_binary_dump_sectionf
+		(denv, "Binary blocks (count: %d)", count);
+
+	for ( i = 0; i < count; i++ ) {
+		struct sieve_binary_block *sblock = sieve_binary_block_get(sbin, i);
+
+		sieve_binary_dumpf(denv, 
+			"%3d: size: %"PRIuSIZE_T" bytes\n", i, 
+			sieve_binary_block_get_size(sblock));
+	}
+
+	/* Hexdump for each block */
+
+	for ( i = 0; i < count; i++ ) {
+		struct sieve_binary_block *sblock = sieve_binary_block_get(sbin, i);
+		buffer_t *blockbuf = sieve_binary_block_get_buffer(sblock);
+		string_t *line;
+		size_t data_size;
+		const char *data;
+		size_t offset;
+
+		data = (const char *) buffer_get_data(blockbuf, &data_size);
+		
+		sieve_binary_dump_sectionf
+			(denv, "Block %d (%"PRIuSIZE_T" bytes, file offset %08llx)", i, 
+				data_size, sblock->offset + 8 /* header size (yuck) */);
+
+		line = t_str_new(128);
+		offset = 0;
+		while ( offset < data_size ) {
+			size_t len = ( data_size - offset >= 16 ? 16 : data_size - offset );
+			size_t b;
+
+			str_printfa(line, "%08llx  ", (unsigned long long) offset);
+
+			for ( b = 0; b < len; b++ ) {
+				str_printfa(line, "%02x ", (unsigned int) data[offset+b]);	
+				if ( b == 7 ) str_append_c(line, ' ');
+			}
+
+			if ( len < 16 ) {
+				if ( len <= 7 ) str_append_c(line, ' ');
+
+				for ( b = len; b < 16; b++ ) {
+					str_append(line, "   ");
+				}
+			}
+
+			str_append(line, " |");
+
+			for ( b = 0; b < len; b++ ) {
+				const char c = data[offset+b];
+
+				if ( c >= 32 && c <= 126 )
+					str_append_c(line, c);
+				else
+					str_append_c(line, '.');
+			}
+
+			str_append(line, "|\n");
+			o_stream_send(stream, str_data(line), str_len(line));
+			str_truncate(line, 0);
+			offset += len;
+		}
+		
+		str_printfa(line, "%08llx\n", (unsigned long long) offset);
+		o_stream_send(stream, str_data(line), str_len(line));
+	}
+} 
+
diff --git a/src/lib-sieve/sieve-binary-dumper.h b/src/lib-sieve/sieve-binary-dumper.h
index 24238963a4ea1adfe56f3fc6cd4de26ffa4f1501..dda7bfa0b0166812fbcd00e7f2962384294aefd6 100644
--- a/src/lib-sieve/sieve-binary-dumper.h
+++ b/src/lib-sieve/sieve-binary-dumper.h
@@ -36,5 +36,11 @@ void sieve_binary_dump_sectionf
 bool sieve_binary_dumper_run
 	(struct sieve_binary_dumper *dumper, struct ostream *stream, bool verbose);
 
+/*
+ * Hexdump production
+ */
+
+void sieve_binary_dumper_hexdump
+(struct sieve_binary_dumper *dumper, struct ostream *stream);
 
 #endif /* __SIEVE_BINARY_DUMPER_H */
diff --git a/src/lib-sieve/sieve-binary.h b/src/lib-sieve/sieve-binary.h
index d33754ca4859dc20190e55e253666c8d49d6b21f..cd45da71ef7af40f8c3fb6eb1f6f962bd8271cbf 100644
--- a/src/lib-sieve/sieve-binary.h
+++ b/src/lib-sieve/sieve-binary.h
@@ -257,7 +257,6 @@ struct sieve_binary_debug_reader *sieve_binary_debug_reader_init
 void sieve_binary_debug_reader_deinit
 	(struct sieve_binary_debug_reader **dreader);
 
-
 void sieve_binary_debug_reader_reset
 	(struct sieve_binary_debug_reader *dreader);
 
diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c
index 3c0caef11344b4824724877f7ae56b75ecb0724e..b93b46d781b4ae4c609cef7f2cc7ac6d2f258f70 100644
--- a/src/lib-sieve/sieve.c
+++ b/src/lib-sieve/sieve.c
@@ -397,7 +397,8 @@ void sieve_close(struct sieve_binary **sbin)
  * Debugging
  */
 
-void sieve_dump(struct sieve_binary *sbin, struct ostream *stream, bool verbose) 
+void sieve_dump
+(struct sieve_binary *sbin, struct ostream *stream, bool verbose) 
 {
 	struct sieve_binary_dumper *dumpr = sieve_binary_dumper_create(sbin);			
 
@@ -406,6 +407,16 @@ void sieve_dump(struct sieve_binary *sbin, struct ostream *stream, bool verbose)
 	sieve_binary_dumper_free(&dumpr);
 }
 
+void sieve_hexdump
+(struct sieve_binary *sbin, struct ostream *stream) 
+{	
+	struct sieve_binary_dumper *dumpr = sieve_binary_dumper_create(sbin);			
+
+	sieve_binary_dumper_hexdump(dumpr, stream);	
+	
+	sieve_binary_dumper_free(&dumpr);
+}
+
 int sieve_test
 (struct sieve_binary *sbin, const struct sieve_message_data *msgdata,
 	const struct sieve_script_env *senv, struct sieve_error_handler *ehandler,
diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h
index ac58cf77ba98a1634d0fc8f51676d913725d16e9..50db0cbd023455e5731931a9df6446433c13fd76 100644
--- a/src/lib-sieve/sieve.h
+++ b/src/lib-sieve/sieve.h
@@ -119,7 +119,16 @@ bool sieve_is_loaded(struct sieve_binary *sbin);
  *
  *   Dumps the byte code in human-readable form to the specified ostream.
  */
-void sieve_dump(struct sieve_binary *sbin, struct ostream *stream, bool verbose);
+void sieve_dump
+	(struct sieve_binary *sbin, struct ostream *stream, bool verbose);
+
+/* sieve_hexdump:
+ *
+ *   Dumps the byte code in hexdump form to the specified ostream.
+ */
+
+void sieve_hexdump
+	(struct sieve_binary *sbin, struct ostream *stream);
 
 /* sieve_test:
  *
diff --git a/src/sieve-tools/sieve-dump.c b/src/sieve-tools/sieve-dump.c
index 1e9d8a0046ca375250ed0c6f31c668b17a72768e..17f8118977698f52e763ce74223e8ecd9ce7d126 100644
--- a/src/sieve-tools/sieve-dump.c
+++ b/src/sieve-tools/sieve-dump.c
@@ -30,7 +30,7 @@
 static void print_help(void)
 {
 	printf(
-"Usage: sieve-dump [-P <plugin>] [-x <extensions>]\n"
+"Usage: sieve-dump [-h] [-P <plugin>] [-x <extensions>]\n"
 "                  <sieve-binary> [<out-file>]\n"
 	);
 }
@@ -44,16 +44,25 @@ int main(int argc, char **argv)
 	struct sieve_instance *svinst;
 	struct sieve_binary *sbin;
 	const char *binfile, *outfile;
+	bool hexdump = FALSE;
 	int exit_status = EXIT_SUCCESS;
 	int c;
 
-	sieve_tool = sieve_tool_init("sieve-dump", &argc, &argv, "P:x:", FALSE);
+	sieve_tool = sieve_tool_init("sieve-dump", &argc, &argv, "hP:x:", FALSE);
 		
 	binfile = outfile = NULL;
 
-	if ( (c = sieve_tool_getopt(sieve_tool)) > 0 ) {
-		print_help();
-		i_fatal_status(EX_USAGE, "Unknown argument: %c", c);
+	while ((c = sieve_tool_getopt(sieve_tool)) > 0) {
+		switch (c) {
+		case 'h':
+			/* produce hexdump */
+			hexdump = TRUE;
+			break;
+		default:
+			print_help();
+			i_fatal_status(EX_USAGE, "Unknown argument: %c", c);
+			break;
+		}
 	}
 
 	if ( optind < argc ) {
@@ -76,7 +85,7 @@ int main(int argc, char **argv)
 	/* Dump binary */
 	sbin = sieve_load(svinst, binfile, NULL);
 	if ( sbin != NULL ) {
-		sieve_tool_dump_binary_to(sbin, outfile == NULL ? "-" : outfile);
+		sieve_tool_dump_binary_to(sbin, outfile == NULL ? "-" : outfile, hexdump);
 	
 		sieve_close(&sbin);
 	} else {
diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c
index fdf8a89756311b001e86a8473bf5fb1990a86de7..b9ca7601bcd32b962b877ca5b990997e7940e149 100644
--- a/src/sieve-tools/sieve-test.c
+++ b/src/sieve-tools/sieve-test.c
@@ -224,7 +224,7 @@ int main(int argc, char **argv)
 		exit_status = EXIT_FAILURE;
 	} else {
 		/* Dump script */
-		sieve_tool_dump_binary_to(main_sbin, dumpfile);
+		sieve_tool_dump_binary_to(main_sbin, dumpfile, FALSE);
 
 		/* Obtain mail namespaces from -l argument */
 		if ( mailloc != NULL ) {
diff --git a/src/sieve-tools/sievec.c b/src/sieve-tools/sievec.c
index 40c97e27ee31104121f2d399f61f63bd607447d9..f93d3447c4944b596e63eadd2513ca4dbc9300cf 100644
--- a/src/sieve-tools/sievec.c
+++ b/src/sieve-tools/sievec.c
@@ -143,7 +143,7 @@ int main(int argc, char **argv)
 
 		if ( sbin != NULL ) {
 			if ( dump ) 
-				sieve_tool_dump_binary_to(sbin, outfile);
+				sieve_tool_dump_binary_to(sbin, outfile, FALSE);
 			else {
 				sieve_save(sbin, outfile, TRUE, NULL);
 			}
diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c
index 2ff4d3a2956b305e2bbac9d11b9bc47177944ce0..5d688aab8e37fb4a0d56fdfc3aa94bbb3f44be90 100644
--- a/src/testsuite/testsuite.c
+++ b/src/testsuite/testsuite.c
@@ -170,7 +170,7 @@ int main(int argc, char **argv)
 		struct sieve_script_env scriptenv;
 
 		/* Dump script */
-		sieve_tool_dump_binary_to(sbin, dumpfile);
+		sieve_tool_dump_binary_to(sbin, dumpfile, FALSE);
 
 		if ( tracefile != NULL )
 			tracestream = sieve_tool_open_output_stream(tracefile);