]> git.sur5r.net Git - openldap/commitdiff
ITS#6758 Add SLAP_OP() &co, contrib:wrap_slap_ops.
authorHallvard Furuseth <hallvard@openldap.org>
Wed, 11 Dec 2013 13:40:45 +0000 (14:40 +0100)
committerHallvard Furuseth <hallvard@openldap.org>
Wed, 11 Dec 2013 13:40:45 +0000 (14:40 +0100)
Add framework for debug macros SLAP_OP(), slap_be_op(),
slap_bi_op() around LDAP-operation backend calls.

contrib/slapd-tools/wrap_slap_ops converts code to use them.

Code compiles as before by default.  #define USE_RS_ASSERT
enables debugging, $NO_RS_ASSERT tweaks it. See slapd/result.c.

contrib/slapd-tools/README
contrib/slapd-tools/wrap_slap_ops [new file with mode: 0755]
servers/slapd/backend.c
servers/slapd/proto-slap.h
servers/slapd/result.c

index 2fe80276b2d4e5159f132953226e209ef7413fbf..4f5f12f924081f9b5a03aa94f98b1ed7b872cd7d 100644 (file)
@@ -5,6 +5,11 @@ statslog
        (LDAP request/response log), grouping log lines by LDAP
        connection.  Useful to search and inspect the server log.
 
+wrap_slap_ops
+       Update source code to use the wrapper macros SLAP_OP() & co
+       for LDAP-operation backend calls. They can help debug the
+       SlapReply.  They compile like the old code by default.
+
 ---
 Copyright 2004-2013 The OpenLDAP Foundation. All rights reserved.
 
