| /* |
| * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr> |
| * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com> |
| * Copyright (c) 2016-2017 The strace developers. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "defs.h" |
| #include "netlink.h" |
| #include "nlattr.h" |
| |
| static bool |
| fetch_nlattr(struct tcb *const tcp, struct nlattr *const nlattr, |
| const kernel_ulong_t addr, const kernel_ulong_t len) |
| { |
| if (len < sizeof(struct nlattr)) { |
| printstrn(tcp, addr, len); |
| return false; |
| } |
| |
| if (umove_or_printaddr(tcp, addr, nlattr)) |
| return false; |
| |
| return true; |
| } |
| |
| static void |
| print_nlattr(const struct nlattr *const nla, |
| const struct xlat *const table, |
| const char *const dflt) |
| { |
| 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|"); |
| printxval(table, nla->nla_type & NLA_TYPE_MASK, dflt); |
| tprints("}"); |
| } |
| |
| static void |
| decode_nlattr_with_data(struct tcb *const tcp, |
| const struct nlattr *const nla, |
| const kernel_ulong_t addr, |
| const kernel_ulong_t len, |
| const struct xlat *const table, |
| const char *const dflt, |
| const nla_decoder_t *const decoders, |
| const unsigned int size, |
| const void *const opaque_data) |
| { |
| const unsigned int nla_len = nla->nla_len > len ? len : nla->nla_len; |
| |
| if (nla_len > NLA_HDRLEN) |
| tprints("{"); |
| |
| print_nlattr(nla, table, dflt); |
| |
| if (nla_len > NLA_HDRLEN) { |
| 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)) |
| printstrn(tcp, addr + NLA_HDRLEN, len - NLA_HDRLEN); |
| tprints("}"); |
| } |
| } |
| |
| void |
| decode_nlattr(struct tcb *const tcp, |
| kernel_ulong_t addr, |
| kernel_ulong_t len, |
| const struct xlat *const table, |
| const char *const dflt, |
| const nla_decoder_t *const decoders, |
| const unsigned int size, |
| const void *const opaque_data) |
| { |
| struct nlattr nla; |
| bool print_array = false; |
| unsigned int elt; |
| |
| for (elt = 0; fetch_nlattr(tcp, &nla, addr, len); elt++) { |
| if (abbrev(tcp) && elt == max_strlen) { |
| tprints("..."); |
| break; |
| } |
| |
| const unsigned long nla_len = NLA_ALIGN(nla.nla_len); |
| kernel_ulong_t next_addr = 0; |
| kernel_ulong_t next_len = 0; |
| |
| if (nla.nla_len >= NLA_HDRLEN) { |
| next_len = (len >= nla_len) ? len - nla_len : 0; |
| |
| if (next_len && addr + nla_len > addr) |
| next_addr = addr + nla_len; |
| } |
| |
| if (!print_array && next_addr) { |
| tprints("["); |
| print_array = true; |
| } |
| |
| decode_nlattr_with_data(tcp, &nla, addr, len, table, dflt, |
| decoders, size, opaque_data); |
| |
| if (!next_addr) |
| break; |
| |
| tprints(", "); |
| addr = next_addr; |
| len = next_len; |
| } |
| |
| if (print_array) { |
| tprints("]"); |
| } |
| } |
| |
| bool |
| decode_nla_str(struct tcb *const tcp, |
| const kernel_ulong_t addr, |
| const kernel_ulong_t len, |
| const void *const opaque_data) |
| { |
| printstr_ex(tcp, addr, len, QUOTE_0_TERMINATED); |
| |
| return true; |
| } |
| |
| bool |
| decode_nla_strn(struct tcb *const tcp, |
| const kernel_ulong_t addr, |
| const kernel_ulong_t len, |
| const void *const opaque_data) |
| { |
| printstrn(tcp, addr, len); |
| |
| return true; |
| } |
| |
| #define DECODE_NLA_INTEGER(name, type, fmt) \ |
| bool \ |
| decode_nla_ ## name(struct tcb *const tcp, \ |
| const kernel_ulong_t addr, \ |
| const kernel_ulong_t len, \ |
| const void *const opaque_data) \ |
| { \ |
| type num; \ |
| \ |
| if (len < sizeof(num)) \ |
| return false; \ |
| if (!umove_or_printaddr(tcp, addr, &num)) \ |
| tprintf(fmt, num); \ |
| return true; \ |
| } |
| |
| DECODE_NLA_INTEGER(u8, uint8_t, "%" PRIu8) |
| DECODE_NLA_INTEGER(u16, uint16_t, "%" PRIu16) |
| DECODE_NLA_INTEGER(u32, uint32_t, "%" PRIu32) |
| DECODE_NLA_INTEGER(u64, uint64_t, "%" PRIu64) |
| DECODE_NLA_INTEGER(s8, int8_t, "%" PRId8) |
| DECODE_NLA_INTEGER(s16, int16_t, "%" PRId16) |
| DECODE_NLA_INTEGER(s32, int32_t, "%" PRId32) |
| DECODE_NLA_INTEGER(s64, int64_t, "%" PRId64) |