From: Dmitry V. Levin Date: Fri, 29 Apr 2016 17:26:56 +0000 (+0000) Subject: Fix decoding of move_pages syscall X-Git-Tag: v4.12~235 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e212a15955824a384cf2a17c4d13a293e908cc6e;p=strace Fix decoding of move_pages syscall * numa.c (print_page_array, print_status, print_int, print_int_array): New functions. (SYS_FUNC(move_pages)): Rewrite using these functions. * tests/move_pages.c: New file. * tests/move_pages.test: New test. * tests/.gitignore: Add move_pages. * tests/Makefile.am (check_PROGRAMS): Likewise. (DECODER_TESTS): Add move_pages.test. --- diff --git a/numa.c b/numa.c index 0ee8b863..e57fe3f2 100644 --- a/numa.c +++ b/numa.c @@ -129,70 +129,108 @@ SYS_FUNC(get_mempolicy) #include "xlat/move_pages_flags.h" -SYS_FUNC(move_pages) +static void +print_page_array(struct tcb *tcp, const unsigned long addr, + const unsigned long count) { - if (entering(tcp)) { - unsigned long npages = tcp->u_arg[1]; - tprintf("%ld, %lu, ", tcp->u_arg[0], npages); - if (tcp->u_arg[2] == 0) - tprints("NULL, "); - else { - unsigned int i; - long puser = tcp->u_arg[2]; - tprints("{"); - for (i = 0; i < npages; ++i) { - void *p; - if (i > 0) - tprints(", "); - if (umove(tcp, puser, &p) < 0) { - tprints("???"); - break; - } - tprintf("%p", p); - puser += sizeof(void *); - } - tprints("}, "); + const unsigned long size = count * current_wordsize; + const unsigned long end = addr + size; + + if (end <= addr || size / current_wordsize != count) { + printaddr(addr); + return; + } + const unsigned long abbrev_end = + (abbrev(tcp) && max_strlen < count) ? + addr + max_strlen * current_wordsize : end; + unsigned long cur; + for (cur = addr; cur < end; cur += current_wordsize) { + if (cur != addr) + tprints(", "); + + unsigned long n; + if (umove_ulong_or_printaddr(tcp, cur, &n)) + break; + + if (cur == addr) + tprints("["); + + if (cur >= abbrev_end) { + tprints("..."); + cur = end; + break; } - if (tcp->u_arg[3] == 0) - tprints("NULL, "); - else { - unsigned int i; - long nodeuser = tcp->u_arg[3]; - tprints("{"); - for (i = 0; i < npages; ++i) { - int node; - if (i > 0) - tprints(", "); - if (umove(tcp, nodeuser, &node) < 0) { - tprints("???"); - break; - } - tprintf("%#x", node); - nodeuser += sizeof(int); - } - tprints("}, "); + printaddr(n); + } + if (cur != addr) + tprints("]"); +} + +static void +print_status(const int status) +{ + if (status < 0 && (unsigned) -status < nerrnos) + tprintf("%s", errnoent[-status]); + else + tprintf("%d", status); +} + +static void +print_int(const int i) +{ + tprintf("%d", i); +} + +static void +print_int_array(struct tcb *tcp, const unsigned long addr, + const unsigned long count, void (*func)(int)) +{ + int i; + const unsigned long size = count * sizeof(i); + const unsigned long end = addr + size; + + if (end <= addr || size / sizeof(i) != count) { + printaddr(addr); + return; + } + const unsigned long abbrev_end = + (abbrev(tcp) && max_strlen < count) ? + addr + max_strlen * sizeof(i) : end; + unsigned long cur; + for (cur = addr; cur < end; cur += sizeof(i)) { + if (cur != addr) + tprints(", "); + + if (umove_or_printaddr(tcp, cur, &i)) + break; + + if (cur == addr) + tprints("["); + + if (cur >= abbrev_end) { + tprints("..."); + cur = end; + break; } + func(i); + } + if (cur != addr) + tprints("]"); +} + +SYS_FUNC(move_pages) +{ + const unsigned long npages = tcp->u_arg[1]; + + if (entering(tcp)) { + tprintf("%d, %lu, ", (int) tcp->u_arg[0], npages); + print_page_array(tcp, tcp->u_arg[2], npages); + tprints(", "); + print_int_array(tcp, tcp->u_arg[3], npages, print_int); + tprints(", "); } else { - unsigned long npages = tcp->u_arg[1]; - if (tcp->u_arg[4] == 0) - tprints("NULL, "); - else { - unsigned int i; - long statususer = tcp->u_arg[4]; - tprints("{"); - for (i = 0; i < npages; ++i) { - int status; - if (i > 0) - tprints(", "); - if (umove(tcp, statususer, &status) < 0) { - tprints("???"); - break; - } - tprintf("%#x", status); - statususer += sizeof(int); - } - tprints("}, "); - } + print_int_array(tcp, tcp->u_arg[4], npages, print_status); + tprints(", "); printflags(move_pages_flags, tcp->u_arg[5], "MPOL_???"); } return 0; diff --git a/tests/.gitignore b/tests/.gitignore index 514374c0..4faa3af4 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -120,6 +120,7 @@ mlockall mmap mmap64 mmsg +move_pages mq nanosleep net-accept-connect diff --git a/tests/Makefile.am b/tests/Makefile.am index 91691f4e..f13f8978 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -173,6 +173,7 @@ check_PROGRAMS = \ mmap \ mmap64 \ mmsg \ + move_pages \ mq \ nanosleep \ net-accept-connect \ @@ -449,6 +450,7 @@ DECODER_TESTS = \ mmap.test \ mmap64.test \ mmsg.test \ + move_pages.test \ mq.test \ nanosleep.test \ net-y-unix.test \ diff --git a/tests/move_pages.c b/tests/move_pages.c new file mode 100644 index 00000000..f9d695f0 --- /dev/null +++ b/tests/move_pages.c @@ -0,0 +1,235 @@ +/* + * Check decoding of move_pages syscall. + * + * Copyright (c) 2016 Dmitry V. Levin + * 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 "tests.h" +#include + +#ifdef __NR_move_pages + +# include +# include +# include + +# define MAX_STRLEN 3 + +static void +print_page_array(const void **const pages, + const unsigned long count, + const unsigned int offset) +{ + if (count <= offset) { + printf("%p", pages); + return; + } + printf("["); + unsigned long i; + for (i = 0; i < count; ++i) { + if (i) + printf(", "); + if (i + offset < count) { + if (i >= MAX_STRLEN) { + printf("..."); + break; + } + } else { + printf("%p", pages + i); + break; + } + const void *const addr = pages[i]; + if (addr) + printf("%p", addr); + else + printf("NULL"); + } + printf("]"); +} + +static void +print_node_array(const int *const nodes, + const unsigned long count, + const unsigned int offset) +{ + if (count <= offset) { + printf("%p", nodes); + return; + } + printf("["); + unsigned long i; + for (i = 0; i < count; ++i) { + if (i) + printf(", "); + if (i + offset < count) { + if (i >= MAX_STRLEN) { + printf("..."); + break; + } + } else { + printf("%p", nodes + i); + break; + } + printf("%d", nodes[i]); + } + printf("]"); +} + +static void +print_status_array(const int *const status, const unsigned long count) +{ + if (!count) { + printf("%p", status); + return; + } + printf("["); + unsigned long i; + for (i = 0; i < count; ++i) { + if (i) + printf(", "); + if (i >= MAX_STRLEN) { + printf("..."); + break; + } + if (status[i] >= 0) { + printf("%d", status[i]); + } else { + errno = -status[i]; + printf("%s", errno2name()); + } + } + printf("]"); +} + +static void +print_stat_pages(const unsigned long pid, const unsigned long count, + const void **const pages, int *const status) +{ + const unsigned long flags = (unsigned long) 0xfacefeed00000002; + + long rc = syscall(__NR_move_pages, + pid, count, pages, NULL, status, flags); + if (rc) { + int saved_errno = errno; + printf("move_pages(%d, %lu, ", (int) pid, count); + print_page_array(pages, count, 0); + errno = saved_errno; + printf(", NULL, %p, MPOL_MF_MOVE) = %ld %s (%m)\n", + status, rc, errno2name()); + } else { + printf("move_pages(%d, %lu, ", (int) pid, count); + print_page_array(pages, count, 0); + printf(", NULL, "); + print_status_array(status, count); + printf(", MPOL_MF_MOVE) = 0\n"); + } +} + +static void +print_move_pages(const unsigned long pid, + unsigned long count, + const unsigned int offset, + const void **const pages, + int *const nodes, + int *const status) +{ + const unsigned long flags = (unsigned long) 0xfacefeed00000004; + count += offset; + + long rc = syscall(__NR_move_pages, + pid, count, pages, nodes, status, flags); + int saved_errno = errno; + printf("move_pages(%d, %lu, ", (int) pid, count); + print_page_array(pages, count, offset); + printf(", "); + print_node_array(nodes, count, offset); + printf(", %p, MPOL_MF_MOVE_ALL) = ", status); + if (rc) { + errno = saved_errno; + printf("%ld %s (%m)\n", rc, errno2name()); + } else { + puts("0"); + } +} + +int +main(void) +{ + const unsigned long pid = + (unsigned long) 0xfacefeed00000000 | getpid(); + unsigned long count = 1; + (void) tail_alloc(1); + const unsigned page_size = get_page_size(); + const void *const page = tail_alloc(page_size); + const void *const efault = page + page_size; + const void **pages = tail_alloc(sizeof(*pages)); + int *nodes = tail_alloc(sizeof(*nodes)); + int *status = tail_alloc(sizeof(*status)); + (void) tail_alloc(1); + + print_stat_pages(pid, 0, pages, status); + print_move_pages(pid, 0, 0, pages, nodes, status); + print_move_pages(pid, 0, 1, pages + 1, nodes + 1, status + 1); + + *pages = page; + print_stat_pages(pid, count, pages, status); + *nodes = 0xdeadbee1; + print_move_pages(pid, count, 0, pages, nodes, status); + print_move_pages(pid, count, 1, pages, nodes, status); + + ++count; + --status; + *(--pages) = efault; + print_stat_pages(pid, count, pages, status); + *(--nodes) = 0xdeadbee2; + print_move_pages(pid, count, 0, pages, nodes, status); + print_move_pages(pid, count, 1, pages, nodes, status); + + ++count; + --status; + *(--pages) = nodes; + print_stat_pages(pid, count, pages, status); + *(--nodes) = 0xdeadbee3; + print_move_pages(pid, count, 0, pages, nodes, status); + print_move_pages(pid, count, 1, pages, nodes, status); + + ++count; + --status; + *(--pages) = status; + print_stat_pages(pid, count, pages, status); + *(--nodes) = 0xdeadbee4; + print_move_pages(pid, count, 0, pages, nodes, status); + print_move_pages(pid, count, 1, pages, nodes, status); + + puts("+++ exited with 0 +++"); + return 0; +} + +#else + +SKIP_MAIN_UNDEFINED("__NR_move_pages") + +#endif diff --git a/tests/move_pages.test b/tests/move_pages.test new file mode 100755 index 00000000..f9577172 --- /dev/null +++ b/tests/move_pages.test @@ -0,0 +1,6 @@ +#!/bin/sh + +# Check decoding of move_pages syscall. + +. "${srcdir=.}/init.sh" +run_strace_match_diff -s3