]> granicus.if.org Git - strace/blobdiff - nlattr.c
nlattr: add unsigned int decoders that print in hex form
[strace] / nlattr.c
index 76010c446d17c818ede8225b00456695ca54f7c4..83a25bd6f402a0126ce58a488c2a8505c21d216c 100644 (file)
--- a/nlattr.c
+++ b/nlattr.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
  * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
- * Copyright (c) 2016-2017 The strace developers.
+ * Copyright (c) 2016-2018 The strace developers.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 
 #include "defs.h"
+#include <endian.h>
 #include "netlink.h"
 #include "nlattr.h"
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include <linux/sock_diag.h>
+#include "static_assert.h"
+
+#include "xlat/netlink_sk_meminfo_indices.h"
 
 static bool
 fetch_nlattr(struct tcb *const tcp, struct nlattr *const nlattr,
-            const kernel_ulong_t addr, const unsigned int len)
+            const kernel_ulong_t addr, const unsigned int len,
+            const bool in_array)
 {
        if (len < sizeof(struct nlattr)) {
                printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
                return false;
        }
 
-       if (umove_or_printaddr(tcp, addr, nlattr))
-               return false;
+       if (tfetch_obj(tcp, addr, nlattr))
+               return true;
 
-       return true;
+       if (in_array) {
+               tprints("...");
+               printaddr_comment(addr);
+       } else {
+               printaddr(addr);
+       }
+
+       return false;
 }
 
 static void
@@ -52,11 +66,18 @@ print_nlattr(const struct nlattr *const nla,
             const struct xlat *const table,
             const char *const dflt)
 {
+       static_assert(NLA_TYPE_MASK == ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER),
+                     "wrong NLA_TYPE_MASK");
+
        tprintf("{nla_len=%u, nla_type=", nla->nla_len);
-       if (nla->nla_type & NLA_F_NESTED)
-               tprints("NLA_F_NESTED|");
-       if (nla->nla_type & NLA_F_NET_BYTEORDER)
-               tprints("NLA_F_NET_BYTEORDER|");
+       if (nla->nla_type & NLA_F_NESTED) {
+               print_xlat(NLA_F_NESTED);
+               tprints("|");
+       }
+       if (nla->nla_type & NLA_F_NET_BYTEORDER) {
+               print_xlat(NLA_F_NET_BYTEORDER);
+               tprints("|");
+       }
        printxval(table, nla->nla_type & NLA_TYPE_MASK, dflt);
        tprints("}");
 }