diff --git a/contrib/slapd-tools/wrap_slap_ops b/contrib/slapd-tools/wrap_slap_ops
new file mode 100755 (executable)
index 0000000..09f6fb6
--- /dev/null
@@ -0,0 +1,162 @@
+#!/usr/bin/perl -wn0777
+# wrap_slap_ops - Help update code to use SLAP_OP() & co.
+#
+# This work is part of OpenLDAP Software <http://www.openldap.org/>.
+#
+# Copyright 2011-2013 The OpenLDAP Foundation.
+# Portions Copyright 2011-2013 Hallvard B. Furuseth.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted only as authorized by the OpenLDAP
+# Public License.
+#
+# A copy of this license is available in the file LICENSE in the
+# top-level directory of the distribution or, alternatively, at
+# <http://www.OpenLDAP.org/license.html>.
+
+use strict;
+
+sub usage() {
+       warn "Usage: $0 {-l | -u | -U<num>} {file | dir}...
+
+Update slapd source code to wrap LDAP operation calls in the debug
+macros SLAP_OP() & co.  They compile like the old code by default.
+Define USE_RS_ASSERT to enable asserts which verify the SlapReply.
+See servers/slapd/result.c.
+
+Options:
+  -u, -U<n> Output unidiffs with n lines of context (-u = default for diff).
+  -l        List files which would change. Show remaining cases on stderr.\n";
+       exit(1);
+}
+
+#### File/option handling. Skips symlinks, handles filenames =~ /\.[ch]+p*$/i.
+
+sub ls_R {
+    map { -l $_ ? () : -d _ ? ls_R(<$_/*>) : /\.[ch]+p*$/i ? $_ : () } @_;
+}
+
+use constant Mode => shift(@ARGV) || "";
+use vars qw($ccnt $rcnt);
+INIT {
+       usage() unless Mode =~ /^-(l|[uU]\d*)$/ && ($ARGV[0]||"") =~ /^[^\-]/;
+       exit(0) unless @ARGV = ls_R(@ARGV); # Expand ARGV, exit if no files
+       $| = 1;
+       $ccnt = $rcnt = 0;
+}
+
+sub file_result( $$ ) {
+       my($contents, $changed) = @_;
+       $ccnt++ if $changed;
+       $rcnt += scalar( my @rest = remaining($contents) );
+       if (Mode eq "-l") {
+               print "$ARGV\n" if $changed;
+               print STDERR "$ARGV:\t$_\n" foreach @rest;
+       } elsif ($changed) {
+               (my $file = "$ARGV") =~ s%^-%./-%;
+               print "Index: $file\n";
+               (open(D, "|-", "diff", Mode, $file, "-")
+                && (print D $contents)
+                && (close(D) || $! == 0)) or die "$0: diff failed: $!\n";
+       }
+}
+
+END {
+       print STDERR <<EOMSG;
+$ccnt files to change. $rcnt suspicious lines remain. (Expect three in slapd).
+EOMSG
+}
+
+#### Edit the contents of a file
+
+use vars qw($obj_re %addr %func2op $func_re $todo_re);
+INIT {
+       $obj_re  = qr/(?:\w+ (?:\s* (?:->|\.) \s* \w+)*?)/x;
+       %addr    = ("." => "&", "->" => ""); # x.y => (&x)->y, x->y => x->y
+       %func2op = map { /(\w+) \s+ (?= .*?=>\s* (\w+))/gx } <DATA>;
+       $func_re = '\b(?=b[ei]_)(?:' . join("|", keys %func2op) . ')\b';
+       my %both = (%func2op, reverse %func2op);
+       $todo_re = '\b(?=[bo][eip]_)(?:' . join("|", keys %both) . ')\b';
+}
+next if !/$todo_re/;
+my $orig = "$_";
+
+# x->func(op, rs)  ==>  slap_bi_op( x, <enum op_func>, op, rs)
+# x. func(op, rs)  ==>  slap_bi_op(&x, <enum op_func>, op, rs)
+s%(                                # 1: entire match: "<delim><function>("
+       ((?: [\)!=\;{}\\] | \*/ | \b if\s*\( | \b return \b ) \s*) # 2: delim
+       (\(\s* (?:\* \s*)?)?        # 3: optional "(*" or "(" in (*f)()
+       ($obj_re) \s* (->|\.)  \s*  # 4: object,          5: "->" or "."
+       (?=(b[ie]_))($func_re) \s*  # 6: "bi_" or "be_",  7: function
+       (\)\s*)?                    # 8: optional ")" in (*f),
+    (\(\s*)                     # 9: "(" + whitespace
+)% (!$3) == (!$8) ? "$2slap_$6op$9$addr{$5}$4, $func2op{$7}, " : $1 %egox;
+
+# (&x->bi_op_bind)[which](op, rs)  ==>  slap_bi_op(x, which, op, rs)
+#    (&x->be_bind)[which](op, rs)  ==>  slap_be_op(x, which, op, rs)
+s/\(&(\w+)->b(?=([ei]))(?:e|i_op)_bind\)\[\s* (\w+) \s*\] \((\s*) ([^()]*)\)
+ /slap_b$2_op($4$1, $3, $5)/gox;
+
+# slap_bi_op(x->bd_info, which, op, rs)  ==>  slap_be_op( x, which, op, rs)
+# slap_bi_op(x. bd_info, which, op, rs)  ==>  slap_be_op(&x, which, op, rs)
+s/\b slap_bi_op (\(\s*) ($obj_re) \s* (->|\.) \s* bd_info \s*,
+ /slap_be_op$1$addr{$3}$2,/gox;
+
+# slap_be_op(op->o_bd, which, &op, rs)   ==>  SLAP_OP(which,  op, rs)
+# slap_be_op(op. o_bd, which, &op, rs)   ==>  SLAP_OP(which, &op, rs)
+s/\b(slap_be_op (\(\s*) ($obj_re) \s*(->|\.)\s* o_bd, \s (\w+, \s (&?)\3,))
+ / $addr{$4} eq $6 ? "SLAP_OP$2$5" : die "$ARGV: Bad syntax: $1\n" /egox;
+
+my $changed = $_ ne $orig;
+
+# When changing a file, do some whitespace cleanup too
+if ($changed) {
+       s/\b ((SLAP_OP|slap_b[ei](func)?_op) \b .*?) [\ \t]+$ /$1/gmx;
+       s/\A\s*\n//;
+       s/\s*\z/\n/;
+}
+
+file_result($_, $changed);
+
+####
+
+# Return remaining lines that contain operation method names
+sub remaining {
+       my($contents) = @_;
+       return $contents !~ /$func_re/o ? () : grep {
+               !/^\# [ \t]* define \s+ ($func_re|slap_bi_op\b) /x &&
+               # Skip "if ( (&bi->bi_op_bind)[ which ] )" and variants
+               !/^(\} \s* else \s*)? if \s* \( \s*
+                       \(& (\w+ | \(\s*\w+\s*=\s*$obj_re\s*\)) -> bi_op_bind\)
+                       \s* \[ \s* \w+ \s* \]
+                       \s* [&|\)]/ox;
+       } $contents =~ m% ^[\ \t]* (?=\S) (
+               # The line contains a member opfunction
+               .*? (?:->|\.) \s* $func_re
+
+               # Skip if the member function is assigned, compared,
+               # 'and/or'ed, followed by a word (this is a comment), or by
+               # ') {' or ') word' (function is the boolean in an if/while).
+               (?! \s* (?: [!=&|\w] | \)\s*[\{\w] ))
+
+               .*?
+       ) \s*?$ %gmox;
+}
+
+# %func2op: Member functions => slap_operation_t
+__DATA__
+be_bind             bi_op_bind          => op_bind
+be_unbind           bi_op_unbind        => op_unbind
+be_search           bi_op_search        => op_search
+be_compare          bi_op_compare       => op_compare
+be_modify           bi_op_modify        => op_modify
+be_modrdn           bi_op_modrdn        => op_modrdn
+be_add              bi_op_add           => op_add
+be_delete           bi_op_delete        => op_delete
+be_abandon          bi_op_abandon       => op_abandon
+be_extended         bi_extended         => op_extended
+be_cancel           bi_op_cancel        => op_cancel
+be_operational      bi_operational      => op_aux_operational
+be_chk_referrals    bi_chk_referrals    => op_aux_chk_referrals
+be_chk_controls     bi_chk_controls     => op_aux_chk_controls
index 2893b92dfcb8d1880ab01afce910279450d37eac..0e334d937da5b618ea3d1c8720ccac05534072dc 100644 (file)
@@ -882,6 +882,69 @@ send_result:;
        return rc;
 }
 
+/* Inlined in proto-slap.h, sans assertions, when !(USE_RS_ASSERT) */
+int
+(slap_bi_op)(
+       BackendInfo *bi,
+       slap_operation_t which,
+       Operation *op,
+       SlapReply *rs )
+{
+       int rc;
+#ifndef slap_bi_op
+       void (*rsCheck)( const SlapReply *rs ) =
+               which < op_aux_operational ? rs_assert_ready : rs_assert_ok;
+#else
+#      define rsCheck(rs) ((void) 0)
+#endif
+       BI_op_func *fn;
+
+       assert( bi != NULL );
+       assert( (unsigned) which < (unsigned) op_last );
+
+       fn = (&bi->bi_op_bind)[ which ];
+
+       assert( op != NULL );
+       assert( rs != NULL );
+       assert( fn != 0 );
+       rsCheck( rs );
+
+       rc = fn( op, rs );
+
+#ifndef slap_bi_op
+       if ( rc != SLAP_CB_CONTINUE && rc != SLAP_CB_BYPASS ) {
+               int err = rs->sr_err;
+
+               if ( 0 )        /* TODO */
+               if ( err == LDAP_COMPARE_TRUE || err == LDAP_COMPARE_FALSE ) {
+                       assert( which == op_compare );
+                       assert( rc == LDAP_SUCCESS );
+               }
+
+               rsCheck = which < op_extended ? rs_assert_done : rs_assert_ok;
+               if ( which == op_aux_chk_referrals ) {
+                       if      ( rc == LDAP_SUCCESS  ) rsCheck = rs_assert_ready;
+                       else if ( rc == LDAP_REFERRAL ) rsCheck = rs_assert_done;
+               } else if ( which == op_bind ) {
+                       if      ( rc == LDAP_SUCCESS  ) rsCheck = rs_assert_ok;
+               }
+
+               /* TODO: Just what is the relation between rc and rs->sr_err? */
+               if ( rc != err &&
+                       (rc != LDAP_SUCCESS ||
+                        (err != LDAP_COMPARE_TRUE && err != LDAP_COMPARE_FALSE)) )
+               {
+                       rs->sr_err = rc;
+                       rsCheck( rs );
+                       rs->sr_err = err;
+               }
+       }
+       rsCheck( rs );
+#endif
+
+       return rc;
+}
+
 int
 be_entry_release_rw(
        Operation *op,
index 80372a92675e2effde785834f4eb234ebed0d30a..cd0dc3ff9ed0886632a4dcfd6da6ee2de1bed943 100644 (file)
@@ -376,6 +376,16 @@ LDAP_SLAPD_F (struct berval *) be_root_dn LDAP_P(( Backend *be ));
 LDAP_SLAPD_F (int) be_entry_get_rw LDAP_P(( Operation *o,
                struct berval *ndn, ObjectClass *oc,
                AttributeDescription *at, int rw, Entry **e ));
+
+/* "backend->ophandler(op,rs)" wrappers, applied by contrib:wrap_slap_ops */
+#define SLAP_OP(which, op, rs)  slap_bi_op((op)->o_bd->bd_info, which, op, rs)
+#define slap_be_op(be, which, op, rs) slap_bi_op((be)->bd_info, which, op, rs)
+#if !(defined(USE_RS_ASSERT) && (USE_RS_ASSERT))
+#define slap_bi_op(bi, which, op, rs) ((&(bi)->bi_op_bind)[which](op, rs))
+#endif
+LDAP_SLAPD_F (int) (slap_bi_op) LDAP_P(( BackendInfo *bi,
+       slap_operation_t which, Operation *op, SlapReply *rs ));
+
 LDAP_SLAPD_F (int) be_entry_release_rw LDAP_P((
        Operation *o, Entry *e, int rw ));
 #define be_entry_release_r( o, e ) be_entry_release_rw( o, e, 0 )
index 5858496b14d093d41f20e4c6012f7f878bd71526..2d3348b270373389f15e9fb0e4fe9d99dd977613 100644 (file)
@@ -132,7 +132,21 @@ slap_req2res( ber_tag_t tag )
        return tag;
 }
 
-/* SlapReply debugging, prodo-slap.h overrides it in OpenLDAP releases */
+/*
+ * SlapReply debugging enabled by USE_RS_ASSERT.
+ *
+ * Disabled by default, but compiled in (but still unused) when
+ * LDAP_TEST.  #define USE_RS_ASSERT as nonzero to enable some
+ * assertions which check the SlapReply.  USE_RS_ASSERT = 2 or higher
+ * check aggressively, currently some code fail these tests.
+ *
+ * Environment variable $NO_RS_ASSERT controls how USE_RS_ASSERT handles
+ * errors.  > 0: ignore errors, 0: abort (the default), < 0: just warn.
+ *
+ * Wrap LDAP operation calls in macros SLAP_OP() & co from proto-slap.h
+ * to check the SlapReply.  contrib/slapd-tools/wrap_slap_ops converts
+ * source code to use the macros.
+ */
 #if defined(LDAP_TEST) || (defined(USE_RS_ASSERT) && (USE_RS_ASSERT))
 
 int rs_suppress_assert = 0;