static void
print_cap_data(struct tcb *tcp, unsigned long addr, const cap_user_header_t h)
{
	struct user_cap_data_struct data[2];
	unsigned int len;

	if (!addr || !h) {
		printaddr(addr);
		return;
	}

	if (_LINUX_CAPABILITY_VERSION_2 == h->version ||
	    _LINUX_CAPABILITY_VERSION_3 == h->version)
		len = 2;
	else
		len = 1;

	if (umoven_or_printaddr(tcp, addr, len * sizeof(data[0]), data))
		return;

	tprints("{");
	print_cap_bits(data[0].effective, len > 1 ? data[1].effective : 0);
	tprints(", ");
	print_cap_bits(data[0].permitted, len > 1 ? data[1].permitted : 0);
	tprints(", ");
	print_cap_bits(data[0].inheritable, len > 1 ? data[1].inheritable : 0);
	tprints("}");
}
Beispiel #2
0
bool
decode_nla_linkinfo_xstats_can(struct tcb *const tcp,
			       const kernel_ulong_t addr,
			       const unsigned int len,
			       const void *const opaque_data)
{
	struct strace_can_device_stats {
		uint32_t bus_error;
		uint32_t error_warning;
		uint32_t error_passive;
		uint32_t bus_off;
		uint32_t arbitration_lost;
		uint32_t restarts;
	} st;
	const unsigned int def_size = sizeof(st);
	const unsigned int size = (len >= def_size) ? def_size : 0;

	if (!size)
		return false;

	if (umoven_or_printaddr(tcp, addr, size, &st))
		return true;

	PRINT_FIELD_U("{", st, bus_error);
	PRINT_FIELD_U(", ", st, error_warning);
	PRINT_FIELD_U(", ", st, error_passive);
	PRINT_FIELD_U(", ", st, bus_off);
	PRINT_FIELD_U(", ", st, arbitration_lost);
	PRINT_FIELD_U(", ", st, restarts);
	tprints("}");

	return true;
}
Beispiel #3
0
static void
print_sched_attr(struct tcb *const tcp, const kernel_ulong_t addr,
		 unsigned int size)
{
	struct {
		uint32_t size;
		uint32_t sched_policy;
		uint64_t sched_flags;
		uint32_t sched_nice;
		uint32_t sched_priority;
		uint64_t sched_runtime;
		uint64_t sched_deadline;
		uint64_t sched_period;
	} attr = {};

	if (size > sizeof(attr))
		size = sizeof(attr);
	if (umoven_or_printaddr(tcp, addr, size, &attr))
		return;

	tprintf("{size=%u, sched_policy=", attr.size);
	printxval(schedulers, attr.sched_policy, "SCHED_???");
	tprints(", sched_flags=");
	printflags64(sched_flags, attr.sched_flags, "SCHED_FLAG_???");
	tprintf(", sched_nice=%d", attr.sched_nice);
	tprintf(", sched_priority=%u", attr.sched_priority);
	tprintf(", sched_runtime=%" PRIu64, attr.sched_runtime);
	tprintf(", sched_deadline=%" PRIu64, attr.sched_deadline);
	tprintf(", sched_period=%" PRIu64 "}", attr.sched_period);
}
Beispiel #4
0
static bool
decode_tc_stats(struct tcb *const tcp,
		const kernel_ulong_t addr,
		const unsigned int len,
		const void *const opaque_data)
{
	struct tc_stats st;
	const unsigned int sizeof_tc_stats =
		offsetofend(struct tc_stats, backlog);

	if (len < sizeof_tc_stats)
		return false;
	else if (!umoven_or_printaddr(tcp, addr, sizeof_tc_stats, &st)) {
		PRINT_FIELD_U("{", st, bytes);
		PRINT_FIELD_U(", ", st, packets);
		PRINT_FIELD_U(", ", st, drops);
		PRINT_FIELD_U(", ", st, overlimits);
		PRINT_FIELD_U(", ", st, bps);
		PRINT_FIELD_U(", ", st, pps);
		PRINT_FIELD_U(", ", st, qlen);
		PRINT_FIELD_U(", ", st, backlog);
		tprints("}");
	}

	return true;
}
static void
printargv(struct tcb *tcp, long addr)
{
	union {
		unsigned int p32;
		unsigned long p64;
		char data[sizeof(long)];
	} cp;
	const char *sep;
	unsigned int n = 0;
	const unsigned wordsize = current_wordsize;

	cp.p64 = 1;
	for (sep = ""; !abbrev(tcp) || n < max_strlen / 2; sep = ", ", ++n) {
		if (umoven_or_printaddr(tcp, addr, wordsize, cp.data))
			return;
		if (wordsize == 4)
			cp.p64 = cp.p32;
		if (cp.p64 == 0)
			break;
		tprints(sep);
		printstr(tcp, cp.p64, -1);
		addr += wordsize;
	}
	if (cp.p64)
		tprintf("%s...", sep);
}
Beispiel #6
0
static bool
decode_rtnl_link_stats64(struct tcb *const tcp,
		         const kernel_ulong_t addr,
			 const unsigned int len,
			 const void *const opaque_data)
{
#ifdef HAVE_STRUCT_RTNL_LINK_STATS64
	struct rtnl_link_stats64 st;
	const unsigned int min_size =
		offsetofend(struct rtnl_link_stats64, tx_compressed);
	const unsigned int def_size = sizeof(st);
	const unsigned int size =
		(len >= def_size) ? def_size :
				    ((len == min_size) ? min_size : 0);

	if (!size)
		return false;

	if (!umoven_or_printaddr(tcp, addr, size, &st)) {
		PRINT_FIELD_U("{", st, rx_packets);
		PRINT_FIELD_U(", ", st, tx_packets);
		PRINT_FIELD_U(", ", st, rx_bytes);
		PRINT_FIELD_U(", ", st, tx_bytes);
		PRINT_FIELD_U(", ", st, rx_errors);
		PRINT_FIELD_U(", ", st, tx_errors);
		PRINT_FIELD_U(", ", st, rx_dropped);
		PRINT_FIELD_U(", ", st, tx_dropped);
		PRINT_FIELD_U(", ", st, multicast);
		PRINT_FIELD_U(", ", st, collisions);

		PRINT_FIELD_U(", ", st, rx_length_errors);
		PRINT_FIELD_U(", ", st, rx_over_errors);
		PRINT_FIELD_U(", ", st, rx_crc_errors);
		PRINT_FIELD_U(", ", st, rx_frame_errors);
		PRINT_FIELD_U(", ", st, rx_fifo_errors);
		PRINT_FIELD_U(", ", st, rx_missed_errors);

		PRINT_FIELD_U(", ", st, tx_aborted_errors);
		PRINT_FIELD_U(", ", st, tx_carrier_errors);
		PRINT_FIELD_U(", ", st, tx_fifo_errors);
		PRINT_FIELD_U(", ", st, tx_heartbeat_errors);
		PRINT_FIELD_U(", ", st, tx_window_errors);

		PRINT_FIELD_U(", ", st, rx_compressed);
		PRINT_FIELD_U(", ", st, tx_compressed);
#ifdef HAVE_STRUCT_RTNL_LINK_STATS64_RX_NOHANDLER
		if (len >= def_size)
			PRINT_FIELD_U(", ", st, rx_nohandler);
#endif
		tprints("}");
	}

	return true;
#else
	return false;
#endif
}
Beispiel #7
0
static void
print_sigset_addr_len_limit(struct tcb *tcp, long addr, long len, long min_len)
{
	/*
	 * Here len is usually equal to NSIG / 8 or current_wordsize.
	 * But we code this defensively:
	 */
	if (len < min_len || len > NSIG / 8) {
		printaddr(addr);
		return;
	}
	int mask[NSIG / 8 / sizeof(int)] = {};
	if (umoven_or_printaddr(tcp, addr, len, mask))
		return;
	tprints(sprintsigmask_n("", mask, len));
}
Beispiel #8
0
static int
fetch_msgrcv_args(struct tcb *tcp, const long addr, unsigned long *pair)
{
	if (current_wordsize == sizeof(*pair)) {
		if (umoven_or_printaddr(tcp, addr, 2 * sizeof(*pair), pair))
			return -1;
	} else {
		unsigned int tmp[2];

		if (umove_or_printaddr(tcp, addr, &tmp))
			return -1;
		pair[0] = tmp[0];
		pair[1] = tmp[1];
	}
	return 0;
}
Beispiel #9
0
static void
print_sigset_addr_len_limit(struct tcb *const tcp, const kernel_ulong_t addr,
			    const kernel_ulong_t len, const unsigned int min_len)
{
	/*
	 * Here len is usually equal to NSIG_BYTES or current_wordsize.
	 * But we code this defensively:
	 */
	if (len < min_len || len > NSIG_BYTES) {
		printaddr(addr);
		return;
	}
	int mask[NSIG_BYTES / sizeof(int)] = {};
	if (umoven_or_printaddr(tcp, addr, len, mask))
		return;
	tprints(sprintsigmask_n("", mask, len));
}
Beispiel #10
0
static void
print_icmp_filter(struct tcb *tcp, const long addr, int len)
{
	struct icmp_filter filter = {};

	if (len > (int) sizeof(filter))
		len = sizeof(filter);
	else if (len <= 0) {
		printaddr(addr);
		return;
	}

	if (umoven_or_printaddr(tcp, addr, len, &filter))
		return;

	tprints("~(");
	printflags(icmpfilterflags, ~filter.data, "ICMP_???");
	tprints(")");
}
Beispiel #11
0
static int
umove_kulong_array_or_printaddr(struct tcb *const tcp, const kernel_ulong_t addr,
				kernel_ulong_t *const ptr, const size_t n)
{
#ifndef current_klongsize
	if (current_klongsize < sizeof(*ptr)) {
		uint32_t ptr32[n];
		int r = umove_or_printaddr(tcp, addr, &ptr32);
		if (!r) {
			size_t i;

			for (i = 0; i < n; ++i)
				ptr[i] = ptr32[i];
		}
		return r;
	}
#endif /* !current_klongsize */
	return umoven_or_printaddr(tcp, addr, n * sizeof(*ptr), ptr);
}
static void
decode_inet_diag_req_compat(struct tcb *const tcp,
			    const struct nlmsghdr *const nlmsghdr,
			    const uint8_t family,
			    const kernel_ulong_t addr,
			    const unsigned int len)
{
	struct inet_diag_req req = { .idiag_family = family };
	size_t offset = sizeof(req.idiag_family);
	bool decode_nla = false;

	PRINT_FIELD_XVAL("{", req, idiag_family, addrfams, "AF_???");
	tprints(", ");
	if (len >= sizeof(req)) {
		if (!umoven_or_printaddr(tcp, addr + offset,
					 sizeof(req) - offset,
					 (char *) &req + offset)) {
			PRINT_FIELD_U("", req, idiag_src_len);
			PRINT_FIELD_U(", ", req, idiag_dst_len);
			PRINT_FIELD_FLAGS(", ", req, idiag_ext,
					  inet_diag_extended_flags,
					  "1<<INET_DIAG_\?\?\?-1");
			PRINT_FIELD_INET_DIAG_SOCKID(", ", req, id,
						     req.idiag_family);
			PRINT_FIELD_FLAGS(", ", req, idiag_states,
					  tcp_state_flags, "1<<TCP_???");
			PRINT_FIELD_U(", ", req, idiag_dbs);
			decode_nla = true;
		}
	} else
		tprints("...");
	tprints("}");

	offset = NLMSG_ALIGN(sizeof(req));
	if (decode_nla && len > offset) {
		tprints(", ");
		decode_nlattr(tcp, addr + offset, len - offset,
			      inet_diag_req_attrs, "INET_DIAG_REQ_???",
			      inet_diag_req_nla_decoders,
			      ARRAY_SIZE(inet_diag_req_nla_decoders), NULL);
	}
}
Beispiel #13
0
void
printsock(struct tcb *tcp, long addr, int addrlen)
{
	sockaddr_buf_t addrbuf;

	if (addrlen < 2) {
		printaddr(addr);
		return;
	}

	if (addrlen > (int) sizeof(addrbuf))
		addrlen = sizeof(addrbuf);

	memset(&addrbuf, 0, sizeof(addrbuf));
	if (umoven_or_printaddr(tcp, addr, addrlen, addrbuf.pad))
		return;
	addrbuf.pad[sizeof(addrbuf.pad) - 1] = '\0';

	print_sockaddr(tcp, &addrbuf, addrlen);
}
static int
umove_kulong_array_or_printaddr(struct tcb *tcp, const long addr,
				kernel_ulong_t *ptr, size_t n)
{
#if defined X86_64 || defined X32
	if (current_personality == 1) {
#else
	if (current_wordsize < sizeof(*ptr)) {
#endif
		uint32_t ptr32[n];
		int r = umove_or_printaddr(tcp, addr, &ptr32);
		if (!r) {
			size_t i;

			for (i = 0; i < n; ++i)
				ptr[i] = (kernel_ulong_t) ptr32[i];
		}
		return r;
	}
	return umoven_or_printaddr(tcp, addr, n * sizeof(*ptr), ptr);
}

SYS_FUNC(pselect6)
{
	int rc = decode_select(tcp, tcp->u_arg, print_timespec, sprint_timespec);
	if (entering(tcp)) {
		kernel_ulong_t data[2];

		tprints(", ");
		if (!umove_kulong_array_or_printaddr(tcp, tcp->u_arg[5],
						     data, ARRAY_SIZE(data))) {
			tprints("{");
			/* NB: kernel requires data[1] == NSIG / 8 */
			print_sigset_addr_len(tcp, (unsigned long) data[0],
					      (unsigned long) data[1]);
			tprintf(", %llu}", (unsigned long long) data[1]);
		}
	}

	return rc;
}
Beispiel #15
0
void
print_sigset_addr_len(struct tcb *tcp, long addr, long len)
{
	char mask[NSIG / 8];

	/* Here len is usually equals NSIG / 8 or current_wordsize.
	 * But we code this defensively:
	 */
	if (len < 0) {
		printaddr(addr);
		return;
	}
	if (len >= NSIG / 8)
		len = NSIG / 8;
	else
		len = (len + 3) & ~3;

	if (umoven_or_printaddr(tcp, addr, len, mask))
		return;
	tprints(sprintsigmask_n("", mask, len));
}
Beispiel #16
0
static bool
decode_gnet_stats_basic(struct tcb *const tcp,
			const kernel_ulong_t addr,
			const unsigned int len,
			const void *const opaque_data)
{
#ifdef HAVE_STRUCT_GNET_STATS_BASIC
	struct gnet_stats_basic sb;
	const unsigned int sizeof_st_basic =
		offsetofend(struct gnet_stats_basic, packets);

	if (len < sizeof_st_basic)
		return false;
	else if (!umoven_or_printaddr(tcp, addr, sizeof_st_basic, &sb)) {
		PRINT_FIELD_U("{", sb, bytes);
		PRINT_FIELD_U(", ", sb, packets);
		tprints("}");
	}

	return true;
#else
	return false;
#endif
}
Beispiel #17
0
static bool
decode_rtnl_link_ifmap(struct tcb *const tcp,
		       const kernel_ulong_t addr,
		       const unsigned int len,
		       const void *const opaque_data)
{
	struct rtnl_link_ifmap map;
	const unsigned int sizeof_ifmap =
		offsetofend(struct rtnl_link_ifmap, port);

	if (len < sizeof_ifmap)
		return false;
	else if (!umoven_or_printaddr(tcp, addr, sizeof_ifmap, &map)) {
		PRINT_FIELD_X("{", map, mem_start);
		PRINT_FIELD_X(", ", map, mem_end);
		PRINT_FIELD_X(", ", map, base_addr);
		PRINT_FIELD_U(", ", map, irq);
		PRINT_FIELD_U(", ", map, dma);
		PRINT_FIELD_U(", ", map, port);
		tprints("}");
	}

	return true;
}
Beispiel #18
0
static void
print_affinitylist(struct tcb *const tcp, const kernel_ulong_t addr,
		   const unsigned int len)
{
	const unsigned int max_size = get_cpuset_size();
	const unsigned int umove_size = len < max_size ? len : max_size;
	const unsigned int size =
		(umove_size + current_wordsize - 1) & -current_wordsize;
	const unsigned int ncpu = size * 8;
	void *cpu;

	if (!verbose(tcp) || (exiting(tcp) && syserror(tcp)) ||
	    !addr || !len || !(cpu = calloc(size, 1))) {
		printaddr(addr);
		return;
	}

	if (!umoven_or_printaddr(tcp, addr, umove_size, cpu)) {
		int i = 0;
		const char *sep = "";

		tprints("[");
		for (;; i++) {
			i = next_set_bit(cpu, i, ncpu);
			if (i < 0)
				break;
			tprintf("%s%d", sep, i);
			sep = ", ";
		}
		if (size < len)
			tprintf("%s...", sep);
		tprints("]");
	}

	free(cpu);
}
Beispiel #19
0
static bool
decode_ifla_linkinfo(struct tcb *const tcp,
		     const kernel_ulong_t addr,
		     const unsigned int len,
		     const void *const opaque_data)
{
	struct ifla_linkinfo_ctx ctx = { .kind = "", };

	decode_nlattr(tcp, addr, len, rtnl_ifla_info_attrs,
		      "IFLA_INFO_???", ARRSZ_PAIR(ifla_linkinfo_nla_decoders),
		      &ctx);

	return true;
}

static bool
decode_rtnl_link_stats64(struct tcb *const tcp,
		         const kernel_ulong_t addr,
			 const unsigned int len,
			 const void *const opaque_data)
{
#ifdef HAVE_STRUCT_RTNL_LINK_STATS64
	struct rtnl_link_stats64 st;
	const unsigned int min_size =
		offsetofend(struct rtnl_link_stats64, tx_compressed);
	const unsigned int def_size = sizeof(st);
	const unsigned int size =
		(len >= def_size) ? def_size :
				    ((len == min_size) ? min_size : 0);

	if (!size)
		return false;

	if (!umoven_or_printaddr(tcp, addr, size, &st)) {
		PRINT_FIELD_U("{", st, rx_packets);
		PRINT_FIELD_U(", ", st, tx_packets);
		PRINT_FIELD_U(", ", st, rx_bytes);
		PRINT_FIELD_U(", ", st, tx_bytes);
		PRINT_FIELD_U(", ", st, rx_errors);
		PRINT_FIELD_U(", ", st, tx_errors);
		PRINT_FIELD_U(", ", st, rx_dropped);
		PRINT_FIELD_U(", ", st, tx_dropped);
		PRINT_FIELD_U(", ", st, multicast);
		PRINT_FIELD_U(", ", st, collisions);

		PRINT_FIELD_U(", ", st, rx_length_errors);
		PRINT_FIELD_U(", ", st, rx_over_errors);
		PRINT_FIELD_U(", ", st, rx_crc_errors);
		PRINT_FIELD_U(", ", st, rx_frame_errors);
		PRINT_FIELD_U(", ", st, rx_fifo_errors);
		PRINT_FIELD_U(", ", st, rx_missed_errors);

		PRINT_FIELD_U(", ", st, tx_aborted_errors);
		PRINT_FIELD_U(", ", st, tx_carrier_errors);
		PRINT_FIELD_U(", ", st, tx_fifo_errors);
		PRINT_FIELD_U(", ", st, tx_heartbeat_errors);
		PRINT_FIELD_U(", ", st, tx_window_errors);

		PRINT_FIELD_U(", ", st, rx_compressed);
		PRINT_FIELD_U(", ", st, tx_compressed);
#ifdef HAVE_STRUCT_RTNL_LINK_STATS64_RX_NOHANDLER
		if (len >= def_size)
			PRINT_FIELD_U(", ", st, rx_nohandler);
#endif
		tprints("}");
	}

	return true;
#else
	return false;
#endif
}

static bool
decode_ifla_port_vsi(struct tcb *const tcp,
		     const kernel_ulong_t addr,
		     const unsigned int len,
		     const void *const opaque_data)
{
#ifdef HAVE_STRUCT_IFLA_PORT_VSI
	struct ifla_port_vsi vsi;

	if (len < sizeof(vsi))
		return false;
	else if (!umove_or_printaddr(tcp, addr, &vsi)) {
		PRINT_FIELD_U("{", vsi, vsi_mgr_id);
		PRINT_FIELD_STRING(", ", vsi, vsi_type_id,
				   sizeof(vsi.vsi_type_id), QUOTE_FORCE_HEX);
		PRINT_FIELD_U(", ", vsi, vsi_type_version);
		tprints("}");
	}

	return true;
#else
	return false;
#endif
}

static const nla_decoder_t ifla_port_nla_decoders[] = {
	[IFLA_PORT_VF]			= decode_nla_u32,
	[IFLA_PORT_PROFILE]		= decode_nla_str,
	[IFLA_PORT_VSI_TYPE]		= decode_ifla_port_vsi,
	[IFLA_PORT_INSTANCE_UUID]	= NULL, /* default parser */
	[IFLA_PORT_HOST_UUID]		= NULL, /* default parser */
	[IFLA_PORT_REQUEST]		= decode_nla_u8,
	[IFLA_PORT_RESPONSE]		= decode_nla_u16
};
Beispiel #20
0
void
printsock(struct tcb *tcp, long addr, int addrlen)
{
	union {
		char pad[128];
		struct sockaddr sa;
		struct sockaddr_in sin;
		struct sockaddr_un sau;
#ifdef HAVE_INET_NTOP
		struct sockaddr_in6 sa6;
#endif
#if defined(AF_IPX)
		struct sockaddr_ipx sipx;
#endif
#ifdef AF_PACKET
		struct sockaddr_ll ll;
#endif
#ifdef AF_NETLINK
		struct sockaddr_nl nl;
#endif
#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
		struct sockaddr_hci hci;
		struct sockaddr_l2 l2;
		struct sockaddr_rc rc;
		struct sockaddr_sco sco;
#endif
	} addrbuf;
	char string_addr[100];

	if (addrlen < 2 || addrlen > (int) sizeof(addrbuf))
		addrlen = sizeof(addrbuf);

	memset(&addrbuf, 0, sizeof(addrbuf));
	if (umoven_or_printaddr(tcp, addr, addrlen, addrbuf.pad))
		return;
	addrbuf.pad[sizeof(addrbuf.pad) - 1] = '\0';

	tprints("{sa_family=");
	printxval(addrfams, addrbuf.sa.sa_family, "AF_???");
	tprints(", ");

	switch (addrbuf.sa.sa_family) {
	case AF_UNIX:
		if (addrlen == 2) {
			tprints("NULL");
		} else if (addrbuf.sau.sun_path[0]) {
			tprints("sun_path=");
			print_quoted_string(addrbuf.sau.sun_path,
					    sizeof(addrbuf.sau.sun_path) + 1,
					    QUOTE_0_TERMINATED);
		} else {
			tprints("sun_path=@");
			print_quoted_string(addrbuf.sau.sun_path + 1,
					    sizeof(addrbuf.sau.sun_path),
					    QUOTE_0_TERMINATED);
		}
		break;
	case AF_INET:
		tprintf("sin_port=htons(%u), sin_addr=inet_addr(\"%s\")",
			ntohs(addrbuf.sin.sin_port), inet_ntoa(addrbuf.sin.sin_addr));
		break;
#ifdef HAVE_INET_NTOP
	case AF_INET6:
		inet_ntop(AF_INET6, &addrbuf.sa6.sin6_addr, string_addr, sizeof(string_addr));
		tprintf("sin6_port=htons(%u), inet_pton(AF_INET6, \"%s\", &sin6_addr), sin6_flowinfo=%u",
				ntohs(addrbuf.sa6.sin6_port), string_addr,
				addrbuf.sa6.sin6_flowinfo);
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
		tprints(", sin6_scope_id=");
#if defined IN6_IS_ADDR_LINKLOCAL && defined IN6_IS_ADDR_MC_LINKLOCAL
		if (IN6_IS_ADDR_LINKLOCAL(&addrbuf.sa6.sin6_addr)
		    || IN6_IS_ADDR_MC_LINKLOCAL(&addrbuf.sa6.sin6_addr))
			print_ifindex(addrbuf.sa6.sin6_scope_id);
		else
#endif
			tprintf("%u", addrbuf.sa6.sin6_scope_id);
#endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */
		break;
#endif
#if defined(AF_IPX)
	case AF_IPX:
		{
			int i;
			tprintf("sipx_port=htons(%u), ",
					ntohs(addrbuf.sipx.sipx_port));
			/* Yes, I know, this does not look too
			 * strace-ish, but otherwise the IPX
			 * addresses just look monstrous...
			 * Anyways, feel free if you don't like
			 * this way.. :)
			 */
			tprintf("%08lx:", (unsigned long)ntohl(addrbuf.sipx.sipx_network));
			for (i = 0; i < IPX_NODE_LEN; i++)
				tprintf("%02x", addrbuf.sipx.sipx_node[i]);
			tprintf("/[%02x]", addrbuf.sipx.sipx_type);
		}
		break;
#endif /* AF_IPX */
#ifdef AF_PACKET
	case AF_PACKET:
		{
			int i;
			tprintf("proto=%#04x, if%d, pkttype=",
					ntohs(addrbuf.ll.sll_protocol),
					addrbuf.ll.sll_ifindex);
			printxval(af_packet_types, addrbuf.ll.sll_pkttype, "PACKET_???");
			tprintf(", addr(%d)={%d, ",
					addrbuf.ll.sll_halen,
					addrbuf.ll.sll_hatype);
			for (i = 0; i < addrbuf.ll.sll_halen; i++)
				tprintf("%02x", addrbuf.ll.sll_addr[i]);
		}
		break;

#endif /* AF_PACKET */
#ifdef AF_NETLINK
	case AF_NETLINK:
		tprintf("pid=%d, groups=%08x", addrbuf.nl.nl_pid, addrbuf.nl.nl_groups);
		break;
#endif /* AF_NETLINK */
#if defined(AF_BLUETOOTH) && defined(HAVE_BLUETOOTH_BLUETOOTH_H)
	case AF_BLUETOOTH:
		tprintf("{sco_bdaddr=%02X:%02X:%02X:%02X:%02X:%02X} or "
			"{rc_bdaddr=%02X:%02X:%02X:%02X:%02X:%02X, rc_channel=%d} or "
			"{l2_psm=htobs(%d), l2_bdaddr=%02X:%02X:%02X:%02X:%02X:%02X, l2_cid=htobs(%d)} or "
			"{hci_dev=htobs(%d)}",
			addrbuf.sco.sco_bdaddr.b[0], addrbuf.sco.sco_bdaddr.b[1],
			addrbuf.sco.sco_bdaddr.b[2], addrbuf.sco.sco_bdaddr.b[3],
			addrbuf.sco.sco_bdaddr.b[4], addrbuf.sco.sco_bdaddr.b[5],
			addrbuf.rc.rc_bdaddr.b[0], addrbuf.rc.rc_bdaddr.b[1],
			addrbuf.rc.rc_bdaddr.b[2], addrbuf.rc.rc_bdaddr.b[3],
			addrbuf.rc.rc_bdaddr.b[4], addrbuf.rc.rc_bdaddr.b[5],
			addrbuf.rc.rc_channel,
			btohs(addrbuf.l2.l2_psm), addrbuf.l2.l2_bdaddr.b[0],
			addrbuf.l2.l2_bdaddr.b[1], addrbuf.l2.l2_bdaddr.b[2],
			addrbuf.l2.l2_bdaddr.b[3], addrbuf.l2.l2_bdaddr.b[4],
			addrbuf.l2.l2_bdaddr.b[5], btohs(addrbuf.l2.l2_cid),
			btohs(addrbuf.hci.hci_dev));
		break;
#endif /* AF_BLUETOOTH && HAVE_BLUETOOTH_BLUETOOTH_H */
	/* AF_AX25 AF_APPLETALK AF_NETROM AF_BRIDGE AF_AAL5
	AF_X25 AF_ROSE etc. still need to be done */

	default:
		tprints("sa_data=");
		print_quoted_string(addrbuf.sa.sa_data,
				    sizeof(addrbuf.sa.sa_data), 0);
		break;
	}
	tprints("}");
}
static int
decode_select(struct tcb *tcp, long *args,
	      void (*print_tv_ts) (struct tcb *, const long),
	      const char * (*sprint_tv_ts) (struct tcb *, const long))
{
	int i, j;
	int nfds, fdsize;
	fd_set *fds = NULL;
	const char *sep;
	long arg;

	/* Kernel truncates arg[0] to int, we do the same. */
	nfds = (int) args[0];

	/* Kernel rejects negative nfds, so we don't parse it either. */
	if (nfds < 0)
		nfds = 0;

	/* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */
	if (nfds > 1024*1024)
		nfds = 1024*1024;

	/*
	 * We had bugs a-la "while (j < args[0])" and "umoven(args[0])" below.
	 * Instead of args[0], use nfds for fd count, fdsize for array lengths.
	 */
	fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize;

	if (entering(tcp)) {
		tprintf("%d", (int) args[0]);

		if (verbose(tcp) && fdsize > 0)
			fds = malloc(fdsize);
		for (i = 0; i < 3; i++) {
			arg = args[i+1];
			tprints(", ");
			if (!fds) {
				printaddr(arg);
				continue;
			}
			if (umoven_or_printaddr(tcp, arg, fdsize, fds))
				continue;
			tprints("[");
			for (j = 0, sep = "";; j++) {
				j = next_set_bit(fds, j, nfds);
				if (j < 0)
					break;
				tprints(sep);
				printfd(tcp, j);
				sep = " ";
			}
			tprints("]");
		}
		free(fds);
		tprints(", ");
		print_tv_ts(tcp, args[4]);
	} else {
		static char outstr[1024];
		char *outptr;
#define end_outstr (outstr + sizeof(outstr))
		int ready_fds;

		if (syserror(tcp))
			return 0;

		ready_fds = tcp->u_rval;
		if (ready_fds == 0) {
			tcp->auxstr = "Timeout";
			return RVAL_STR;
		}

		fds = malloc(fdsize);

		outptr = outstr;
		sep = "";
		for (i = 0; i < 3 && ready_fds > 0; i++) {
			int first = 1;

			arg = args[i+1];
			if (!arg || !fds || umoven(tcp, arg, fdsize, fds) < 0)
				continue;
			for (j = 0;; j++) {
				j = next_set_bit(fds, j, nfds);
				if (j < 0)
					break;
				/* +2 chars needed at the end: ']',NUL */
				if (outptr < end_outstr - (sizeof(", except [") + sizeof(int)*3 + 2)) {
					if (first) {
						outptr += sprintf(outptr, "%s%s [%u",
							sep,
							i == 0 ? "in" : i == 1 ? "out" : "except",
							j
						);
						first = 0;
						sep = ", ";
					}
					else {
						outptr += sprintf(outptr, " %u", j);
					}
				}
				if (--ready_fds == 0)
					break;
			}
			if (outptr != outstr)
				*outptr++ = ']';
		}
		free(fds);
		/* This contains no useful information on SunOS.  */
		if (args[4]) {
			const char *str = sprint_tv_ts(tcp, args[4]);
			if (outptr + sizeof("left ") + strlen(sep) + strlen(str) < end_outstr) {
				outptr += sprintf(outptr, "%sleft %s", sep, str);
			}
		}
		*outptr = '\0';
		tcp->auxstr = outstr;
		return RVAL_STR;
#undef end_outstr
	}
	return 0;
}