@@ -72,7 +93,7 @@ decode_nlattr_with_data(struct tcb *const tcp,
                        const unsigned int size,
                        const void *const opaque_data)
 {
-       const unsigned int nla_len = nla->nla_len > len ? len : nla->nla_len;
+       const unsigned int nla_len = MIN(nla->nla_len, len);
 
        if (nla_len > NLA_HDRLEN)
                tprints("{");
@@ -80,13 +101,18 @@ decode_nlattr_with_data(struct tcb *const tcp,
        print_nlattr(nla, table, dflt);
 
        if (nla_len > NLA_HDRLEN) {
+               const unsigned int idx = size ? nla->nla_type : 0;
+
                tprints(", ");
                if (!decoders
-                   || nla->nla_type >= size
-                   || !decoders[nla->nla_type]
-                   || !decoders[nla->nla_type](tcp, addr + NLA_HDRLEN,
-                                               nla_len - NLA_HDRLEN,
-                                               opaque_data))
+                   || (size && idx >= size)
+                   || !decoders[idx]
+                   || !decoders[idx](
+                               tcp, addr + NLA_HDRLEN,
+                               nla_len - NLA_HDRLEN,
+                               size ? opaque_data
+                                    : (const void *) (uintptr_t) nla->nla_type)
+                   )
                        printstr_ex(tcp, addr + NLA_HDRLEN,
                                    nla_len - NLA_HDRLEN, QUOTE_FORCE_HEX);
                tprints("}");
@@ -104,10 +130,17 @@ decode_nlattr(struct tcb *const tcp,
              const void *const opaque_data)
 {
        struct nlattr nla;
-       bool print_array = false;
+       bool is_array = false;
        unsigned int elt;
 
-       for (elt = 0; fetch_nlattr(tcp, &nla, addr, len); elt++) {
+       if (decoders && !size && opaque_data)
+               error_func_msg("[xlat %p, dflt \"%s\", decoders %p] "
+                              "size is zero (going to pass nla_type as "
+                              "decoder argument), but opaque data (%p) is not "
+                              "- will be ignored",
+                              table, dflt, decoders, opaque_data);
+
+       for (elt = 0; fetch_nlattr(tcp, &nla, addr, len, is_array); elt++) {
                if (abbrev(tcp) && elt == max_strlen) {
                        tprints("...");
                        break;
@@ -124,9 +157,9 @@ decode_nlattr(struct tcb *const tcp,
                                next_addr = addr + nla_len;
                }
 
-               if (!print_array && next_addr) {
+               if (!is_array && next_addr) {
                        tprints("[");
-                       print_array = true;
+                       is_array = true;
                }
 
                decode_nlattr_with_data(tcp, &nla, addr, len, table, dflt,
@@ -140,7 +173,7 @@ decode_nlattr(struct tcb *const tcp,
                len = next_len;
        }
 
-       if (print_array) {
+       if (is_array) {
                tprints("]");
        }
 }
@@ -167,24 +200,6 @@ decode_nla_strn(struct tcb *const tcp,
        return true;
 }
 
-static bool
-print_meminfo(struct tcb *const tcp,
-             void *const elem_buf,
-             const size_t elem_size,
-             void *const opaque_data)
-{
-       unsigned int *const count = opaque_data;
-
-       if ((*count)++ >= SK_MEMINFO_VARS) {
-               tprints("...");
-               return false;
-       }
-
-       tprintf("%" PRIu32, *(uint32_t *) elem_buf);
-
-       return true;
-}
-
 bool
 decode_nla_meminfo(struct tcb *const tcp,
                   const kernel_ulong_t addr,
@@ -198,8 +213,28 @@ decode_nla_meminfo(struct tcb *const tcp,
                return false;
 
        unsigned int count = 0;
-       print_array(tcp, addr, nmemb, &mem, sizeof(mem),
-                   umoven_or_printaddr, print_meminfo, &count);
+       print_array_ex(tcp, addr, nmemb, &mem, sizeof(mem),
+                      tfetch_mem, print_uint32_array_member, &count,
+                      PAF_PRINT_INDICES | PAF_INDEX_XLAT_VALUE_INDEXED
+                       | XLAT_STYLE_FMT_U,
+                      ARRSZ_PAIR(netlink_sk_meminfo_indices),
+                      "SK_MEMINFO_???");
+
+       return true;
+}
+
+bool
+decode_nla_fd(struct tcb *const tcp,
+             const kernel_ulong_t addr,
+             const unsigned int len,
+             const void *const opaque_data)
+{
+       int fd;
+
+       if (len < sizeof(fd))
+               return false;
+       else if (!umove_or_printaddr(tcp, addr, &fd))
+               printfd(tcp, fd);
 
        return true;
 }
@@ -220,6 +255,149 @@ decode_nla_ifindex(struct tcb *const tcp,
        return true;
 }
 
+bool
+decode_nla_xval(struct tcb *const tcp,
+               const kernel_ulong_t addr,
+               const unsigned int len,
+               const void *const opaque_data)
+{
+       const struct decode_nla_xlat_opts * const opts = opaque_data;
+       union {
+               uint64_t val;
+               uint8_t  bytes[sizeof(uint64_t)];
+       } data;
+       const size_t bytes_offs = is_bigendian ? sizeof(data) - len : 0;
+
+       data.val = 0;
+
+       if (len > sizeof(data))
+               return false;
+       else if (!umoven_or_printaddr(tcp, addr, len, data.bytes + bytes_offs))
+       {
+               if (opts->process_fn)
+                       data.val = opts->process_fn(data.val);
+               if (opts->prefix)
+                       tprints(opts->prefix);
+               printxval_dispatch_ex(opts->xlat, opts->xlat_size, data.val,
+                                     opts->dflt, opts->xt, opts->style);
+               if (opts->suffix)
+                       tprints(opts->suffix);
+       }
+
+       return true;
+}
+
+static uint64_t
+process_host_order(uint64_t val)
+{
+       return ntohs(val);
+}
+
+bool
+decode_nla_ether_proto(struct tcb *const tcp,
+                      const kernel_ulong_t addr,
+                      const unsigned int len,
+                      const void *const opaque_data)
+{
+       const struct decode_nla_xlat_opts opts = {
+               .xlat = ethernet_protocols,
+               .xlat_size = ethernet_protocols_size,
+               .dflt = "ETHER_P_???",
+               .xt = XT_SORTED,
+               .prefix = "htons(",
+               .suffix = ")",
+               .process_fn = process_host_order,
+       };
+
+       return decode_nla_xval(tcp, addr, len, &opts);
+}
+
+bool
+decode_nla_ip_proto(struct tcb *const tcp,
+                   const kernel_ulong_t addr,
+                   const unsigned int len,
+                   const void *const opaque_data)
+{
+       const struct decode_nla_xlat_opts opts = {
+               .xlat = inet_protocols,
+               .xlat_size = inet_protocols_size,
+               .xt = XT_SORTED,
+               .dflt = "IPPROTO_???",
+       };
+
+       return decode_nla_xval(tcp, addr, len, &opts);
+}
+
+bool
+decode_nla_flags(struct tcb *const tcp,
+                const kernel_ulong_t addr,
+                const unsigned int len,
+                const void *const opaque_data)
+{
+       const struct decode_nla_xlat_opts * const opts = opaque_data;
+       union {
+               uint64_t flags;
+               uint8_t  bytes[sizeof(uint64_t)];
+       } data = { .flags = 0 };
+       const size_t bytes_offs = is_bigendian ? sizeof(data) - len : 0;
+
+       if (opts->xt == XT_INDEXED)
+               error_func_msg("indexed xlats are currently incompatible with "
+                              "printflags");
+
+       if (len > sizeof(data))
+               return false;
+       else if (!umoven_or_printaddr(tcp, addr, len, data.bytes + bytes_offs))
+       {
+               if (opts->process_fn)
+                       data.flags = opts->process_fn(data.flags);
+               if (opts->prefix)
+                       tprints(opts->prefix);
+               printflags_ex(data.flags, opts->dflt, opts->style, opts->xlat,
+                             NULL);
+               if (opts->suffix)
+                       tprints(opts->suffix);
+       }
+
+       return true;
+}
+
+bool
+decode_nla_be16(struct tcb *const tcp,
+               const kernel_ulong_t addr,
+               const unsigned int len,
+               const void *const opaque_data)
+{
+       uint16_t num;
+
+       if (len < sizeof(num))
+               return false;
+       else if (!umove_or_printaddr(tcp, addr, &num))
+               tprintf("htons(%u)", ntohs(num));
+
+       return true;
+}
+
+bool
+decode_nla_be64(struct tcb *const tcp,
+               const kernel_ulong_t addr,
+               const unsigned int len,
+               const void *const opaque_data)
+{
+#if defined HAVE_BE64TOH || defined be64toh
+       uint64_t num;
+
+       if (len < sizeof(num))
+               return false;
+       else if (!umove_or_printaddr(tcp, addr, &num))
+               tprintf("htobe64(%" PRIu64 ")", be64toh(num));
+
+       return true;
+#else
+       return false;
+#endif
+}
+
 #define DECODE_NLA_INTEGER(name, type, fmt)            \
 bool                                                   \
 decode_nla_ ## name(struct tcb *const tcp,             \
@@ -236,6 +414,10 @@ decode_nla_ ## name(struct tcb *const tcp,         \
        return true;                                    \
 }
 
+DECODE_NLA_INTEGER(x8, uint8_t, "%#" PRIx8)
+DECODE_NLA_INTEGER(x16, uint16_t, "%#" PRIx16)
+DECODE_NLA_INTEGER(x32, uint32_t, "%#" PRIx32)
+DECODE_NLA_INTEGER(x64, uint64_t, "%#" PRIx64)
 DECODE_NLA_INTEGER(u8, uint8_t, "%" PRIu8)
 DECODE_NLA_INTEGER(u16, uint16_t, "%" PRIu16)
 DECODE_NLA_INTEGER(u32, uint32_t, "%" PRIu32)