From patchwork Mon Jan 20 21:22:01 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean Pihet X-Patchwork-Id: 23419 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ie0-f200.google.com (mail-ie0-f200.google.com [209.85.223.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id EF08F203C6 for ; Mon, 20 Jan 2014 21:22:22 +0000 (UTC) Received: by mail-ie0-f200.google.com with SMTP id tp5sf10786256ieb.11 for ; Mon, 20 Jan 2014 13:22:22 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=ae5x7CCTnglhWyd7Rc4wONfQNZBwe5NjxsX5So8tCOc=; b=ez/NP1+IhRyFdD/PErxVw8JoeNr96KphKJsEN9TuGYde7hwKrwyME3EM/n+2CCvG6C Z78DWtXFNpSDRq2bUXrGigcuR0cA7H43UJF0kH54dq8YMFbrcqQv9Zb+8Y2RP8BuWBs7 iGFguRaodN6ulqyc/zDpgxsyaLTMAB0mvWOS5BvAugARi019L8rtH7quXYVUm6n7X6Sl pUMdx8q4HuPHXts9x0JXvwwRdAVnv6pDxBJsADqCncXM1WSLUOjjDtUBZoXsE183G4TQ 4MhE6/TrNzFJII2+116QBbLlECpmFn3GU3Me9YVjddv1kGWfe+0vYIHFOQfMLgL0vXap rQYw== X-Gm-Message-State: ALoCoQlhjtckZ3oRGgf6FzA9YV3t0+0B28C//9jcyqUC2brmNT+24EN52Pfeuu23ZHeFZ8cKsJ1A X-Received: by 10.43.163.202 with SMTP id mp10mr6884386icc.19.1390252942280; Mon, 20 Jan 2014 13:22:22 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.83.73 with SMTP id i67ls1074711qgd.97.gmail; Mon, 20 Jan 2014 13:22:22 -0800 (PST) X-Received: by 10.220.191.134 with SMTP id dm6mr11959652vcb.16.1390252942141; Mon, 20 Jan 2014 13:22:22 -0800 (PST) Received: from mail-vb0-f52.google.com (mail-vb0-f52.google.com [209.85.212.52]) by mx.google.com with ESMTPS id uh1si792719vcb.100.2014.01.20.13.22.22 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 20 Jan 2014 13:22:22 -0800 (PST) Received-SPF: neutral (google.com: 209.85.212.52 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.212.52; Received: by mail-vb0-f52.google.com with SMTP id p14so3023058vbm.39 for ; Mon, 20 Jan 2014 13:22:22 -0800 (PST) X-Received: by 10.221.42.8 with SMTP id tw8mr11963444vcb.12.1390252942056; Mon, 20 Jan 2014 13:22:22 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp77096vcz; Mon, 20 Jan 2014 13:22:21 -0800 (PST) X-Received: by 10.14.202.8 with SMTP id c8mr4150228eeo.88.1390252941095; Mon, 20 Jan 2014 13:22:21 -0800 (PST) Received: from mail-ea0-f173.google.com (mail-ea0-f173.google.com [209.85.215.173]) by mx.google.com with ESMTPS id f43si4655075eeo.133.2014.01.20.13.22.20 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 20 Jan 2014 13:22:21 -0800 (PST) Received-SPF: neutral (google.com: 209.85.215.173 is neither permitted nor denied by best guess record for domain of jean.pihet@linaro.org) client-ip=209.85.215.173; Received: by mail-ea0-f173.google.com with SMTP id d10so578409eaj.32 for ; Mon, 20 Jan 2014 13:22:20 -0800 (PST) X-Received: by 10.14.251.68 with SMTP id a44mr6941356ees.64.1390252940673; Mon, 20 Jan 2014 13:22:20 -0800 (PST) Received: from localhost.localdomain (222.28-245-81.adsl-dyn.isp.belgacom.be. [81.245.28.222]) by mx.google.com with ESMTPSA id w4sm7306209eef.20.2014.01.20.13.22.19 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Mon, 20 Jan 2014 13:22:20 -0800 (PST) From: Jean Pihet To: libunwind-devel Cc: Will Deacon , Jiri Olsa , patches@linaro.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Jean Pihet Subject: [PATCH 2/3] Dwarf: load and parse the debug info of different target address sizes Date: Mon, 20 Jan 2014 22:22:01 +0100 Message-Id: <1390252922-25889-3-git-send-email-jean.pihet@linaro.org> X-Mailer: git-send-email 1.7.11.7 In-Reply-To: <1390252922-25889-1-git-send-email-jean.pihet@linaro.org> References: <1390252922-25889-1-git-send-email-jean.pihet@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: jean.pihet@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.52 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , When in compat mode, load and parse the dwarf debug info accordingly. Tested dwarf local unwinding on ARMv8 (aka AARCH64) with ARMv7 and ARMv8 binaries. Signed-off-by: Jean Pihet --- src/dwarf/Gfde.c | 25 ++++-- src/dwarf/Gfind_proc_info-lsb.c | 194 +++++++++++++++++++++++++++++++--------- 2 files changed, 170 insertions(+), 49 deletions(-) diff --git a/src/dwarf/Gfde.c b/src/dwarf/Gfde.c index 8659624..81959d1 100644 --- a/src/dwarf/Gfde.c +++ b/src/dwarf/Gfde.c @@ -59,14 +59,23 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr, /* Pick appropriate default for FDE-encoding. DWARF spec says start-IP (initial_location) and the code-size (address_range) are "address-unit sized constants". The `R' augmentation can be used - to override this, but by default, we pick an address-sized unit - for fde_encoding. */ - switch (dwarf_addr_size (as)) - { - case 4: fde_encoding = DW_EH_PE_udata4; break; - case 8: fde_encoding = DW_EH_PE_udata8; break; - default: fde_encoding = DW_EH_PE_omit; break; - } + to override this, but by default, we pick the target binary address + size unit for fde_encoding. */ + switch (as->target_addr_size) + { + /* If defined at binary load time (e.g. from the ELF format) */ + case TARGET_ADDR_SIZE_32: fde_encoding = DW_EH_PE_udata4; break; + case TARGET_ADDR_SIZE_64: fde_encoding = DW_EH_PE_udata8; break; + /* If not defined, use the current address size unit */ + case TARGET_ADDR_SIZE_DEFAULT: + default: + switch (dwarf_addr_size (as)) + { + case 4: fde_encoding = DW_EH_PE_udata4; break; + case 8: fde_encoding = DW_EH_PE_udata8; break; + default: fde_encoding = DW_EH_PE_omit; break; + } + } dci->lsda_encoding = DW_EH_PE_omit; dci->handler = 0; diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c index f75bda2..8c35e58 100644 --- a/src/dwarf/Gfind_proc_info-lsb.c +++ b/src/dwarf/Gfind_proc_info-lsb.c @@ -81,36 +81,89 @@ linear_search (unw_addr_space_t as, unw_word_t ip, #endif /* !UNW_REMOTE_ONLY */ #ifdef CONFIG_DEBUG_FRAME -/* Load .debug_frame section from FILE. Allocates and returns space - in *BUF, and sets *BUFSIZE to its size. IS_LOCAL is 1 if using the - local process, in which case we can search the system debug file - directory; 0 for other address spaces, in which case we do not; or - -1 for recursive calls following .gnu_debuglink. Returns 0 on - success, 1 on error. Succeeds even if the file contains no - .debug_frame. */ -/* XXX: Could use mmap; but elf_map_image keeps tons mapped in. */ - -static int -load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) +static int load_debug_frame_Elf32(const char *file, FILE *f, char *linkbuf, + size_t *linksize, char **buf, size_t *bufsize) { - FILE *f; - Elf_W (Ehdr) ehdr; - Elf_W (Half) shstrndx; - Elf_W (Shdr) *sec_hdrs = NULL; + Elf32_Ehdr ehdr; + Elf32_Shdr *sec_hdrs = NULL; + Elf32_Half shstrndx; char *stringtab = NULL; unsigned int i; - size_t linksize = 0; - char *linkbuf = NULL; + + if (fseek(f, 0L, SEEK_SET)) + goto file_error; + if (fread (&ehdr, sizeof(Elf32_Ehdr), 1, f) != 1) + goto file_error; - *buf = NULL; - *bufsize = 0; + shstrndx = ehdr.e_shstrndx; - f = fopen (file, "r"); + Debug (4, "opened file '%s'. Section header at offset %d\n", + file, (int) ehdr.e_shoff); + + fseek (f, ehdr.e_shoff, SEEK_SET); + sec_hdrs = calloc (ehdr.e_shnum, sizeof(Elf32_Shdr)); + if (fread (sec_hdrs, sizeof(Elf32_Shdr), ehdr.e_shnum, f) != ehdr.e_shnum) + goto file_error; - if (!f) - return 1; + Debug (4, "loading string table of size %zd\n", + sec_hdrs[shstrndx].sh_size); + stringtab = malloc (sec_hdrs[shstrndx].sh_size); + fseek (f, sec_hdrs[shstrndx].sh_offset, SEEK_SET); + if (fread (stringtab, 1, sec_hdrs[shstrndx].sh_size, f) != sec_hdrs[shstrndx].sh_size) + goto file_error; - if (fread (&ehdr, sizeof (Elf_W (Ehdr)), 1, f) != 1) + for (i = 1; i < ehdr.e_shnum && *buf == NULL; i++) + { + char *secname = &stringtab[sec_hdrs[i].sh_name]; + + if (strcmp (secname, ".debug_frame") == 0) + { + *bufsize = sec_hdrs[i].sh_size; + *buf = malloc (*bufsize); + + fseek (f, sec_hdrs[i].sh_offset, SEEK_SET); + if (fread (*buf, 1, *bufsize, f) != *bufsize) + goto file_error; + + Debug (4, "read %zd bytes of .debug_frame from offset %d\n", + *bufsize, sec_hdrs[i].sh_offset); + } + else if (strcmp (secname, ".gnu_debuglink") == 0) + { + *linksize = sec_hdrs[i].sh_size; + linkbuf = malloc(*linksize); + + fseek (f, sec_hdrs[i].sh_offset, SEEK_SET); + if (fread (linkbuf, 1, *linksize, f) != *linksize) + goto file_error; + + Debug (4, "read %d bytes of .gnu_debuglink from offset %d\n", + (int) *linksize, sec_hdrs[i].sh_offset); + } + } + + free(sec_hdrs); + free(stringtab); + return 0; + +file_error: + free(sec_hdrs); + free(stringtab); + return -1; +} + +static int load_debug_frame_Elf64(const char *file, FILE *f, char *linkbuf, + size_t *linksize, char **buf, size_t *bufsize) +{ + Elf64_Ehdr ehdr; + Elf64_Shdr *sec_hdrs = NULL; + Elf64_Half shstrndx; + char *stringtab = NULL; + unsigned int i; + + if (fseek(f, 0L, SEEK_SET)) + goto file_error; + if (fread (&ehdr, sizeof(Elf64_Ehdr), 1, f) != 1) goto file_error; shstrndx = ehdr.e_shstrndx; @@ -119,8 +172,8 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) file, (int) ehdr.e_shoff); fseek (f, ehdr.e_shoff, SEEK_SET); - sec_hdrs = calloc (ehdr.e_shnum, sizeof (Elf_W (Shdr))); - if (fread (sec_hdrs, sizeof (Elf_W (Shdr)), ehdr.e_shnum, f) != ehdr.e_shnum) + sec_hdrs = calloc (ehdr.e_shnum, sizeof(Elf64_Shdr)); + if (fread (sec_hdrs, sizeof(Elf64_Shdr), ehdr.e_shnum, f) != ehdr.e_shnum) goto file_error; Debug (4, "loading string table of size %zd\n", @@ -131,7 +184,7 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) goto file_error; for (i = 1; i < ehdr.e_shnum && *buf == NULL; i++) - { + { char *secname = &stringtab[sec_hdrs[i].sh_name]; if (strcmp (secname, ".debug_frame") == 0) @@ -148,20 +201,71 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) } else if (strcmp (secname, ".gnu_debuglink") == 0) { - linksize = sec_hdrs[i].sh_size; - linkbuf = malloc (linksize); + *linksize = sec_hdrs[i].sh_size; + linkbuf = malloc(*linksize); fseek (f, sec_hdrs[i].sh_offset, SEEK_SET); - if (fread (linkbuf, 1, linksize, f) != linksize) + if (fread (linkbuf, 1, *linksize, f) != *linksize) goto file_error; - Debug (4, "read %zd bytes of .gnu_debuglink from offset %zd\n", - linksize, sec_hdrs[i].sh_offset); + Debug (4, "read %d bytes of .gnu_debuglink from offset %zd\n", + (int) *linksize, sec_hdrs[i].sh_offset); } - } + } + + free(sec_hdrs); + free(stringtab); + return 0; + +file_error: + free(sec_hdrs); + free(stringtab); + return -1; +} + +/* Load .debug_frame section from FILE. Allocates and returns space + in *BUF, and sets *BUFSIZE to its size. IS_LOCAL is 1 if using the + local process, in which case we can search the system debug file + directory; 0 for other address spaces, in which case we do not; or + -1 for recursive calls following .gnu_debuglink. Returns 0 on + success, 1 on error. Succeeds even if the file contains no + .debug_frame. */ +/* XXX: Could use mmap; but elf_map_image keeps tons mapped in. */ - free (stringtab); - free (sec_hdrs); +static int +load_debug_frame (const char *file, char **buf, size_t *bufsize, + unw_addr_space_t as, int is_local) +{ + FILE *f; + unsigned char e_ident[sizeof(((Elf32_Ehdr *)0)->e_ident)]; + size_t linksize = 0; + char *linkbuf = NULL; + + *buf = NULL; + *bufsize = 0; + + f = fopen (file, "r"); + + if (!f) + return 1; + + if (fread (&e_ident, sizeof(e_ident), 1, f) != 1) + goto file_error; + + switch (e_ident[EI_CLASS]) { + case ELFCLASS32: + as->target_addr_size = TARGET_ADDR_SIZE_32; + load_debug_frame_Elf32(file, f, linkbuf, &linksize, buf, bufsize); + break; + case ELFCLASS64: + as->target_addr_size = TARGET_ADDR_SIZE_64; + load_debug_frame_Elf64(file, f, linkbuf, &linksize, buf, bufsize); + break; + case ELFCLASSNONE: + default: + Debug (15, "Wrong ELF class 0x%02x\n", e_ident[EI_CLASS]); + goto file_error; + } fclose (f); @@ -195,14 +299,14 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) strcpy (newname, basedir); strcat (newname, "/"); strcat (newname, linkbuf); - ret = load_debug_frame (newname, buf, bufsize, -1); + ret = load_debug_frame (newname, buf, bufsize, as, -1); if (ret == 1) { strcpy (newname, basedir); strcat (newname, "/.debug/"); strcat (newname, linkbuf); - ret = load_debug_frame (newname, buf, bufsize, -1); + ret = load_debug_frame (newname, buf, bufsize, as, -1); } if (ret == 1 && is_local == 1) @@ -211,20 +315,19 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) strcat (newname, basedir); strcat (newname, "/"); strcat (newname, linkbuf); - ret = load_debug_frame (newname, buf, bufsize, -1); + ret = load_debug_frame (newname, buf, bufsize, as, -1); } free (basedir); free (newname); } - free (linkbuf); + + free(linkbuf); return 0; /* An error reading image file. Release resources and return error code */ file_error: - free(stringtab); - free(sec_hdrs); free(linkbuf); fclose(f); @@ -303,7 +406,8 @@ locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname, else name = (char*) dlname; - err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space); + err = load_debug_frame (name, &buf, &bufsize, as, + as == unw_local_addr_space); if (!err) { @@ -851,6 +955,14 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, #ifndef UNW_REMOTE_ONLY struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data; + /* + * Set the target address size as found in the loaded debug binary. + * Note: in case of local unwinding the caller 'as' is set to + * unw_local_addr_space, cf. below. Let's assign the value to + * the caller 'as' before changing the value of 'as'. + */ + as->target_addr_size = unw_local_addr_space->target_addr_size; + /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is read from local address space. Both the index and the unwind tables live in local memory, but the address space to check for properties like the address size and