From 20a4f14f6e6f543100bfdd93705cbdebb549d250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Apr 2020 23:41:25 +0200 Subject: [PATCH 01/13] .github: Enable repo-lockdown bot to refuse GitHub pull requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some GitHub users try to open pull requests against the GitHub mirror. Unfortunate these get ignored until eventually someone notices and closes the request. Enable the 'Repo Lockdown' [*] 3rd party bot which can autorespond to pull requests with a friendly comment, close the request, and then lock it to prevent further comments. [*] https://github.com/dessant/repo-lockdown Suggested-by: Daniel P. Berrangé Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: John Snow Message-Id: <20200406214125.18538-1-f4bug@amsat.org> [AJB: s/fill/file/ and point at canonical qemu.org/contribute] Signed-off-by: Alex Bennée --- .github/lockdown.yml | 34 ++++++++++++++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 35 insertions(+) create mode 100644 .github/lockdown.yml diff --git a/.github/lockdown.yml b/.github/lockdown.yml new file mode 100644 index 000000000000..9acc393f1cf1 --- /dev/null +++ b/.github/lockdown.yml @@ -0,0 +1,34 @@ +# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown + +# Close issues and pull requests +close: true + +# Lock issues and pull requests +lock: true + +issues: + comment: | + Thank you for your interest in the QEMU project. + + This repository is a read-only mirror of the project's master + repostories hosted on https://git.qemu.org/git/qemu.git. + The project does not process issues filed on GitHub. + + The project issues are tracked on Launchpad: + https://bugs.launchpad.net/qemu + + QEMU welcomes bug report contributions. You can file new ones on: + https://bugs.launchpad.net/qemu/+filebug + +pulls: + comment: | + Thank you for your interest in the QEMU project. + + This repository is a read-only mirror of the project's master + repostories hosted on https://git.qemu.org/git/qemu.git. + The project does not process merge requests filed on GitHub. + + QEMU welcomes contributions of code (either fixing bugs or adding new + functionality). However, we get a lot of patches, and so we have some + guidelines about contributing on the project website: + https://www.qemu.org/contribute/ diff --git a/MAINTAINERS b/MAINTAINERS index 9d156d73b31e..0559e847901a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2833,6 +2833,7 @@ M: Alex Bennée M: Fam Zheng R: Philippe Mathieu-Daudé S: Maintained +F: .github/lockdown.yml F: .travis.yml F: scripts/travis/ F: .shippable.yml From 040425f849b959ed903610cc028e0996d921f9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 3 Apr 2020 20:11:39 +0100 Subject: [PATCH 02/13] elf-ops: bail out if we have no function symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's perfectly possible to have no function symbols in your elf file and if we do the undefined behaviour sanitizer rightly complains about us passing NULL to qsort. Check nsyms before we go ahead. While we are at it lets drop the unchecked return value and cleanup the fail leg by use of g_autoptr. Another fix was proposed 101 weeks ago in: Message-Id: 20180421232120.22208-1-f4bug@amsat.org Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200403191150.863-2-alex.bennee@linaro.org> --- include/hw/elf_ops.h | 48 +++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index a1411bfcab62..e0bb47bb678d 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -104,19 +104,21 @@ static int glue(symcmp, SZ)(const void *s0, const void *s1) : ((sym0->st_value > sym1->st_value) ? 1 : 0); } -static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab, - int clear_lsb, symbol_fn_t sym_cb) +static void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab, + int clear_lsb, symbol_fn_t sym_cb) { - struct elf_shdr *symtab, *strtab, *shdr_table = NULL; - struct elf_sym *syms = NULL; + struct elf_shdr *symtab, *strtab; + g_autofree struct elf_shdr *shdr_table = NULL; + g_autofree struct elf_sym *syms = NULL; + g_autofree char *str = NULL; struct syminfo *s; int nsyms, i; - char *str = NULL; shdr_table = load_at(fd, ehdr->e_shoff, sizeof(struct elf_shdr) * ehdr->e_shnum); - if (!shdr_table) - return -1; + if (!shdr_table) { + return ; + } if (must_swab) { for (i = 0; i < ehdr->e_shnum; i++) { @@ -125,23 +127,25 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab, } symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB); - if (!symtab) - goto fail; + if (!symtab) { + return; + } syms = load_at(fd, symtab->sh_offset, symtab->sh_size); - if (!syms) - goto fail; + if (!syms) { + return; + } nsyms = symtab->sh_size / sizeof(struct elf_sym); /* String table */ if (symtab->sh_link >= ehdr->e_shnum) { - goto fail; + return; } strtab = &shdr_table[symtab->sh_link]; str = load_at(fd, strtab->sh_offset, strtab->sh_size); if (!str) { - goto fail; + return; } i = 0; @@ -170,8 +174,13 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab, } i++; } - syms = g_realloc(syms, nsyms * sizeof(*syms)); + /* check we have symbols left */ + if (nsyms == 0) { + return; + } + + syms = g_realloc(syms, nsyms * sizeof(*syms)); qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ)); for (i = 0; i < nsyms - 1; i++) { if (syms[i].st_size == 0) { @@ -182,18 +191,11 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab, /* Commit */ s = g_malloc0(sizeof(*s)); s->lookup_symbol = glue(lookup_symbol, SZ); - glue(s->disas_symtab.elf, SZ) = syms; + glue(s->disas_symtab.elf, SZ) = g_steal_pointer(&syms); s->disas_num_syms = nsyms; - s->disas_strtab = str; + s->disas_strtab = g_steal_pointer(&str); s->next = syminfos; syminfos = s; - g_free(shdr_table); - return 0; - fail: - g_free(syms); - g_free(str); - g_free(shdr_table); - return -1; } static int glue(elf_reloc, SZ)(struct elfhdr *ehdr, int fd, int must_swab, From bbf5f2a1aa39fcab01000a0f3b566f1e6b788a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 3 Apr 2020 20:11:40 +0100 Subject: [PATCH 03/13] linux-user: protect fcntl64 with an #ifdef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Checking TARGET_ABI_BITS is sketchy - we should check for the presence of the define to be sure. Also clean up the white space while we are there. Signed-off-by: Alex Bennée Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20200403191150.863-3-alex.bennee@linaro.org> --- linux-user/syscall.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5af55fca7811..b679bc6b136d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -11331,11 +11331,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, This is a hint, so ignoring and returning success is ok. */ return 0; #endif -#if TARGET_ABI_BITS == 32 +#ifdef TARGET_NR_fcntl64 case TARGET_NR_fcntl64: { - int cmd; - struct flock64 fl; + int cmd; + struct flock64 fl; from_flock64_fn *copyfrom = copy_from_user_flock64; to_flock64_fn *copyto = copy_to_user_flock64; @@ -11346,7 +11346,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, } #endif - cmd = target_to_host_fcntl_cmd(arg2); + cmd = target_to_host_fcntl_cmd(arg2); if (cmd == -TARGET_EINVAL) { return cmd; } From af7fc47f2c28fe0183ce98aa070e1b899cd08199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 3 Apr 2020 20:11:41 +0100 Subject: [PATCH 04/13] tests/tcg: remove extraneous pasting macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are not using them and they just get in the way. Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200403191150.863-4-alex.bennee@linaro.org> --- tests/tcg/x86_64/system/boot.S | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/tcg/x86_64/system/boot.S b/tests/tcg/x86_64/system/boot.S index 205cfbd39823..73b19a2bda68 100644 --- a/tests/tcg/x86_64/system/boot.S +++ b/tests/tcg/x86_64/system/boot.S @@ -41,10 +41,7 @@ #define XEN_ELFNOTE_PHYS32_ENTRY 18 #define __ASM_FORM(x) x -#define __ASM_FORM_RAW(x) x -#define __ASM_FORM_COMMA(x) x, -#define __ASM_SEL(a,b) __ASM_FORM(b) -#define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b) +#define __ASM_SEL(a,b) __ASM_FORM(b) #define _ASM_PTR __ASM_SEL(.long, .quad) ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, _ASM_PTR 0x100000) From b859040dc44b271e9ad29f729cac71d2389b05fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 3 Apr 2020 20:11:42 +0100 Subject: [PATCH 05/13] linux-user: more debug for init_guest_space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Searching for memory space can cause problems so lets extend the CPU_LOG_PAGE output so you can watch init_guest_space fail to allocate memory. A more involved fix is actually required to make this function play nicely with the large guard pages the sanitiser likes to use. Signed-off-by: Alex Bennée Reviewed-by: Laurent Vivier Message-Id: <20200403191150.863-5-alex.bennee@linaro.org> --- linux-user/elfload.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 8198be044604..619c054cc48f 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2172,6 +2172,8 @@ unsigned long init_guest_space(unsigned long host_start, /* Check to see if the address is valid. */ if (host_start && real_start != current_start) { + qemu_log_mask(CPU_LOG_PAGE, "invalid %lx && %lx != %lx\n", + host_start, real_start, current_start); goto try_again; } @@ -2240,7 +2242,11 @@ unsigned long init_guest_space(unsigned long host_start, * probably a bad strategy if not, which means we got here * because of trouble with ARM commpage setup. */ - munmap((void *)real_start, real_size); + if (munmap((void *)real_start, real_size) != 0) { + error_report("%s: failed to unmap %lx:%lx (%s)", __func__, + real_start, real_size, strerror(errno)); + abort(); + } current_start += align; if (host_start == current_start) { /* Theoretically possible if host doesn't have any suitably From 1f089c6705fdb0da1b6def842ecf323b07a4460f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 3 Apr 2020 20:11:43 +0100 Subject: [PATCH 06/13] target/xtensa: add FIXME for translation memory leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dynamically allocating a new structure within the DisasContext can potentially leak as we can longjmp out of the translation loop (see test_phys_mem). The proper fix would be to use static allocation within the DisasContext but as the Xtensa translator imports it's code from elsewhere I leave that as an exercise for the maintainer. Signed-off-by: Alex Bennée Acked-by: Max Filippov Message-Id: <20200403191150.863-6-alex.bennee@linaro.org> --- target/xtensa/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 8aa972cafdf3..37f65b1f0305 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -1174,6 +1174,11 @@ static void xtensa_tr_init_disas_context(DisasContextBase *dcbase, dc->callinc = ((tb_flags & XTENSA_TBFLAG_CALLINC_MASK) >> XTENSA_TBFLAG_CALLINC_SHIFT); + /* + * FIXME: This will leak when a failed instruction load or similar + * event causes us to longjump out of the translation loop and + * hence not clean-up in xtensa_tr_tb_stop + */ if (dc->config->isa) { dc->insnbuf = xtensa_insnbuf_alloc(dc->config->isa); dc->slotbuf = xtensa_insnbuf_alloc(dc->config->isa); From 076b2fadb582e4734a879f843885dad38cf91526 Mon Sep 17 00:00:00 2001 From: Denis Plotnikov Date: Fri, 3 Apr 2020 20:11:44 +0100 Subject: [PATCH 07/13] gdbstub: fix compiler complaining MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ./gdbstub.c: In function ‘handle_query_thread_extra’: /usr/include/glib-2.0/glib/glib-autocleanups.h:28:10: error: ‘cpu_name’ may be used uninitialized in this function [-Werror=maybe-uninitialized] g_free (*pp); ^ ./gdbstub.c:2063:26: note: ‘cpu_name’ was declared here g_autofree char *cpu_name; ^ cc1: all warnings being treated as errors Signed-off-by: Denis Plotnikov Message-Id: <20200326151407.25046-1-dplotnikov@virtuozzo.com> Reported-by: Euler Robot Reported-by: Chen Qun Reviewed-by: Miroslav Rezanina Message-Id: <20200325092137.24020-1-kuhn.chenqun@huawei.com> Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200403191150.863-7-alex.bennee@linaro.org> --- gdbstub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 013fb1ac0f18..171e15095090 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2060,8 +2060,8 @@ static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx) /* Print the CPU model and name in multiprocess mode */ ObjectClass *oc = object_get_class(OBJECT(cpu)); const char *cpu_model = object_class_get_name(oc); - g_autofree char *cpu_name; - cpu_name = object_get_canonical_path_component(OBJECT(cpu)); + g_autofree char *cpu_name = + object_get_canonical_path_component(OBJECT(cpu)); g_string_printf(rs, "%s %s [%s]", cpu_model, cpu_name, cpu->halted ? "halted " : "running"); } else { From 2f311075b7a74124098effc72290767b02869561 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 3 Apr 2020 20:11:45 +0100 Subject: [PATCH 08/13] softfloat: Fix BAD_SHIFT from normalizeFloatx80Subnormal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All other calls to normalize*Subnormal detect zero input before the call -- this is the only outlier. This case can happen with +0.0 + +0.0 = +0.0 or -0.0 + -0.0 = -0.0, so return a zero of the correct sign. Reported-by: Coverity (CID 1421991) Signed-off-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20200327232042.10008-1-richard.henderson@linaro.org> Message-Id: <20200403191150.863-8-alex.bennee@linaro.org> --- fpu/softfloat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 301ce3b537b6..ae6ba7185405 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5856,6 +5856,9 @@ static floatx80 addFloatx80Sigs(floatx80 a, floatx80 b, flag zSign, zSig1 = 0; zSig0 = aSig + bSig; if ( aExp == 0 ) { + if (zSig0 == 0) { + return packFloatx80(zSign, 0, 0); + } normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 ); goto roundAndPack; } From 01ef6b9e4e4e84b106b7f934354eada8fe36674f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 3 Apr 2020 20:11:46 +0100 Subject: [PATCH 09/13] linux-user: factor out reading of /proc/self/maps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unfortunately reading /proc/self/maps is still considered the gold standard for a process finding out about it's own memory layout. As we will want this data in other contexts soon factor out the code to read and parse the data. Rather than just blindly copying the existing sscanf based code we use a more modern glib version of the parsing code to make a more general purpose map structure. Signed-off-by: Alex Bennée Message-Id: <20200403191150.863-9-alex.bennee@linaro.org> --- include/qemu/selfmap.h | 44 ++++++++++++++++++++++++ linux-user/syscall.c | 58 +++++++++++++++---------------- util/Makefile.objs | 1 + util/selfmap.c | 78 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 30 deletions(-) create mode 100644 include/qemu/selfmap.h create mode 100644 util/selfmap.c diff --git a/include/qemu/selfmap.h b/include/qemu/selfmap.h new file mode 100644 index 000000000000..8382c4c779dc --- /dev/null +++ b/include/qemu/selfmap.h @@ -0,0 +1,44 @@ +/* + * Utility functions to read our own memory map + * + * Copyright (c) 2020 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef _SELFMAP_H_ +#define _SELFMAP_H_ + +typedef struct { + unsigned long start; + unsigned long end; + + /* flags */ + bool is_read; + bool is_write; + bool is_exec; + bool is_priv; + + unsigned long offset; + gchar *dev; + uint64_t inode; + gchar *path; +} MapInfo; + + +/** + * read_self_maps: + * + * Read /proc/self/maps and return a list of MapInfo structures. + */ +GSList *read_self_maps(void); + +/** + * free_self_maps: + * @info: a GSlist + * + * Free a list of MapInfo structures. + */ +void free_self_maps(GSList *info); + +#endif /* _SELFMAP_H_ */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b679bc6b136d..5f1178729474 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -117,6 +117,7 @@ #include "qemu.h" #include "qemu/guest-random.h" +#include "qemu/selfmap.h" #include "user/syscall-trace.h" #include "qapi/error.h" #include "fd-trans.h" @@ -7232,45 +7233,45 @@ static int open_self_maps(void *cpu_env, int fd) { CPUState *cpu = env_cpu((CPUArchState *)cpu_env); TaskState *ts = cpu->opaque; - FILE *fp; - char *line = NULL; - size_t len = 0; - ssize_t read; + GSList *map_info = read_self_maps(); + GSList *s; - fp = fopen("/proc/self/maps", "r"); - if (fp == NULL) { - return -1; - } + for (s = map_info; s; s = g_slist_next(s)) { + MapInfo *e = (MapInfo *) s->data; - while ((read = getline(&line, &len, fp)) != -1) { - int fields, dev_maj, dev_min, inode; - uint64_t min, max, offset; - char flag_r, flag_w, flag_x, flag_p; - char path[512] = ""; - fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d" - " %512s", &min, &max, &flag_r, &flag_w, &flag_x, - &flag_p, &offset, &dev_maj, &dev_min, &inode, path); - - if ((fields < 10) || (fields > 11)) { - continue; - } - if (h2g_valid(min)) { + if (h2g_valid(e->start)) { + unsigned long min = e->start; + unsigned long max = e->end; int flags = page_get_flags(h2g(min)); - max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1; + const char *path; + + max = h2g_valid(max - 1) ? + max : (uintptr_t) g2h(GUEST_ADDR_MAX) + 1; + if (page_check_range(h2g(min), max - min, flags) == -1) { continue; } + if (h2g(min) == ts->info->stack_limit) { - pstrcpy(path, sizeof(path), " [stack]"); + path = " [stack]"; + } else { + path = e->path; } + dprintf(fd, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr - " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n", - h2g(min), h2g(max - 1) + 1, flag_r, flag_w, - flag_x, flag_p, offset, dev_maj, dev_min, inode, - path[0] ? " " : "", path); + " %c%c%c%c %08" PRIx64 " %s %"PRId64" %s%s\n", + h2g(min), h2g(max - 1) + 1, + e->is_read ? 'r' : '-', + e->is_write ? 'w' : '-', + e->is_exec ? 'x' : '-', + e->is_priv ? 'p' : '-', + (uint64_t) e->offset, e->dev, e->inode, + path ? " " : "", path ? path : ""); } } + free_self_maps(map_info); + #ifdef TARGET_VSYSCALL_PAGE /* * We only support execution from the vsyscall page. @@ -7281,9 +7282,6 @@ static int open_self_maps(void *cpu_env, int fd) TARGET_VSYSCALL_PAGE, TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE); #endif - free(line); - fclose(fp); - return 0; } diff --git a/util/Makefile.objs b/util/Makefile.objs index 6718a38b616d..fe339c2636ba 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -63,3 +63,4 @@ util-obj-y += guest-random.o util-obj-$(CONFIG_GIO) += dbus.o dbus.o-cflags = $(GIO_CFLAGS) dbus.o-libs = $(GIO_LIBS) +util-obj-$(CONFIG_USER_ONLY) += selfmap.o diff --git a/util/selfmap.c b/util/selfmap.c new file mode 100644 index 000000000000..2ec99dfdda17 --- /dev/null +++ b/util/selfmap.c @@ -0,0 +1,78 @@ +/* + * Utility function to get QEMU's own process map + * + * Copyright (c) 2020 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "qemu/selfmap.h" + +GSList *read_self_maps(void) +{ + gchar *maps; + GSList *map_info = NULL; + + if (g_file_get_contents("/proc/self/maps", &maps, NULL, NULL)) { + gchar **lines = g_strsplit(maps, "\n", 0); + int i, entries = g_strv_length(lines); + + for (i = 0; i < entries; i++) { + gchar **fields = g_strsplit(lines[i], " ", 6); + if (g_strv_length(fields) > 4) { + MapInfo *e = g_new0(MapInfo, 1); + int errors; + const char *end; + + errors = qemu_strtoul(fields[0], &end, 16, &e->start); + errors += qemu_strtoul(end + 1, NULL, 16, &e->end); + + e->is_read = fields[1][0] == 'r'; + e->is_write = fields[1][1] == 'w'; + e->is_exec = fields[1][2] == 'x'; + e->is_priv = fields[1][3] == 'p'; + + errors += qemu_strtoul(fields[2], NULL, 16, &e->offset); + e->dev = g_strdup(fields[3]); + errors += qemu_strtou64(fields[4], NULL, 10, &e->inode); + + /* + * The last field may have leading spaces which we + * need to strip. + */ + if (g_strv_length(fields) == 6) { + e->path = g_strdup(g_strchug(fields[5])); + } + map_info = g_slist_prepend(map_info, e); + } + + g_strfreev(fields); + } + g_strfreev(lines); + g_free(maps); + } + + /* ensure the map data is in the same order we collected it */ + return g_slist_reverse(map_info); +} + +/** + * free_self_maps: + * @info: a GSlist + * + * Free a list of MapInfo structures. + */ +static void free_info(gpointer data) +{ + MapInfo *e = (MapInfo *) data; + g_free(e->dev); + g_free(e->path); + g_free(e); +} + +void free_self_maps(GSList *info) +{ + g_slist_free_full(info, &free_info); +} From bb55173cfb7bd69b79c4092bf524a32b0fdeddbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 3 Apr 2020 20:11:47 +0100 Subject: [PATCH 10/13] linux-user: clean-up padding on /proc/self/maps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't use magic spaces, calculate the justification for the file field like the kernel does with seq_pad. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20200403191150.863-10-alex.bennee@linaro.org> --- linux-user/syscall.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5f1178729474..6495ddc4cda0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7235,6 +7235,7 @@ static int open_self_maps(void *cpu_env, int fd) TaskState *ts = cpu->opaque; GSList *map_info = read_self_maps(); GSList *s; + int count; for (s = map_info; s; s = g_slist_next(s)) { MapInfo *e = (MapInfo *) s->data; @@ -7253,20 +7254,24 @@ static int open_self_maps(void *cpu_env, int fd) } if (h2g(min) == ts->info->stack_limit) { - path = " [stack]"; + path = "[stack]"; } else { path = e->path; } - dprintf(fd, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr - " %c%c%c%c %08" PRIx64 " %s %"PRId64" %s%s\n", - h2g(min), h2g(max - 1) + 1, - e->is_read ? 'r' : '-', - e->is_write ? 'w' : '-', - e->is_exec ? 'x' : '-', - e->is_priv ? 'p' : '-', - (uint64_t) e->offset, e->dev, e->inode, - path ? " " : "", path ? path : ""); + count = dprintf(fd, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr + " %c%c%c%c %08" PRIx64 " %s %"PRId64, + h2g(min), h2g(max - 1) + 1, + e->is_read ? 'r' : '-', + e->is_write ? 'w' : '-', + e->is_exec ? 'x' : '-', + e->is_priv ? 'p' : '-', + (uint64_t) e->offset, e->dev, e->inode); + if (path) { + dprintf(fd, "%*s%s\n", 73 - count, "", path); + } else { + dprintf(fd, "\n"); + } } } @@ -7277,9 +7282,10 @@ static int open_self_maps(void *cpu_env, int fd) * We only support execution from the vsyscall page. * This is as if CONFIG_LEGACY_VSYSCALL_XONLY=y from v5.3. */ - dprintf(fd, TARGET_FMT_lx "-" TARGET_FMT_lx - " --xp 00000000 00:00 0 [vsyscall]\n", - TARGET_VSYSCALL_PAGE, TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE); + count = dprintf(fd, TARGET_FMT_lx "-" TARGET_FMT_lx + " --xp 00000000 00:00 0", + TARGET_VSYSCALL_PAGE, TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE); + dprintf(fd, "%*s%s\n", 73 - count, "", "[vsyscall]"); #endif return 0; From 58d5e749d6663701f90931764f8bee6c76b0b1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 3 Apr 2020 20:11:49 +0100 Subject: [PATCH 11/13] hw/core: properly terminate loading .hex on EOF record MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The https://makecode.microbit.org/#editor generates slightly weird .hex files which work fine on a real microbit but causes QEMU to choke. The reason is extraneous data after the EOF record which causes the loader to attempt to write a bigger file than it should to the "rom". According to the HEX file spec an EOF really should be the last thing we process so lets do that. Reported-by: Ursula Bennée Signed-off-by: Alex Bennée Reviewed-by: Stefan Hajnoczi Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20200403191150.863-12-alex.bennee@linaro.org> --- hw/core/loader.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index eeef6da9a1b6..8bbb1797a4c9 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -1447,6 +1447,7 @@ typedef struct { uint32_t current_rom_index; uint32_t rom_start_address; AddressSpace *as; + bool complete; } HexParser; /* return size or -1 if error */ @@ -1484,6 +1485,7 @@ static int handle_record_type(HexParser *parser) parser->current_rom_index, parser->rom_start_address, parser->as); } + parser->complete = true; return parser->total_size; case EXT_SEG_ADDR_RECORD: case EXT_LINEAR_ADDR_RECORD: @@ -1548,11 +1550,12 @@ static int parse_hex_blob(const char *filename, hwaddr *addr, uint8_t *hex_blob, .bin_buf = g_malloc(hex_blob_size), .start_addr = addr, .as = as, + .complete = false }; rom_transaction_begin(); - for (; hex_blob < end; ++hex_blob) { + for (; hex_blob < end && !parser.complete; ++hex_blob) { switch (*hex_blob) { case '\r': case '\n': From eca7a8e6c08f80129ae0bab7d060da568ed90f20 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 3 Apr 2020 20:11:50 +0100 Subject: [PATCH 12/13] configure: Add -Werror to PIE probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without -Werror, the probe may succeed, but then compilation fails later when -Werror is added for other reasons. Shows up on windows, where the compiler complains about -fPIC. Signed-off-by: Richard Henderson Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20200401214756.6559-1-richard.henderson@linaro.org> Message-Id: <20200403191150.863-13-alex.bennee@linaro.org> --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 22870f386729..233c671aaa9b 100755 --- a/configure +++ b/configure @@ -2119,7 +2119,7 @@ if compile_prog "-Werror -fno-pie" "-no-pie"; then fi if test "$static" = "yes"; then - if test "$pie" != "no" && compile_prog "-fPIE -DPIE" "-static-pie"; then + if test "$pie" != "no" && compile_prog "-Werror -fPIE -DPIE" "-static-pie"; then QEMU_CFLAGS="-fPIE -DPIE $QEMU_CFLAGS" QEMU_LDFLAGS="-static-pie $QEMU_LDFLAGS" pie="yes" @@ -2132,7 +2132,7 @@ if test "$static" = "yes"; then elif test "$pie" = "no"; then QEMU_CFLAGS="$CFLAGS_NOPIE $QEMU_CFLAGS" QEMU_LDFLAGS="$LDFLAGS_NOPIE $QEMU_LDFLAGS" -elif compile_prog "-fPIE -DPIE" "-pie"; then +elif compile_prog "-Werror -fPIE -DPIE" "-pie"; then QEMU_CFLAGS="-fPIE -DPIE $QEMU_CFLAGS" QEMU_LDFLAGS="-pie $QEMU_LDFLAGS" pie="yes" From cce743abbf398a324879039cd582349b36da0ea6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Apr 2020 10:48:03 -0700 Subject: [PATCH 13/13] tcg/i386: Fix %r12 guest_base initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When %gs cannot be used, we use register offset addressing. This path is almost never used, so it was clearly not tested. Signed-off-by: Richard Henderson Reviewed-by: Alex Bennée Tested-by: Alex Bennée Message-Id: <20200406174803.8192-1-richard.henderson@linaro.org> Signed-off-by: Alex Bennée --- tcg/i386/tcg-target.inc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c index 7f61eeedd09c..ec083bddcfb7 100644 --- a/tcg/i386/tcg-target.inc.c +++ b/tcg/i386/tcg-target.inc.c @@ -3737,7 +3737,7 @@ static void tcg_target_qemu_prologue(TCGContext *s) } else { /* Choose R12 because, as a base, it requires a SIB byte. */ x86_guest_base_index = TCG_REG_R12; - tcg_out_mov(s, TCG_TYPE_PTR, x86_guest_base_index, guest_base); + tcg_out_movi(s, TCG_TYPE_PTR, x86_guest_base_index, guest_base); tcg_regset_set_reg(s->reserved_regs, x86_guest_base_index); } }