]> granicus.if.org Git - strace/blob - sockaddr.c
xlat: add BPF_F_TEST_STATE_FREQ to bpf_prog_flags
[strace] / sockaddr.c
1 /*
2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3  * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5  * Copyright (c) 1996-2000 Wichert Akkerman <wichert@cistron.nl>
6  * Copyright (c) 2005-2016 Dmitry V. Levin <ldv@altlinux.org>
7  * Copyright (c) 2016-2019 The strace developers.
8  * All rights reserved.
9  *
10  * SPDX-License-Identifier: LGPL-2.1-or-later
11  */
12
13 #include "defs.h"
14 #include "print_fields.h"
15
16 #include <sys/socket.h>
17 #include <sys/un.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20
21 #include "netlink.h"
22 #include <linux/ax25.h>
23 #include <linux/if_packet.h>
24 #include <linux/if_arp.h>
25 #include <linux/if_ether.h>
26 #include <linux/x25.h>
27
28 #ifdef HAVE_NETIPX_IPX_H
29 # include <netipx/ipx.h>
30 #else
31 # include <linux/ipx.h>
32 #endif
33
34 #include "xlat/addrfams.h"
35 #include "xlat/arp_hardware_types.h"
36 #include "xlat/ethernet_protocols.h"
37 #include "xlat/af_packet_types.h"
38
39 #include "xlat/bdaddr_types.h"
40 #include "xlat/bluetooth_l2_cid.h"
41 #include "xlat/bluetooth_l2_psm.h"
42 #include "xlat/hci_channels.h"
43
44 #define SIZEOF_SA_FAMILY sizeof(((struct sockaddr *) 0)->sa_family)
45
46 const size_t arp_hardware_types_size = ARRAY_SIZE(arp_hardware_types) - 1;
47 const size_t ethernet_protocols_size = ARRAY_SIZE(ethernet_protocols) - 1;
48
49 static void
50 print_sockaddr_data_un(const void *const buf, const int addrlen)
51 {
52         const struct sockaddr_un *const sa_un = buf;
53         const int un_len = addrlen > (int) sizeof(*sa_un)
54                            ? (int) sizeof(*sa_un) : addrlen;
55         const int path_len = un_len - SIZEOF_SA_FAMILY;
56
57         tprints("sun_path=");
58         if (sa_un->sun_path[0]) {
59                 print_quoted_string(sa_un->sun_path, path_len + 1,
60                                     QUOTE_0_TERMINATED);
61         } else {
62                 tprints("@");
63                 print_quoted_string(sa_un->sun_path + 1, path_len - 1, 0);
64         }
65 }
66
67 bool
68 print_inet_addr(const int af,
69                 const void *const addr,
70                 const unsigned int len,
71                 const char *const var_name)
72 {
73         char buf[INET6_ADDRSTRLEN];
74
75         switch (af) {
76         case AF_INET:
77                 if (inet_ntop(af, addr, buf, sizeof(buf))) {
78                         if (var_name)
79                                 tprintf("%s=", var_name);
80
81                         if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_ABBREV)
82                                 print_quoted_string((const char*) addr,
83                                                     len, QUOTE_FORCE_HEX);
84
85                         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW)
86                                 return true;
87
88                         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE)
89                                 tprints(" /* ");
90
91                         tprintf("inet_addr(\"%s\")", buf);
92
93                         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE)
94                                 tprints(" */");
95
96                         return true;
97                 }
98                 break;
99         case AF_INET6:
100                 if (inet_ntop(af, addr, buf, sizeof(buf))) {
101                         if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_ABBREV) {
102                                 if (var_name)
103                                         tprintf("%s=", var_name);
104                                 print_quoted_string(addr, len, QUOTE_FORCE_HEX);
105                         }
106
107                         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW)
108                                 return true;
109
110                         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE)
111                                 tprints(" /* ");
112
113                         if (var_name &&
114                             (xlat_verbose(xlat_verbosity) == XLAT_STYLE_ABBREV))
115                                 tprintf("inet_pton(%s, \"%s\", &%s)",
116                                         "AF_INET6", buf, var_name);
117                         else
118                                 tprintf("inet_pton(%s, \"%s\")",
119                                         "AF_INET6", buf);
120
121                         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE)
122                                 tprints(" */");
123
124                         return true;
125                 }
126                 break;
127         }
128
129         if (var_name)
130                 tprintf("%s=", var_name);
131         print_quoted_string(addr, len, QUOTE_FORCE_HEX);
132         return false;
133 }
134
135 bool
136 decode_inet_addr(struct tcb *const tcp,
137                  const kernel_ulong_t addr,
138                  const unsigned int len,
139                  const int family,
140                  const char *const var_name)
141 {
142         union {
143                 struct in_addr  a4;
144                 struct in6_addr a6;
145         } addrbuf;
146         size_t size = 0;
147
148         switch (family) {
149         case AF_INET:
150                 size = sizeof(addrbuf.a4);
151                 break;
152         case AF_INET6:
153                 size = sizeof(addrbuf.a6);
154                 break;
155         }
156
157         if (!size || len < size) {
158                 if (var_name)
159                         tprintf("%s=", var_name);
160                 printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
161                 return false;
162         }
163
164         if (umoven(tcp, addr, size, &addrbuf) < 0) {
165                 if (var_name)
166                         tprintf("%s=", var_name);
167                 printaddr(addr);
168                 return false;
169         }
170
171         return print_inet_addr(family, &addrbuf, size, var_name);
172 }
173
174 static void
175 print_sockaddr_data_in(const void *const buf, const int addrlen)
176 {
177         const struct sockaddr_in *const sa_in = buf;
178
179         PRINT_FIELD_NET_PORT("", *sa_in, sin_port);
180         PRINT_FIELD_INET_ADDR(", ", *sa_in, sin_addr, AF_INET);
181 }
182
183 #define SIN6_MIN_LEN offsetof(struct sockaddr_in6, sin6_scope_id)
184
185 static void
186 print_sockaddr_data_in6(const void *const buf, const int addrlen)
187 {
188         const struct sockaddr_in6 *const sa_in6 = buf;
189
190         PRINT_FIELD_NET_PORT("", *sa_in6, sin6_port);
191         tprints(", sin6_flowinfo=");
192         if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_ABBREV)
193                 print_quoted_string((const char*) &sa_in6->sin6_flowinfo,
194                                     sizeof(sa_in6->sin6_flowinfo),
195                                     QUOTE_FORCE_HEX);
196
197         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE)
198                 tprintf(" /* htonl(%u) */", ntohl(sa_in6->sin6_flowinfo));
199
200         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_ABBREV)
201                 tprintf("htonl(%u)", ntohl(sa_in6->sin6_flowinfo));
202
203         PRINT_FIELD_INET_ADDR(", ", *sa_in6, sin6_addr, AF_INET6);
204         if (addrlen <= (int) SIN6_MIN_LEN)
205                 return;
206
207 #if defined IN6_IS_ADDR_LINKLOCAL && defined IN6_IS_ADDR_MC_LINKLOCAL
208         if (IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr)
209             || IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr))
210                 PRINT_FIELD_IFINDEX(", ", *sa_in6, sin6_scope_id);
211         else
212 #endif
213                 PRINT_FIELD_U(", ", *sa_in6, sin6_scope_id);
214 }
215
216 /**
217  * Check that we can print an AX.25 address in its native form, otherwise it
218  * makes sense to print it in raw also (or in raw only).
219  */
220 enum xlat_style
221 check_ax25_address(const ax25_address *addr)
222 {
223         enum xlat_style ret = XLAT_STYLE_DEFAULT;
224         bool space_seen = false;
225         bool char_seen = false;
226
227         for (size_t i = 0; i < ARRAY_SIZE(addr->ax25_call) - 1; i++) {
228                 unsigned char c = addr->ax25_call[i];
229
230                 /* The lowest bit should be zero */
231                 if (c & 1)
232                         ret = XLAT_STYLE_VERBOSE;
233
234                 c >>= 1;
235
236                 if (c == ' ')
237                         space_seen = true;
238                 else
239                         char_seen = true;
240
241                 /* Sane address contains only numbers and uppercase letters */
242                 if ((c < '0' || c > '9') && (c < 'A' || c > 'Z') && c != ' ')
243                         ret = XLAT_STYLE_VERBOSE;
244                 if (c != ' ' && space_seen)
245                         ret = XLAT_STYLE_VERBOSE;
246
247                 /* non-printable chars */
248                 if (c < ' ' || c > 0x7e
249                     /* characters used for printing comments */
250                     || c == '*' || c == '/')
251                         return XLAT_STYLE_RAW;
252         }
253
254         if (addr->ax25_call[ARRAY_SIZE(addr->ax25_call) - 1] & ~0x1e)
255                 ret = XLAT_STYLE_VERBOSE;
256
257         if (!char_seen && addr->ax25_call[ARRAY_SIZE(addr->ax25_call) - 1])
258                 ret = XLAT_STYLE_VERBOSE;
259
260         return ret;
261 }
262
263 /** Convert a (presumably) valid AX.25 to a string */
264 static const char *
265 ax25_addr2str(const ax25_address *addr)
266 {
267         static char buf[ARRAY_SIZE(addr->ax25_call) + sizeof("-15")];
268         char *p = buf;
269         size_t end;
270
271         for (end = ARRAY_SIZE(addr->ax25_call) - 1; end; end--)
272                 if ((addr->ax25_call[end - 1] >> 1) != ' ')
273                         break;
274
275         for (size_t i = 0; i < end; i++)
276                 *p++ = ((unsigned char) addr->ax25_call[i]) >> 1;
277
278         *p++ = '-';
279
280         unsigned char ssid = (addr->ax25_call[ARRAY_SIZE(addr->ax25_call) - 1]
281                               >> 1) & 0xf;
282
283         if (ssid > 9) {
284                 *p++ = '1';
285                 ssid -= 10;
286         }
287
288         *p++ = ssid + '0';
289         *p = '\0';
290
291         if (buf[0] == '-' && buf[1] == '0')
292                 return "*";
293
294         return buf;
295 }
296
297 static void
298 print_ax25_addr_raw(const ax25_address *addr)
299 {
300         PRINT_FIELD_HEX_ARRAY("{", *addr, ax25_call);
301         tprints("}");
302 }
303
304 void
305 print_ax25_addr(const void /* ax25_address */ *addr_void)
306 {
307         const ax25_address *addr = addr_void;
308         enum xlat_style xs = check_ax25_address(addr);
309
310         if (xs == XLAT_STYLE_DEFAULT)
311                 xs = xlat_verbose(xlat_verbosity);
312
313         if (xs != XLAT_STYLE_ABBREV)
314                 print_ax25_addr_raw(addr);
315
316         if (xs == XLAT_STYLE_RAW)
317                 return;
318
319         const char *addr_str = ax25_addr2str(addr);
320
321         (xs == XLAT_STYLE_VERBOSE ? tprints_comment : tprints)(addr_str);
322 }
323
324 static void
325 print_sockaddr_data_ax25(const void *const buf, const int addrlen)
326 {
327         const struct full_sockaddr_ax25 *const sax25 = buf;
328         size_t addrlen_us = MAX(addrlen, 0);
329         bool full = sax25->fsa_ax25.sax25_ndigis ||
330         (addrlen_us > sizeof(struct sockaddr_ax25));
331
332         if (full)
333                 tprints("fsa_ax25={");
334
335         tprints("sax25_call=");
336         print_ax25_addr(&sax25->fsa_ax25.sax25_call);
337         PRINT_FIELD_D(", ", sax25->fsa_ax25, sax25_ndigis);
338
339         if (!full)
340                 return;
341
342         tprints("}");
343
344         size_t has_digis = MIN((addrlen_us - sizeof(sax25->fsa_ax25))
345                                / sizeof(sax25->fsa_digipeater[0]),
346                                ARRAY_SIZE(sax25->fsa_digipeater));
347         size_t want_digis = MIN(
348                 (unsigned int) MAX(sax25->fsa_ax25.sax25_ndigis, 0),
349                 ARRAY_SIZE(sax25->fsa_digipeater));
350         size_t digis = MIN(has_digis, want_digis);
351
352         if (want_digis == 0)
353                 goto digis_end;
354
355         tprints(", fsa_digipeater=[");
356         for (size_t i = 0; i < digis; i++) {
357                 if (i)
358                         tprints(", ");
359
360                 print_ax25_addr(sax25->fsa_digipeater + i);
361         }
362
363         if (want_digis > has_digis)
364                 tprintf("%s/* ??? */", digis ? ", " : "");
365
366         tprints("]");
367
368 digis_end:
369         if (addrlen_us > (has_digis * sizeof(sax25->fsa_digipeater[0])
370                        + sizeof(sax25->fsa_ax25)))
371                 tprints(", ...");
372 }
373
374 static void
375 print_sockaddr_data_ipx(const void *const buf, const int addrlen)
376 {
377         const struct sockaddr_ipx *const sa_ipx = buf;
378         unsigned int i;
379
380         PRINT_FIELD_NET_PORT("", *sa_ipx, sipx_port);
381         tprintf(", sipx_network=htonl(%#08x)"
382                 ", sipx_node=[",
383                 ntohl(sa_ipx->sipx_network));
384         for (i = 0; i < IPX_NODE_LEN; ++i) {
385                 tprintf("%s%#02x", i ? ", " : "",
386                         sa_ipx->sipx_node[i]);
387         }
388         PRINT_FIELD_0X("], ", *sa_ipx, sipx_type);
389 }
390
391 void
392 print_x25_addr(const void /* struct x25_address */ *addr_void)
393 {
394         const struct x25_address *addr = addr_void;
395
396         tprints("{x25_addr=");
397         print_quoted_cstring(addr->x25_addr, sizeof(addr->x25_addr));
398         tprints("}");
399 }
400
401 static void
402 print_sockaddr_data_x25(const void *const buf, const int addrlen)
403 {
404         const struct sockaddr_x25 *const sa_x25 = buf;
405
406         PRINT_FIELD_X25_ADDR("", *sa_x25, sx25_addr);
407 }
408
409 static void
410 print_sockaddr_data_nl(const void *const buf, const int addrlen)
411 {
412         const struct sockaddr_nl *const sa_nl = buf;
413
414         PRINT_FIELD_D("", *sa_nl, nl_pid);
415         PRINT_FIELD_0X(", ", *sa_nl, nl_groups);
416 }
417
418 static void
419 print_sll_protocol(const struct sockaddr_ll *const sa_ll)
420 {
421         int x_style = xlat_verbose(xlat_verbosity);
422
423         tprints("sll_protocol=");
424         if (x_style != XLAT_STYLE_ABBREV)
425                 print_quoted_string((const char *) &sa_ll->sll_protocol,
426                                     sizeof(sa_ll->sll_protocol),
427                                     QUOTE_FORCE_HEX);
428
429         if (x_style == XLAT_STYLE_RAW)
430                 return;
431
432         if (x_style == XLAT_STYLE_VERBOSE)
433                 tprints(" /* ");
434
435         tprints("htons(");
436         printxval_ex(ethernet_protocols, ntohs(sa_ll->sll_protocol),
437                      "ETH_P_???", XLAT_STYLE_ABBREV);
438         tprints(")");
439
440         if (x_style == XLAT_STYLE_VERBOSE)
441                 tprints(" */");
442 }
443
444 static void
445 print_sockaddr_data_ll(const void *const buf, const int addrlen)
446 {
447         const struct sockaddr_ll *const sa_ll = buf;
448
449         print_sll_protocol(sa_ll);
450         PRINT_FIELD_IFINDEX(", ", *sa_ll, sll_ifindex);
451         tprints(", sll_hatype=");
452         printxval(arp_hardware_types, sa_ll->sll_hatype, "ARPHRD_???");
453         tprints(", sll_pkttype=");
454         printxval(af_packet_types, sa_ll->sll_pkttype, "PACKET_???");
455         tprintf(", sll_halen=%u", sa_ll->sll_halen);
456         if (sa_ll->sll_halen) {
457                 const unsigned int oob_halen =
458                         addrlen - offsetof(struct sockaddr_ll, sll_addr);
459                 unsigned int i;
460
461                 tprints(", sll_addr=[");
462                 for (i = 0; i < sa_ll->sll_halen; ++i) {
463                         if (i)
464                                 tprints(", ");
465                         if (i >= oob_halen) {
466                                 tprints("...");
467                                 break;
468                         }
469                         tprintf("%#02x", sa_ll->sll_addr[i]);
470                 }
471                 tprints("]");
472         }
473 }
474
475 static void
476 print_sockaddr_data_raw(const void *const buf, const int addrlen)
477 {
478         const char *const data = buf + SIZEOF_SA_FAMILY;
479         const int datalen = addrlen - SIZEOF_SA_FAMILY;
480
481         tprints("sa_data=");
482         print_quoted_string(data, datalen, 0);
483 }
484
485 static uint16_t
486 btohs(uint16_t val)
487 {
488 #ifdef WORDS_BIGENDIAN
489         return (val << 8) | (val >> 8);
490 #else
491         return val;
492 #endif
493 }
494
495 static void
496 print_bluetooth_l2_psm(const char *prefix, uint16_t psm)
497 {
498         const uint16_t psm_he = btohs(psm);
499         const char *psm_name = xlookup(bluetooth_l2_psm, psm_he);
500         const bool psm_str = psm_name || (psm_he >= L2CAP_PSM_LE_DYN_START
501                                           && psm_he <= L2CAP_PSM_LE_DYN_END)
502                                       || (psm_he >= L2CAP_PSM_DYN_START);
503
504         tprintf("%shtobs(", prefix);
505
506         if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_ABBREV || !psm_str)
507                 tprintf("%#x", psm_he);
508
509         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW)
510                 goto print_bluetooth_l2_psm_end;
511
512         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE || !psm_str)
513                 tprints(" /* ");
514
515         if (psm_name) {
516                 tprints(psm_name);
517         } else if (psm_he >= L2CAP_PSM_LE_DYN_START
518             && psm_he <= L2CAP_PSM_LE_DYN_END) {
519                 print_xlat(L2CAP_PSM_LE_DYN_START);
520                 tprintf(" + %u", psm_he - L2CAP_PSM_LE_DYN_START);
521         } else if (psm_he >= L2CAP_PSM_DYN_START) {
522                 print_xlat(L2CAP_PSM_DYN_START);
523                 tprintf(" + %u", psm_he - L2CAP_PSM_DYN_START);
524         } else {
525                 tprints("L2CAP_PSM_???");
526         }
527
528         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE || !psm_str)
529                 tprints(" */");
530
531 print_bluetooth_l2_psm_end:
532         tprints(")");
533 }
534
535 static void
536 print_bluetooth_l2_cid(const char *prefix, uint16_t cid)
537 {
538         const uint16_t cid_he = btohs(cid);
539         const char *cid_name = xlookup(bluetooth_l2_cid, cid_he);
540         const bool cid_str = cid_name || (cid_he >= L2CAP_CID_DYN_START);
541
542         tprintf("%shtobs(", prefix);
543
544         if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_ABBREV || !cid_str)
545                 tprintf("%#x", cid_he);
546
547         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW)
548                 goto print_bluetooth_l2_cid_end;
549
550         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE || !cid_str)
551                 tprints(" /* ");
552
553         if (cid_name) {
554                 tprints(cid_name);
555         } else if (cid_he >= L2CAP_CID_DYN_START) {
556                 print_xlat(L2CAP_CID_DYN_START);
557                 tprintf(" + %u", cid_he - L2CAP_CID_DYN_START);
558         } else {
559                 tprints("L2CAP_CID_???");
560         }
561
562         if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE || !cid_str)
563                 tprints(" */");
564
565 print_bluetooth_l2_cid_end:
566         tprints(")");
567 }
568
569 static void
570 print_sockaddr_data_bt(const void *const buf, const int addrlen)
571 {
572         struct sockaddr_hci {
573                 /* sa_family_t */ uint16_t      hci_family;
574                 uint16_t                        hci_dev;
575                 uint16_t                        hci_channel;
576         };
577
578         struct bdaddr {
579                 uint8_t                         b[6];
580         } ATTRIBUTE_PACKED;
581
582         struct sockaddr_sco {
583                 /* sa_family_t */ uint16_t      sco_family;
584                 struct bdaddr                   sco_bdaddr;
585         };
586
587         struct sockaddr_rc {
588                 /* sa_family_t */ uint16_t      rc_family;
589                 struct bdaddr                   rc_bdaddr;
590                 uint8_t                         rc_channel;
591         };
592
593         struct sockaddr_l2 {
594                 /* sa_family_t */ uint16_t      l2_family;
595                 /* little endian */ uint16_t    l2_psm;
596                 struct bdaddr                   l2_bdaddr;
597                 /* little endian */ uint16_t    l2_cid;
598                 uint8_t                         l2_bdaddr_type;
599         };
600
601         switch (addrlen) {
602         case offsetofend(struct sockaddr_hci, hci_dev):
603         case sizeof(struct sockaddr_hci): {
604                 const struct sockaddr_hci *const hci = buf;
605                 tprintf("hci_dev=htobs(%hu)", btohs(hci->hci_dev));
606
607                 /*
608                  * hci_channel field has been introduced
609                  * Linux commit in v2.6.38-rc1~476^2~14^2~3^2~43^2~9.
610                  */
611                 if (addrlen == sizeof(struct sockaddr_hci)) {
612                         tprints(", hci_channel=");
613                         printxval(hci_channels, hci->hci_channel,
614                                   "HCI_CHANNEL_???");
615                 }
616
617                 break;
618         }
619         case sizeof(struct sockaddr_sco): {
620                 const struct sockaddr_sco *const sco = buf;
621                 print_mac_addr("sco_bdaddr=", sco->sco_bdaddr.b,
622                                sizeof(sco->sco_bdaddr.b));
623                 break;
624         }
625         case sizeof(struct sockaddr_rc): {
626                 const struct sockaddr_rc *const rc = buf;
627                 print_mac_addr("rc_bdaddr=", rc->rc_bdaddr.b,
628                                sizeof(rc->rc_bdaddr.b));
629                 tprintf(", rc_channel=%u", rc->rc_channel);
630                 break;
631         }
632         case offsetof(struct sockaddr_l2, l2_bdaddr_type):
633         case sizeof(struct sockaddr_l2): {
634                 const struct sockaddr_l2 *const l2 = buf;
635                 print_bluetooth_l2_psm("l2_psm=", l2->l2_psm);
636                 print_mac_addr(", l2_bdaddr=", l2->l2_bdaddr.b,
637                                sizeof(l2->l2_bdaddr.b));
638                 print_bluetooth_l2_cid(", l2_cid=", l2->l2_cid);
639
640                 if (addrlen == sizeof(struct sockaddr_l2)) {
641                         tprints(", l2_bdaddr_type=");
642                         printxval(bdaddr_types, l2->l2_bdaddr_type,
643                                   "BDADDR_???");
644                 }
645
646                 break;
647         }
648         default:
649                 print_sockaddr_data_raw(buf, addrlen);
650                 break;
651         }
652 }
653
654 typedef void (* const sockaddr_printer)(const void *const, const int);
655
656 static const struct {
657         const sockaddr_printer printer;
658         const int min_len;
659 } sa_printers[] = {
660         [AF_UNIX] = { print_sockaddr_data_un, SIZEOF_SA_FAMILY + 1 },
661         [AF_INET] = { print_sockaddr_data_in, sizeof(struct sockaddr_in) },
662         [AF_AX25] = { print_sockaddr_data_ax25, sizeof(struct sockaddr_ax25) },
663         [AF_IPX] = { print_sockaddr_data_ipx, sizeof(struct sockaddr_ipx) },
664         [AF_X25] = { print_sockaddr_data_x25, sizeof(struct sockaddr_x25) },
665         [AF_INET6] = { print_sockaddr_data_in6, SIN6_MIN_LEN },
666         [AF_NETLINK] = { print_sockaddr_data_nl, SIZEOF_SA_FAMILY + 1 },
667         [AF_PACKET] = { print_sockaddr_data_ll, sizeof(struct sockaddr_ll) },
668         [AF_BLUETOOTH] = { print_sockaddr_data_bt, SIZEOF_SA_FAMILY + 1 },
669 };
670
671 void
672 print_sockaddr(const void *const buf, const int addrlen)
673 {
674         const struct sockaddr *const sa = buf;
675
676         tprints("{sa_family=");
677         printxval(addrfams, sa->sa_family, "AF_???");
678
679         if (addrlen > (int) SIZEOF_SA_FAMILY) {
680                 tprints(", ");
681
682                 if (sa->sa_family < ARRAY_SIZE(sa_printers)
683                     && sa_printers[sa->sa_family].printer
684                     && addrlen >= sa_printers[sa->sa_family].min_len) {
685                         sa_printers[sa->sa_family].printer(buf, addrlen);
686                 } else {
687                         print_sockaddr_data_raw(buf, addrlen);
688                 }
689         }
690
691         tprints("}");
692 }
693
694 int
695 decode_sockaddr(struct tcb *const tcp, const kernel_ulong_t addr, int addrlen)
696 {
697         if (addrlen < 2) {
698                 printaddr(addr);
699                 return -1;
700         }
701
702         union {
703                 struct sockaddr sa;
704                 struct sockaddr_storage storage;
705                 char pad[sizeof(struct sockaddr_storage) + 1];
706         } addrbuf;
707
708         if ((unsigned) addrlen > sizeof(addrbuf.storage))
709                 addrlen = sizeof(addrbuf.storage);
710
711         if (umoven_or_printaddr(tcp, addr, addrlen, addrbuf.pad))
712                 return -1;
713
714         memset(&addrbuf.pad[addrlen], 0, sizeof(addrbuf.pad) - addrlen);
715
716         print_sockaddr(&addrbuf, addrlen);
717
718         return addrbuf.sa.sa_family;
719 }