1da0c48c4Sopenharmony_ci/* Standard libdwfl callbacks for debugging a live Linux process. 2da0c48c4Sopenharmony_ci Copyright (C) 2005-2010, 2013, 2014, 2016 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci 5da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 6da0c48c4Sopenharmony_ci it under the terms of either 7da0c48c4Sopenharmony_ci 8da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 9da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 10da0c48c4Sopenharmony_ci your option) any later version 11da0c48c4Sopenharmony_ci 12da0c48c4Sopenharmony_ci or 13da0c48c4Sopenharmony_ci 14da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 15da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 16da0c48c4Sopenharmony_ci your option) any later version 17da0c48c4Sopenharmony_ci 18da0c48c4Sopenharmony_ci or both in parallel, as here. 19da0c48c4Sopenharmony_ci 20da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 21da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 22da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23da0c48c4Sopenharmony_ci General Public License for more details. 24da0c48c4Sopenharmony_ci 25da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 26da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 27da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 28da0c48c4Sopenharmony_ci 29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 30da0c48c4Sopenharmony_ci# include <config.h> 31da0c48c4Sopenharmony_ci#endif 32da0c48c4Sopenharmony_ci 33da0c48c4Sopenharmony_ci#include "libdwflP.h" 34da0c48c4Sopenharmony_ci#include <inttypes.h> 35da0c48c4Sopenharmony_ci#include <sys/types.h> 36da0c48c4Sopenharmony_ci#include <sys/stat.h> 37da0c48c4Sopenharmony_ci#include <errno.h> 38da0c48c4Sopenharmony_ci#include <stdio.h> 39da0c48c4Sopenharmony_ci#include <stdio_ext.h> 40da0c48c4Sopenharmony_ci#include <stdbool.h> 41da0c48c4Sopenharmony_ci#include <string.h> 42da0c48c4Sopenharmony_ci#include <stdlib.h> 43da0c48c4Sopenharmony_ci#include <fcntl.h> 44da0c48c4Sopenharmony_ci#include <unistd.h> 45da0c48c4Sopenharmony_ci#include <assert.h> 46da0c48c4Sopenharmony_ci#include <endian.h> 47da0c48c4Sopenharmony_ci#include "system.h" 48da0c48c4Sopenharmony_ci 49da0c48c4Sopenharmony_ci 50da0c48c4Sopenharmony_ci#define PROCMAPSFMT "/proc/%d/maps" 51da0c48c4Sopenharmony_ci#define PROCMEMFMT "/proc/%d/mem" 52da0c48c4Sopenharmony_ci#define PROCAUXVFMT "/proc/%d/auxv" 53da0c48c4Sopenharmony_ci#define PROCEXEFMT "/proc/%d/exe" 54da0c48c4Sopenharmony_ci 55da0c48c4Sopenharmony_ci 56da0c48c4Sopenharmony_ci/* Return ELFCLASS64 or ELFCLASS32 for the main ELF executable. Return 57da0c48c4Sopenharmony_ci ELFCLASSNONE for an error. */ 58da0c48c4Sopenharmony_ci 59da0c48c4Sopenharmony_cistatic unsigned char 60da0c48c4Sopenharmony_ciget_pid_class (pid_t pid) 61da0c48c4Sopenharmony_ci{ 62da0c48c4Sopenharmony_ci char *fname; 63da0c48c4Sopenharmony_ci if (asprintf (&fname, PROCEXEFMT, pid) < 0) 64da0c48c4Sopenharmony_ci return ELFCLASSNONE; 65da0c48c4Sopenharmony_ci 66da0c48c4Sopenharmony_ci int fd = open (fname, O_RDONLY); 67da0c48c4Sopenharmony_ci free (fname); 68da0c48c4Sopenharmony_ci if (fd < 0) 69da0c48c4Sopenharmony_ci return ELFCLASSNONE; 70da0c48c4Sopenharmony_ci 71da0c48c4Sopenharmony_ci unsigned char buf[EI_CLASS + 1]; 72da0c48c4Sopenharmony_ci ssize_t nread = pread_retry (fd, &buf, sizeof buf, 0); 73da0c48c4Sopenharmony_ci close (fd); 74da0c48c4Sopenharmony_ci if (nread != sizeof buf || buf[EI_MAG0] != ELFMAG0 75da0c48c4Sopenharmony_ci || buf[EI_MAG1] != ELFMAG1 || buf[EI_MAG2] != ELFMAG2 76da0c48c4Sopenharmony_ci || buf[EI_MAG3] != ELFMAG3 77da0c48c4Sopenharmony_ci || (buf[EI_CLASS] != ELFCLASS64 && buf[EI_CLASS] != ELFCLASS32)) 78da0c48c4Sopenharmony_ci return ELFCLASSNONE; 79da0c48c4Sopenharmony_ci 80da0c48c4Sopenharmony_ci return buf[EI_CLASS]; 81da0c48c4Sopenharmony_ci} 82da0c48c4Sopenharmony_ci 83da0c48c4Sopenharmony_ci/* Search /proc/PID/auxv for the AT_SYSINFO_EHDR tag. 84da0c48c4Sopenharmony_ci 85da0c48c4Sopenharmony_ci It would be easiest to call get_pid_class and parse everything according to 86da0c48c4Sopenharmony_ci the 32-bit or 64-bit class. But this would bring the overhead of syscalls 87da0c48c4Sopenharmony_ci to open and read the "/proc/%d/exe" file. 88da0c48c4Sopenharmony_ci 89da0c48c4Sopenharmony_ci Therefore this function tries to parse the "/proc/%d/auxv" content both 90da0c48c4Sopenharmony_ci ways, as if it were the 32-bit format and also if it were the 64-bit format. 91da0c48c4Sopenharmony_ci Only if it gives some valid data in both cases get_pid_class gets called. 92da0c48c4Sopenharmony_ci In most cases only one of the format bit sizes gives valid data and the 93da0c48c4Sopenharmony_ci get_pid_class call overhead can be saved. */ 94da0c48c4Sopenharmony_ci 95da0c48c4Sopenharmony_cistatic int 96da0c48c4Sopenharmony_cigrovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr) 97da0c48c4Sopenharmony_ci{ 98da0c48c4Sopenharmony_ci char *fname; 99da0c48c4Sopenharmony_ci if (asprintf (&fname, PROCAUXVFMT, pid) < 0) 100da0c48c4Sopenharmony_ci return ENOMEM; 101da0c48c4Sopenharmony_ci 102da0c48c4Sopenharmony_ci int fd = open (fname, O_RDONLY); 103da0c48c4Sopenharmony_ci free (fname); 104da0c48c4Sopenharmony_ci if (fd < 0) 105da0c48c4Sopenharmony_ci return errno == ENOENT ? 0 : errno; 106da0c48c4Sopenharmony_ci 107da0c48c4Sopenharmony_ci GElf_Addr sysinfo_ehdr64 = 0; 108da0c48c4Sopenharmony_ci GElf_Addr sysinfo_ehdr32 = 0; 109da0c48c4Sopenharmony_ci GElf_Addr segment_align64 = dwfl->segment_align; 110da0c48c4Sopenharmony_ci GElf_Addr segment_align32 = dwfl->segment_align; 111da0c48c4Sopenharmony_ci off_t offset = 0; 112da0c48c4Sopenharmony_ci ssize_t nread; 113da0c48c4Sopenharmony_ci union 114da0c48c4Sopenharmony_ci { 115da0c48c4Sopenharmony_ci Elf64_auxv_t a64[64]; 116da0c48c4Sopenharmony_ci Elf32_auxv_t a32[128]; 117da0c48c4Sopenharmony_ci } d; 118da0c48c4Sopenharmony_ci do 119da0c48c4Sopenharmony_ci { 120da0c48c4Sopenharmony_ci eu_static_assert (sizeof d.a64 == sizeof d.a32); 121da0c48c4Sopenharmony_ci nread = pread_retry (fd, d.a64, sizeof d.a64, offset); 122da0c48c4Sopenharmony_ci if (nread < 0) 123da0c48c4Sopenharmony_ci { 124da0c48c4Sopenharmony_ci int ret = errno; 125da0c48c4Sopenharmony_ci close (fd); 126da0c48c4Sopenharmony_ci return ret; 127da0c48c4Sopenharmony_ci } 128da0c48c4Sopenharmony_ci for (size_t a32i = 0; a32i < nread / sizeof d.a32[0]; a32i++) 129da0c48c4Sopenharmony_ci { 130da0c48c4Sopenharmony_ci const Elf32_auxv_t *a32 = d.a32 + a32i; 131da0c48c4Sopenharmony_ci switch (a32->a_type) 132da0c48c4Sopenharmony_ci { 133da0c48c4Sopenharmony_ci case AT_SYSINFO_EHDR: 134da0c48c4Sopenharmony_ci sysinfo_ehdr32 = a32->a_un.a_val; 135da0c48c4Sopenharmony_ci break; 136da0c48c4Sopenharmony_ci case AT_PAGESZ: 137da0c48c4Sopenharmony_ci segment_align32 = a32->a_un.a_val; 138da0c48c4Sopenharmony_ci break; 139da0c48c4Sopenharmony_ci } 140da0c48c4Sopenharmony_ci } 141da0c48c4Sopenharmony_ci for (size_t a64i = 0; a64i < nread / sizeof d.a64[0]; a64i++) 142da0c48c4Sopenharmony_ci { 143da0c48c4Sopenharmony_ci const Elf64_auxv_t *a64 = d.a64 + a64i; 144da0c48c4Sopenharmony_ci switch (a64->a_type) 145da0c48c4Sopenharmony_ci { 146da0c48c4Sopenharmony_ci case AT_SYSINFO_EHDR: 147da0c48c4Sopenharmony_ci sysinfo_ehdr64 = a64->a_un.a_val; 148da0c48c4Sopenharmony_ci break; 149da0c48c4Sopenharmony_ci case AT_PAGESZ: 150da0c48c4Sopenharmony_ci segment_align64 = a64->a_un.a_val; 151da0c48c4Sopenharmony_ci break; 152da0c48c4Sopenharmony_ci } 153da0c48c4Sopenharmony_ci } 154da0c48c4Sopenharmony_ci offset += nread; 155da0c48c4Sopenharmony_ci } 156da0c48c4Sopenharmony_ci while (nread == sizeof d.a64); 157da0c48c4Sopenharmony_ci 158da0c48c4Sopenharmony_ci close (fd); 159da0c48c4Sopenharmony_ci 160da0c48c4Sopenharmony_ci bool valid64 = sysinfo_ehdr64 != 0 || segment_align64 != dwfl->segment_align; 161da0c48c4Sopenharmony_ci bool valid32 = sysinfo_ehdr32 != 0 || segment_align32 != dwfl->segment_align; 162da0c48c4Sopenharmony_ci 163da0c48c4Sopenharmony_ci unsigned char pid_class = ELFCLASSNONE; 164da0c48c4Sopenharmony_ci if (valid64 && valid32) 165da0c48c4Sopenharmony_ci pid_class = get_pid_class (pid); 166da0c48c4Sopenharmony_ci 167da0c48c4Sopenharmony_ci if (pid_class == ELFCLASS64 || (valid64 && ! valid32)) 168da0c48c4Sopenharmony_ci { 169da0c48c4Sopenharmony_ci *sysinfo_ehdr = sysinfo_ehdr64; 170da0c48c4Sopenharmony_ci dwfl->segment_align = segment_align64; 171da0c48c4Sopenharmony_ci return 0; 172da0c48c4Sopenharmony_ci } 173da0c48c4Sopenharmony_ci if (pid_class == ELFCLASS32 || (! valid64 && valid32)) 174da0c48c4Sopenharmony_ci { 175da0c48c4Sopenharmony_ci *sysinfo_ehdr = sysinfo_ehdr32; 176da0c48c4Sopenharmony_ci dwfl->segment_align = segment_align32; 177da0c48c4Sopenharmony_ci return 0; 178da0c48c4Sopenharmony_ci } 179da0c48c4Sopenharmony_ci return ENOEXEC; 180da0c48c4Sopenharmony_ci} 181da0c48c4Sopenharmony_ci 182da0c48c4Sopenharmony_cistatic inline bool 183da0c48c4Sopenharmony_cido_report (Dwfl *dwfl, char **plast_file, Dwarf_Addr low, Dwarf_Addr high) 184da0c48c4Sopenharmony_ci{ 185da0c48c4Sopenharmony_ci if (*plast_file != NULL) 186da0c48c4Sopenharmony_ci { 187da0c48c4Sopenharmony_ci Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, *plast_file, 188da0c48c4Sopenharmony_ci low, high); 189da0c48c4Sopenharmony_ci free (*plast_file); 190da0c48c4Sopenharmony_ci *plast_file = NULL; 191da0c48c4Sopenharmony_ci if (unlikely (mod == NULL)) 192da0c48c4Sopenharmony_ci return true; 193da0c48c4Sopenharmony_ci } 194da0c48c4Sopenharmony_ci return false; 195da0c48c4Sopenharmony_ci} 196da0c48c4Sopenharmony_ci 197da0c48c4Sopenharmony_ci#define report() do_report(dwfl, &last_file, low, high) 198da0c48c4Sopenharmony_ci 199da0c48c4Sopenharmony_cistatic int 200da0c48c4Sopenharmony_ciproc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid) 201da0c48c4Sopenharmony_ci{ 202da0c48c4Sopenharmony_ci unsigned int last_dmajor = -1, last_dminor = -1; 203da0c48c4Sopenharmony_ci uint64_t last_ino = -1; 204da0c48c4Sopenharmony_ci char *last_file = NULL; 205da0c48c4Sopenharmony_ci Dwarf_Addr low = 0, high = 0; 206da0c48c4Sopenharmony_ci 207da0c48c4Sopenharmony_ci char *line = NULL; 208da0c48c4Sopenharmony_ci size_t linesz; 209da0c48c4Sopenharmony_ci ssize_t len; 210da0c48c4Sopenharmony_ci while ((len = getline (&line, &linesz, f)) > 0) 211da0c48c4Sopenharmony_ci { 212da0c48c4Sopenharmony_ci if (line[len - 1] == '\n') 213da0c48c4Sopenharmony_ci line[len - 1] = '\0'; 214da0c48c4Sopenharmony_ci 215da0c48c4Sopenharmony_ci Dwarf_Addr start, end, offset; 216da0c48c4Sopenharmony_ci unsigned int dmajor, dminor; 217da0c48c4Sopenharmony_ci uint64_t ino; 218da0c48c4Sopenharmony_ci int nread = -1; 219da0c48c4Sopenharmony_ci if (sscanf (line, "%" PRIx64 "-%" PRIx64 " %*s %" PRIx64 220da0c48c4Sopenharmony_ci " %x:%x %" PRIu64 " %n", 221da0c48c4Sopenharmony_ci &start, &end, &offset, &dmajor, &dminor, &ino, &nread) < 6 222da0c48c4Sopenharmony_ci || nread <= 0) 223da0c48c4Sopenharmony_ci { 224da0c48c4Sopenharmony_ci free (line); 225da0c48c4Sopenharmony_ci free (last_file); 226da0c48c4Sopenharmony_ci return ENOEXEC; 227da0c48c4Sopenharmony_ci } 228da0c48c4Sopenharmony_ci 229da0c48c4Sopenharmony_ci /* If this is the special mapping AT_SYSINFO_EHDR pointed us at, 230da0c48c4Sopenharmony_ci report the last one and then this special one. */ 231da0c48c4Sopenharmony_ci if (start == sysinfo_ehdr && start != 0) 232da0c48c4Sopenharmony_ci { 233da0c48c4Sopenharmony_ci if (report ()) 234da0c48c4Sopenharmony_ci { 235da0c48c4Sopenharmony_ci bad_report: 236da0c48c4Sopenharmony_ci free (line); 237da0c48c4Sopenharmony_ci return -1; 238da0c48c4Sopenharmony_ci } 239da0c48c4Sopenharmony_ci 240da0c48c4Sopenharmony_ci low = start; 241da0c48c4Sopenharmony_ci high = end; 242da0c48c4Sopenharmony_ci if (asprintf (&last_file, "[vdso: %d]", (int) pid) < 0 243da0c48c4Sopenharmony_ci || report ()) 244da0c48c4Sopenharmony_ci goto bad_report; 245da0c48c4Sopenharmony_ci } 246da0c48c4Sopenharmony_ci 247da0c48c4Sopenharmony_ci char *file = line + nread + strspn (line + nread, " \t"); 248da0c48c4Sopenharmony_ci if (file[0] != '/' || (ino == 0 && dmajor == 0 && dminor == 0)) 249da0c48c4Sopenharmony_ci /* This line doesn't indicate a file mapping. */ 250da0c48c4Sopenharmony_ci continue; 251da0c48c4Sopenharmony_ci 252da0c48c4Sopenharmony_ci if (last_file != NULL 253da0c48c4Sopenharmony_ci && ino == last_ino && dmajor == last_dmajor && dminor == last_dminor) 254da0c48c4Sopenharmony_ci { 255da0c48c4Sopenharmony_ci /* This is another portion of the same file's mapping. */ 256da0c48c4Sopenharmony_ci if (strcmp (last_file, file) != 0) 257da0c48c4Sopenharmony_ci { 258da0c48c4Sopenharmony_ci free (last_file); 259da0c48c4Sopenharmony_ci goto bad_report; 260da0c48c4Sopenharmony_ci } 261da0c48c4Sopenharmony_ci high = end; 262da0c48c4Sopenharmony_ci } 263da0c48c4Sopenharmony_ci else 264da0c48c4Sopenharmony_ci { 265da0c48c4Sopenharmony_ci /* This is a different file mapping. Report the last one. */ 266da0c48c4Sopenharmony_ci if (report ()) 267da0c48c4Sopenharmony_ci goto bad_report; 268da0c48c4Sopenharmony_ci low = start; 269da0c48c4Sopenharmony_ci high = end; 270da0c48c4Sopenharmony_ci last_file = strdup (file); 271da0c48c4Sopenharmony_ci last_ino = ino; 272da0c48c4Sopenharmony_ci last_dmajor = dmajor; 273da0c48c4Sopenharmony_ci last_dminor = dminor; 274da0c48c4Sopenharmony_ci } 275da0c48c4Sopenharmony_ci } 276da0c48c4Sopenharmony_ci free (line); 277da0c48c4Sopenharmony_ci 278da0c48c4Sopenharmony_ci int result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC; 279da0c48c4Sopenharmony_ci 280da0c48c4Sopenharmony_ci /* Report the final one. */ 281da0c48c4Sopenharmony_ci bool lose = report (); 282da0c48c4Sopenharmony_ci 283da0c48c4Sopenharmony_ci return result != 0 ? result : lose ? -1 : 0; 284da0c48c4Sopenharmony_ci} 285da0c48c4Sopenharmony_ci 286da0c48c4Sopenharmony_ciint 287da0c48c4Sopenharmony_cidwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *f) 288da0c48c4Sopenharmony_ci{ 289da0c48c4Sopenharmony_ci return proc_maps_report (dwfl, f, 0, 0); 290da0c48c4Sopenharmony_ci} 291da0c48c4Sopenharmony_ciINTDEF (dwfl_linux_proc_maps_report) 292da0c48c4Sopenharmony_ci 293da0c48c4Sopenharmony_ciint 294da0c48c4Sopenharmony_cidwfl_linux_proc_report (Dwfl *dwfl, pid_t pid) 295da0c48c4Sopenharmony_ci{ 296da0c48c4Sopenharmony_ci if (dwfl == NULL) 297da0c48c4Sopenharmony_ci return -1; 298da0c48c4Sopenharmony_ci 299da0c48c4Sopenharmony_ci /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it. */ 300da0c48c4Sopenharmony_ci GElf_Addr sysinfo_ehdr = 0; 301da0c48c4Sopenharmony_ci int result = grovel_auxv (pid, dwfl, &sysinfo_ehdr); 302da0c48c4Sopenharmony_ci if (result != 0) 303da0c48c4Sopenharmony_ci return result; 304da0c48c4Sopenharmony_ci 305da0c48c4Sopenharmony_ci char *fname; 306da0c48c4Sopenharmony_ci if (asprintf (&fname, PROCMAPSFMT, pid) < 0) 307da0c48c4Sopenharmony_ci return ENOMEM; 308da0c48c4Sopenharmony_ci 309da0c48c4Sopenharmony_ci FILE *f = fopen (fname, "r"); 310da0c48c4Sopenharmony_ci free (fname); 311da0c48c4Sopenharmony_ci if (f == NULL) 312da0c48c4Sopenharmony_ci return errno; 313da0c48c4Sopenharmony_ci 314da0c48c4Sopenharmony_ci (void) __fsetlocking (f, FSETLOCKING_BYCALLER); 315da0c48c4Sopenharmony_ci 316da0c48c4Sopenharmony_ci result = proc_maps_report (dwfl, f, sysinfo_ehdr, pid); 317da0c48c4Sopenharmony_ci 318da0c48c4Sopenharmony_ci fclose (f); 319da0c48c4Sopenharmony_ci 320da0c48c4Sopenharmony_ci return result; 321da0c48c4Sopenharmony_ci} 322da0c48c4Sopenharmony_ciINTDEF (dwfl_linux_proc_report) 323da0c48c4Sopenharmony_ci 324da0c48c4Sopenharmony_cistatic ssize_t 325da0c48c4Sopenharmony_ciread_proc_memory (void *arg, void *data, GElf_Addr address, 326da0c48c4Sopenharmony_ci size_t minread, size_t maxread) 327da0c48c4Sopenharmony_ci{ 328da0c48c4Sopenharmony_ci const int fd = *(const int *) arg; 329da0c48c4Sopenharmony_ci 330da0c48c4Sopenharmony_ci /* This code relies on the fact the Linux kernel accepts negative 331da0c48c4Sopenharmony_ci offsets when seeking /dev/$$/mem files, as a special case. In 332da0c48c4Sopenharmony_ci particular pread cannot be used here, because it will always 333da0c48c4Sopenharmony_ci return EINVAL when passed a negative offset. */ 334da0c48c4Sopenharmony_ci 335da0c48c4Sopenharmony_ci if (lseek (fd, (off_t) address, SEEK_SET) == -1) 336da0c48c4Sopenharmony_ci return -1; 337da0c48c4Sopenharmony_ci 338da0c48c4Sopenharmony_ci ssize_t nread = read (fd, data, maxread); 339da0c48c4Sopenharmony_ci 340da0c48c4Sopenharmony_ci if (nread > 0 && (size_t) nread < minread) 341da0c48c4Sopenharmony_ci nread = 0; 342da0c48c4Sopenharmony_ci return nread; 343da0c48c4Sopenharmony_ci} 344da0c48c4Sopenharmony_ci 345da0c48c4Sopenharmony_ciextern Elf *elf_from_remote_memory (GElf_Addr ehdr_vma, 346da0c48c4Sopenharmony_ci GElf_Xword pagesize, 347da0c48c4Sopenharmony_ci GElf_Addr *loadbasep, 348da0c48c4Sopenharmony_ci ssize_t (*read_memory) (void *arg, 349da0c48c4Sopenharmony_ci void *data, 350da0c48c4Sopenharmony_ci GElf_Addr address, 351da0c48c4Sopenharmony_ci size_t minread, 352da0c48c4Sopenharmony_ci size_t maxread), 353da0c48c4Sopenharmony_ci void *arg); 354da0c48c4Sopenharmony_ci 355da0c48c4Sopenharmony_ci 356da0c48c4Sopenharmony_ci/* Dwfl_Callbacks.find_elf */ 357da0c48c4Sopenharmony_ci 358da0c48c4Sopenharmony_ciint 359da0c48c4Sopenharmony_cidwfl_linux_proc_find_elf (Dwfl_Module *mod __attribute__ ((unused)), 360da0c48c4Sopenharmony_ci void **userdata __attribute__ ((unused)), 361da0c48c4Sopenharmony_ci const char *module_name, Dwarf_Addr base, 362da0c48c4Sopenharmony_ci char **file_name, Elf **elfp) 363da0c48c4Sopenharmony_ci{ 364da0c48c4Sopenharmony_ci int pid = -1; 365da0c48c4Sopenharmony_ci if (module_name[0] == '/') 366da0c48c4Sopenharmony_ci { 367da0c48c4Sopenharmony_ci /* When this callback is used together with dwfl_linux_proc_report 368da0c48c4Sopenharmony_ci then we might see mappings of special character devices. Make 369da0c48c4Sopenharmony_ci sure we only open and return regular files. Special devices 370da0c48c4Sopenharmony_ci might hang on open or read. (deleted) files are super special. 371da0c48c4Sopenharmony_ci The image might come from memory if we are attached. */ 372da0c48c4Sopenharmony_ci struct stat sb; 373da0c48c4Sopenharmony_ci if (stat (module_name, &sb) == -1 || (sb.st_mode & S_IFMT) != S_IFREG) 374da0c48c4Sopenharmony_ci { 375da0c48c4Sopenharmony_ci if (strcmp (strrchr (module_name, ' ') ?: "", " (deleted)") == 0) 376da0c48c4Sopenharmony_ci pid = INTUSE(dwfl_pid) (mod->dwfl); 377da0c48c4Sopenharmony_ci else 378da0c48c4Sopenharmony_ci return -1; 379da0c48c4Sopenharmony_ci } 380da0c48c4Sopenharmony_ci 381da0c48c4Sopenharmony_ci if (pid == -1) 382da0c48c4Sopenharmony_ci { 383da0c48c4Sopenharmony_ci int fd = open (module_name, O_RDONLY); 384da0c48c4Sopenharmony_ci if (fd >= 0) 385da0c48c4Sopenharmony_ci { 386da0c48c4Sopenharmony_ci *file_name = strdup (module_name); 387da0c48c4Sopenharmony_ci if (*file_name == NULL) 388da0c48c4Sopenharmony_ci { 389da0c48c4Sopenharmony_ci close (fd); 390da0c48c4Sopenharmony_ci return ENOMEM; 391da0c48c4Sopenharmony_ci } 392da0c48c4Sopenharmony_ci } 393da0c48c4Sopenharmony_ci return fd; 394da0c48c4Sopenharmony_ci } 395da0c48c4Sopenharmony_ci } 396da0c48c4Sopenharmony_ci 397da0c48c4Sopenharmony_ci if (pid != -1 || sscanf (module_name, "[vdso: %d]", &pid) == 1) 398da0c48c4Sopenharmony_ci { 399da0c48c4Sopenharmony_ci /* Special case for in-memory ELF image. */ 400da0c48c4Sopenharmony_ci 401da0c48c4Sopenharmony_ci bool detach = false; 402da0c48c4Sopenharmony_ci bool tid_was_stopped = false; 403da0c48c4Sopenharmony_ci struct __libdwfl_pid_arg *pid_arg = __libdwfl_get_pid_arg (mod->dwfl); 404da0c48c4Sopenharmony_ci if (pid_arg != NULL && ! pid_arg->assume_ptrace_stopped) 405da0c48c4Sopenharmony_ci { 406da0c48c4Sopenharmony_ci /* If any thread is already attached we are fine. Read 407da0c48c4Sopenharmony_ci through that thread. It doesn't have to be the main 408da0c48c4Sopenharmony_ci thread pid. */ 409da0c48c4Sopenharmony_ci pid_t tid = pid_arg->tid_attached; 410da0c48c4Sopenharmony_ci if (tid != 0) 411da0c48c4Sopenharmony_ci pid = tid; 412da0c48c4Sopenharmony_ci else 413da0c48c4Sopenharmony_ci detach = __libdwfl_ptrace_attach (pid, &tid_was_stopped); 414da0c48c4Sopenharmony_ci } 415da0c48c4Sopenharmony_ci 416da0c48c4Sopenharmony_ci char *fname; 417da0c48c4Sopenharmony_ci if (asprintf (&fname, PROCMEMFMT, pid) < 0) 418da0c48c4Sopenharmony_ci goto detach; 419da0c48c4Sopenharmony_ci 420da0c48c4Sopenharmony_ci int fd = open (fname, O_RDONLY); 421da0c48c4Sopenharmony_ci free (fname); 422da0c48c4Sopenharmony_ci if (fd < 0) 423da0c48c4Sopenharmony_ci goto detach; 424da0c48c4Sopenharmony_ci 425da0c48c4Sopenharmony_ci *elfp = elf_from_remote_memory (base, sysconf (_SC_PAGESIZE), NULL, 426da0c48c4Sopenharmony_ci &read_proc_memory, &fd); 427da0c48c4Sopenharmony_ci 428da0c48c4Sopenharmony_ci close (fd); 429da0c48c4Sopenharmony_ci 430da0c48c4Sopenharmony_ci *file_name = NULL; 431da0c48c4Sopenharmony_ci 432da0c48c4Sopenharmony_ci detach: 433da0c48c4Sopenharmony_ci if (detach) 434da0c48c4Sopenharmony_ci __libdwfl_ptrace_detach (pid, tid_was_stopped); 435da0c48c4Sopenharmony_ci return -1; 436da0c48c4Sopenharmony_ci } 437da0c48c4Sopenharmony_ci 438da0c48c4Sopenharmony_ci return -1; 439da0c48c4Sopenharmony_ci} 440da0c48c4Sopenharmony_ciINTDEF (dwfl_linux_proc_find_elf) 441