(root)/
strace-6.5/
src/
xgetdents.c
       1  /*
       2   * Copyright (c) 2020-2021 Dmitry V. Levin <ldv@strace.io>
       3   * All rights reserved.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   */
       7  
       8  #include "xgetdents.h"
       9  #include "kernel_dirent.h"
      10  
      11  static void
      12  decode_dents(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
      13  	     const unsigned int header_size,
      14  	     const decode_dentry_head_fn decode_dentry_head,
      15  	     const decode_dentry_tail_fn decode_dentry_tail)
      16  {
      17  	union {
      18  		kernel_dirent_t ent;
      19  		kernel_dirent64_t ent64;
      20  	} dent;
      21  	unsigned int count = 0;
      22  
      23  	if (abbrev(tcp))
      24  		printaddr(addr);
      25  
      26  	for (;;) {
      27  		if (len < header_size) {
      28  			if (!abbrev(tcp)) {
      29  				if (!len) {
      30  					tprint_array_begin();
      31  					++count;
      32  				} else {
      33  					printstr_ex(tcp, addr, len,
      34  						    QUOTE_FORCE_HEX);
      35  				}
      36  			}
      37  			break;
      38  		}
      39  
      40  		/* len >= header_size after this point.  */
      41  		if (!tfetch_mem(tcp, addr, header_size, &dent)) {
      42  			if (!abbrev(tcp)) {
      43  				if (count) {
      44  					tprint_more_data_follows();
      45  					printaddr_comment(addr);
      46  				} else {
      47  					printaddr(addr);
      48  				}
      49  			}
      50  
      51  			break;
      52  		}
      53  
      54  		if (!abbrev(tcp)) {
      55  			if (!count)
      56  				tprint_array_begin();
      57  		}
      58  		++count;
      59  
      60  		kernel_ulong_t next_addr = 0;
      61  		unsigned int next_len = 0;
      62  		unsigned int d_reclen = decode_dentry_head(tcp, &dent);
      63  
      64  		if (d_reclen > len) {
      65  			/* cannot happen? */
      66  			tprintf_comment("%s%u bytes overflow",
      67  					(abbrev(tcp) ? "d_reclen " : ""),
      68  					d_reclen - len);
      69  			d_reclen = len;
      70  		} else if (d_reclen < header_size) {
      71  			/* cannot happen? */
      72  			tprintf_comment("%s%u bytes underflow",
      73  					(abbrev(tcp) ? "d_reclen " : ""),
      74  					header_size - d_reclen);
      75  			d_reclen = header_size;
      76  			next_len = len - header_size;
      77  		} else {
      78  			next_len = len - d_reclen;
      79  			if (next_len) {
      80  				if (addr + d_reclen > addr) {
      81  					next_addr = addr + d_reclen;
      82  				} else {
      83  					/* cannot happen? */
      84  					tprints_comment("address overflow");
      85  				}
      86  			}
      87  		}
      88  
      89  		len = next_len;
      90  		/* Do not use len inside the loop after this point.  */
      91  
      92  		if (!abbrev(tcp)) {
      93  			int rc = decode_dentry_tail(tcp, addr + header_size,
      94  						   &dent,
      95  						   d_reclen - header_size);
      96  			if (next_addr) {
      97  				tprint_array_next();
      98  				if (rc < 0) {
      99  					tprint_more_data_follows();
     100  					break;
     101  				}
     102  			}
     103  		}
     104  
     105  		if (!next_addr)
     106  			break;
     107  		addr = next_addr;
     108  	}
     109  
     110  	if (!abbrev(tcp)) {
     111  		if (count)
     112  			tprint_array_end();
     113  	} else {
     114  		tprintf_comment("%u%s entries", count, len ? "+" : "");
     115  	}
     116  }
     117  
     118  int
     119  xgetdents(struct tcb *const tcp, const unsigned int header_size,
     120  	  const decode_dentry_head_fn decode_dentry_head,
     121  	  const decode_dentry_tail_fn decode_dentry_tail)
     122  {
     123  	if (entering(tcp)) {
     124  		/* fd */
     125  		printfd(tcp, tcp->u_arg[0]);
     126  #ifdef ENABLE_SECONTEXT
     127  		tcp->last_dirfd = (int) tcp->u_arg[0];
     128  #endif
     129  		tprint_arg_next();
     130  		return 0;
     131  	}
     132  
     133  	const unsigned int count = tcp->u_arg[2];
     134  
     135  	if (syserror(tcp) || !verbose(tcp) ||
     136  	    (kernel_ulong_t) tcp->u_rval > count /* kernel gone bananas? */) {
     137  		printaddr(tcp->u_arg[1]);
     138  	} else {
     139  		decode_dents(tcp, tcp->u_arg[1], tcp->u_rval, header_size,
     140  			     decode_dentry_head, decode_dentry_tail);
     141  	}
     142  	tprint_arg_next();
     143  
     144  	PRINT_VAL_U(count);
     145  	return 0;
     146  }