MINOR: trace: retrieve useful pointers and enforce lock-on

Now we try to find frontend, listener, backend, server, connection,
session, stream, from the presented argument of type connection,
stream or session. Various combinations and bounces allow to
retrieve most of them almost all the time. The extraction is
performed early so that we'll be able to apply filters later.

The lock-on is set if it was not there while the trace is running and
a valid pointer is available. If it was already set and doesn't match,
no trace is produced.
diff --git a/src/trace.c b/src/trace.c
index 3ba4f81..039bf3a 100644
--- a/src/trace.c
+++ b/src/trace.c
@@ -48,6 +48,26 @@
 REGISTER_PER_THREAD_ALLOC(alloc_trace_buffers_per_thread);
 REGISTER_PER_THREAD_FREE(free_trace_buffers_per_thread);
 
+/* pick the lowest non-null argument with a non-null arg_def mask */
+static inline const void *trace_pick_arg(uint32_t arg_def, const void *a1, const void *a2, const void *a3, const void *a4)
+{
+	if (arg_def & 0x0000FFFF) {
+		if ((arg_def & 0x000000FF) && a1)
+			return a1;
+		if ((arg_def & 0x0000FF00) && a2)
+			return a2;
+	}
+
+	if (arg_def & 0xFFFF0000) {
+		if ((arg_def & 0x00FF0000) && a3)
+			return a3;
+		if ((arg_def & 0xFF000000) && a4)
+			return a4;
+	}
+
+	return NULL;
+}
+
 /* write a message for the given trace source */
 void __trace(enum trace_level level, uint64_t mask, struct trace_source *src, const struct ist where,
              const void *a1, const void *a2, const void *a3, const void *a4,
@@ -55,6 +75,14 @@
                         const void *a1, const void *a2, const void *a3, const void *a4),
              const struct ist msg)
 {
+	const struct listener *li = NULL;
+	const struct proxy *fe = NULL;
+	const struct proxy *be = NULL;
+	const struct server *srv = NULL;
+	const struct session *sess = NULL;
+	const struct stream *strm = NULL;
+	const struct connection *conn = NULL;
+	const void *lockon_ptr = NULL;
 	struct ist line[8];
 
 	if (likely(src->state == TRACE_STATE_STOPPED))
@@ -64,6 +92,46 @@
 	if (((src->report_events | src->start_events | src->pause_events | src->stop_events) & mask) == 0)
 		return;
 
+	/* retrieve available information from the caller's arguments */
+	if (src->arg_def & TRC_ARGS_CONN)
+		conn = trace_pick_arg(src->arg_def & TRC_ARGS_CONN, a1, a2, a3, a4);
+
+	if (src->arg_def & TRC_ARGS_SESS)
+		sess = trace_pick_arg(src->arg_def & TRC_ARGS_SESS, a1, a2, a3, a4);
+
+	if (src->arg_def & TRC_ARGS_STRM)
+		strm = trace_pick_arg(src->arg_def & TRC_ARGS_STRM, a1, a2, a3, a4);
+
+	if (!sess && strm)
+		sess = strm->sess;
+	else if (!sess && conn)
+		sess = conn->owner;
+
+	if (sess) {
+		fe = sess->fe;
+		li = sess->listener;
+	}
+
+	if (!li && conn)
+		li = objt_listener(conn->target);
+
+	if (li && !fe)
+		fe = li->bind_conf->frontend;
+
+	if (strm) {
+		be = strm->be;
+		srv = strm->srv_conn;
+	}
+
+	if (!srv && conn)
+		srv = objt_server(conn->target);
+
+	if (srv && !be)
+		be = srv->proxy;
+
+	if (!be && conn)
+		be = objt_proxy(conn->target);
+
 	/* TODO: add handling of filters here, return if no match (not even update states) */
 
 	/* check if we need to start the trace now */
@@ -75,7 +143,31 @@
 		HA_ATOMIC_STORE(&src->state, TRACE_STATE_RUNNING);
 	}
 
+	/* we may want to lock on a particular object */
+	if (src->lockon != TRACE_LOCKON_NOTHING) {
+		switch (src->lockon) {
+		case TRACE_LOCKON_BACKEND:    lockon_ptr = be;   break;
+		case TRACE_LOCKON_CONNECTION: lockon_ptr = conn; break;
+		case TRACE_LOCKON_FRONTEND:   lockon_ptr = fe;   break;
+		case TRACE_LOCKON_LISTENER:   lockon_ptr = li;   break;
+		case TRACE_LOCKON_SERVER:     lockon_ptr = srv;  break;
+		case TRACE_LOCKON_SESSION:    lockon_ptr = sess; break;
+		case TRACE_LOCKON_STREAM:     lockon_ptr = strm; break;
+		case TRACE_LOCKON_THREAD:     lockon_ptr = ti;   break;
+		case TRACE_LOCKON_ARG1:       lockon_ptr = a1;   break;
+		case TRACE_LOCKON_ARG2:       lockon_ptr = a2;   break;
+		case TRACE_LOCKON_ARG3:       lockon_ptr = a3;   break;
+		case TRACE_LOCKON_ARG4:       lockon_ptr = a4;   break;
+		default: break; // silence stupid gcc -Wswitch
+		}
+
+		if (src->lockon_ptr && src->lockon_ptr != lockon_ptr)
+			return;
+
+		if (!src->lockon_ptr && lockon_ptr && src->state == TRACE_STATE_RUNNING)
+			HA_ATOMIC_STORE(&src->lockon_ptr, lockon_ptr);
+	}
+
-	/* TODO: add check of lockon+lockon_ptr here, return if no match */
 	/* here the trace is running and is tracking a desired item */
 
 	if ((src->report_events & mask) == 0 || level > src->level)