linux/tools/perf/util/probe-finder.c
<<
>>
Prefs
   1/*
   2 * probe-finder.c : C expression to kprobe event converter
   3 *
   4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19 *
  20 */
  21
  22#include <sys/utsname.h>
  23#include <sys/types.h>
  24#include <sys/stat.h>
  25#include <fcntl.h>
  26#include <errno.h>
  27#include <stdio.h>
  28#include <unistd.h>
  29#include <getopt.h>
  30#include <stdlib.h>
  31#include <string.h>
  32#include <stdarg.h>
  33#include <ctype.h>
  34#include <dwarf-regs.h>
  35
  36#include <linux/bitops.h>
  37#include "event.h"
  38#include "debug.h"
  39#include "util.h"
  40#include "symbol.h"
  41#include "probe-finder.h"
  42
  43/* Kprobe tracer basic type is up to u64 */
  44#define MAX_BASIC_TYPE_BITS     64
  45
  46/* Line number list operations */
  47
  48/* Add a line to line number list */
  49static int line_list__add_line(struct list_head *head, int line)
  50{
  51        struct line_node *ln;
  52        struct list_head *p;
  53
  54        /* Reverse search, because new line will be the last one */
  55        list_for_each_entry_reverse(ln, head, list) {
  56                if (ln->line < line) {
  57                        p = &ln->list;
  58                        goto found;
  59                } else if (ln->line == line)    /* Already exist */
  60                        return 1;
  61        }
  62        /* List is empty, or the smallest entry */
  63        p = head;
  64found:
  65        pr_debug("line list: add a line %u\n", line);
  66        ln = zalloc(sizeof(struct line_node));
  67        if (ln == NULL)
  68                return -ENOMEM;
  69        ln->line = line;
  70        INIT_LIST_HEAD(&ln->list);
  71        list_add(&ln->list, p);
  72        return 0;
  73}
  74
  75/* Check if the line in line number list */
  76static int line_list__has_line(struct list_head *head, int line)
  77{
  78        struct line_node *ln;
  79
  80        /* Reverse search, because new line will be the last one */
  81        list_for_each_entry(ln, head, list)
  82                if (ln->line == line)
  83                        return 1;
  84
  85        return 0;
  86}
  87
  88/* Init line number list */
  89static void line_list__init(struct list_head *head)
  90{
  91        INIT_LIST_HEAD(head);
  92}
  93
  94/* Free line number list */
  95static void line_list__free(struct list_head *head)
  96{
  97        struct line_node *ln;
  98        while (!list_empty(head)) {
  99                ln = list_first_entry(head, struct line_node, list);
 100                list_del(&ln->list);
 101                free(ln);
 102        }
 103}
 104
 105/* Dwarf FL wrappers */
 106static char *debuginfo_path;    /* Currently dummy */
 107
 108static const Dwfl_Callbacks offline_callbacks = {
 109        .find_debuginfo = dwfl_standard_find_debuginfo,
 110        .debuginfo_path = &debuginfo_path,
 111
 112        .section_address = dwfl_offline_section_address,
 113
 114        /* We use this table for core files too.  */
 115        .find_elf = dwfl_build_id_find_elf,
 116};
 117
 118/* Get a Dwarf from offline image */
 119static int debuginfo__init_offline_dwarf(struct debuginfo *self,
 120                                         const char *path)
 121{
 122        Dwfl_Module *mod;
 123        int fd;
 124
 125        fd = open(path, O_RDONLY);
 126        if (fd < 0)
 127                return fd;
 128
 129        self->dwfl = dwfl_begin(&offline_callbacks);
 130        if (!self->dwfl)
 131                goto error;
 132
 133        mod = dwfl_report_offline(self->dwfl, "", "", fd);
 134        if (!mod)
 135                goto error;
 136
 137        self->dbg = dwfl_module_getdwarf(mod, &self->bias);
 138        if (!self->dbg)
 139                goto error;
 140
 141        return 0;
 142error:
 143        if (self->dwfl)
 144                dwfl_end(self->dwfl);
 145        else
 146                close(fd);
 147        memset(self, 0, sizeof(*self));
 148
 149        return -ENOENT;
 150}
 151
 152#if _ELFUTILS_PREREQ(0, 148)
 153/* This method is buggy if elfutils is older than 0.148 */
 154static int __linux_kernel_find_elf(Dwfl_Module *mod,
 155                                   void **userdata,
 156                                   const char *module_name,
 157                                   Dwarf_Addr base,
 158                                   char **file_name, Elf **elfp)
 159{
 160        int fd;
 161        const char *path = kernel_get_module_path(module_name);
 162
 163        pr_debug2("Use file %s for %s\n", path, module_name);
 164        if (path) {
 165                fd = open(path, O_RDONLY);
 166                if (fd >= 0) {
 167                        *file_name = strdup(path);
 168                        return fd;
 169                }
 170        }
 171        /* If failed, try to call standard method */
 172        return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
 173                                          file_name, elfp);
 174}
 175
 176static const Dwfl_Callbacks kernel_callbacks = {
 177        .find_debuginfo = dwfl_standard_find_debuginfo,
 178        .debuginfo_path = &debuginfo_path,
 179
 180        .find_elf = __linux_kernel_find_elf,
 181        .section_address = dwfl_linux_kernel_module_section_address,
 182};
 183
 184/* Get a Dwarf from live kernel image */
 185static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
 186                                               Dwarf_Addr addr)
 187{
 188        self->dwfl = dwfl_begin(&kernel_callbacks);
 189        if (!self->dwfl)
 190                return -EINVAL;
 191
 192        /* Load the kernel dwarves: Don't care the result here */
 193        dwfl_linux_kernel_report_kernel(self->dwfl);
 194        dwfl_linux_kernel_report_modules(self->dwfl);
 195
 196        self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias);
 197        /* Here, check whether we could get a real dwarf */
 198        if (!self->dbg) {
 199                pr_debug("Failed to find kernel dwarf at %lx\n",
 200                         (unsigned long)addr);
 201                dwfl_end(self->dwfl);
 202                memset(self, 0, sizeof(*self));
 203                return -ENOENT;
 204        }
 205
 206        return 0;
 207}
 208#else
 209/* With older elfutils, this just support kernel module... */
 210static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
 211                                               Dwarf_Addr addr __used)
 212{
 213        const char *path = kernel_get_module_path("kernel");
 214
 215        if (!path) {
 216                pr_err("Failed to find vmlinux path\n");
 217                return -ENOENT;
 218        }
 219
 220        pr_debug2("Use file %s for debuginfo\n", path);
 221        return debuginfo__init_offline_dwarf(self, path);
 222}
 223#endif
 224
 225struct debuginfo *debuginfo__new(const char *path)
 226{
 227        struct debuginfo *self = zalloc(sizeof(struct debuginfo));
 228        if (!self)
 229                return NULL;
 230
 231        if (debuginfo__init_offline_dwarf(self, path) < 0) {
 232                free(self);
 233                self = NULL;
 234        }
 235
 236        return self;
 237}
 238
 239struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
 240{
 241        struct debuginfo *self = zalloc(sizeof(struct debuginfo));
 242        if (!self)
 243                return NULL;
 244
 245        if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) {
 246                free(self);
 247                self = NULL;
 248        }
 249
 250        return self;
 251}
 252
 253void debuginfo__delete(struct debuginfo *self)
 254{
 255        if (self) {
 256                if (self->dwfl)
 257                        dwfl_end(self->dwfl);
 258                free(self);
 259        }
 260}
 261
 262/*
 263 * Probe finder related functions
 264 */
 265
 266static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
 267{
 268        struct probe_trace_arg_ref *ref;
 269        ref = zalloc(sizeof(struct probe_trace_arg_ref));
 270        if (ref != NULL)
 271                ref->offset = offs;
 272        return ref;
 273}
 274
 275/*
 276 * Convert a location into trace_arg.
 277 * If tvar == NULL, this just checks variable can be converted.
 278 */
 279static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
 280                                     Dwarf_Op *fb_ops,
 281                                     struct probe_trace_arg *tvar)
 282{
 283        Dwarf_Attribute attr;
 284        Dwarf_Op *op;
 285        size_t nops;
 286        unsigned int regn;
 287        Dwarf_Word offs = 0;
 288        bool ref = false;
 289        const char *regs;
 290        int ret;
 291
 292        if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
 293                goto static_var;
 294
 295        /* TODO: handle more than 1 exprs */
 296        if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
 297            dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
 298            nops == 0) {
 299                /* TODO: Support const_value */
 300                return -ENOENT;
 301        }
 302
 303        if (op->atom == DW_OP_addr) {
 304static_var:
 305                if (!tvar)
 306                        return 0;
 307                /* Static variables on memory (not stack), make @varname */
 308                ret = strlen(dwarf_diename(vr_die));
 309                tvar->value = zalloc(ret + 2);
 310                if (tvar->value == NULL)
 311                        return -ENOMEM;
 312                snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
 313                tvar->ref = alloc_trace_arg_ref((long)offs);
 314                if (tvar->ref == NULL)
 315                        return -ENOMEM;
 316                return 0;
 317        }
 318
 319        /* If this is based on frame buffer, set the offset */
 320        if (op->atom == DW_OP_fbreg) {
 321                if (fb_ops == NULL)
 322                        return -ENOTSUP;
 323                ref = true;
 324                offs = op->number;
 325                op = &fb_ops[0];
 326        }
 327
 328        if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
 329                regn = op->atom - DW_OP_breg0;
 330                offs += op->number;
 331                ref = true;
 332        } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
 333                regn = op->atom - DW_OP_reg0;
 334        } else if (op->atom == DW_OP_bregx) {
 335                regn = op->number;
 336                offs += op->number2;
 337                ref = true;
 338        } else if (op->atom == DW_OP_regx) {
 339                regn = op->number;
 340        } else {
 341                pr_debug("DW_OP %x is not supported.\n", op->atom);
 342                return -ENOTSUP;
 343        }
 344
 345        if (!tvar)
 346                return 0;
 347
 348        regs = get_arch_regstr(regn);
 349        if (!regs) {
 350                /* This should be a bug in DWARF or this tool */
 351                pr_warning("Mapping for the register number %u "
 352                           "missing on this architecture.\n", regn);
 353                return -ERANGE;
 354        }
 355
 356        tvar->value = strdup(regs);
 357        if (tvar->value == NULL)
 358                return -ENOMEM;
 359
 360        if (ref) {
 361                tvar->ref = alloc_trace_arg_ref((long)offs);
 362                if (tvar->ref == NULL)
 363                        return -ENOMEM;
 364        }
 365        return 0;
 366}
 367
 368#define BYTES_TO_BITS(nb)       ((nb) * BITS_PER_LONG / sizeof(long))
 369
 370static int convert_variable_type(Dwarf_Die *vr_die,
 371                                 struct probe_trace_arg *tvar,
 372                                 const char *cast)
 373{
 374        struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
 375        Dwarf_Die type;
 376        char buf[16];
 377        int bsize, boffs, total;
 378        int ret;
 379
 380        /* TODO: check all types */
 381        if (cast && strcmp(cast, "string") != 0) {
 382                /* Non string type is OK */
 383                tvar->type = strdup(cast);
 384                return (tvar->type == NULL) ? -ENOMEM : 0;
 385        }
 386
 387        bsize = dwarf_bitsize(vr_die);
 388        if (bsize > 0) {
 389                /* This is a bitfield */
 390                boffs = dwarf_bitoffset(vr_die);
 391                total = dwarf_bytesize(vr_die);
 392                if (boffs < 0 || total < 0)
 393                        return -ENOENT;
 394                ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs,
 395                                BYTES_TO_BITS(total));
 396                goto formatted;
 397        }
 398
 399        if (die_get_real_type(vr_die, &type) == NULL) {
 400                pr_warning("Failed to get a type information of %s.\n",
 401                           dwarf_diename(vr_die));
 402                return -ENOENT;
 403        }
 404
 405        pr_debug("%s type is %s.\n",
 406                 dwarf_diename(vr_die), dwarf_diename(&type));
 407
 408        if (cast && strcmp(cast, "string") == 0) {      /* String type */
 409                ret = dwarf_tag(&type);
 410                if (ret != DW_TAG_pointer_type &&
 411                    ret != DW_TAG_array_type) {
 412                        pr_warning("Failed to cast into string: "
 413                                   "%s(%s) is not a pointer nor array.\n",
 414                                   dwarf_diename(vr_die), dwarf_diename(&type));
 415                        return -EINVAL;
 416                }
 417                if (ret == DW_TAG_pointer_type) {
 418                        if (die_get_real_type(&type, &type) == NULL) {
 419                                pr_warning("Failed to get a type"
 420                                           " information.\n");
 421                                return -ENOENT;
 422                        }
 423                        while (*ref_ptr)
 424                                ref_ptr = &(*ref_ptr)->next;
 425                        /* Add new reference with offset +0 */
 426                        *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
 427                        if (*ref_ptr == NULL) {
 428                                pr_warning("Out of memory error\n");
 429                                return -ENOMEM;
 430                        }
 431                }
 432                if (!die_compare_name(&type, "char") &&
 433                    !die_compare_name(&type, "unsigned char")) {
 434                        pr_warning("Failed to cast into string: "
 435                                   "%s is not (unsigned) char *.\n",
 436                                   dwarf_diename(vr_die));
 437                        return -EINVAL;
 438                }
 439                tvar->type = strdup(cast);
 440                return (tvar->type == NULL) ? -ENOMEM : 0;
 441        }
 442
 443        ret = dwarf_bytesize(&type);
 444        if (ret <= 0)
 445                /* No size ... try to use default type */
 446                return 0;
 447        ret = BYTES_TO_BITS(ret);
 448
 449        /* Check the bitwidth */
 450        if (ret > MAX_BASIC_TYPE_BITS) {
 451                pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n",
 452                        dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
 453                ret = MAX_BASIC_TYPE_BITS;
 454        }
 455        ret = snprintf(buf, 16, "%c%d",
 456                       die_is_signed_type(&type) ? 's' : 'u', ret);
 457
 458formatted:
 459        if (ret < 0 || ret >= 16) {
 460                if (ret >= 16)
 461                        ret = -E2BIG;
 462                pr_warning("Failed to convert variable type: %s\n",
 463                           strerror(-ret));
 464                return ret;
 465        }
 466        tvar->type = strdup(buf);
 467        if (tvar->type == NULL)
 468                return -ENOMEM;
 469        return 0;
 470}
 471
 472static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
 473                                    struct perf_probe_arg_field *field,
 474                                    struct probe_trace_arg_ref **ref_ptr,
 475                                    Dwarf_Die *die_mem)
 476{
 477        struct probe_trace_arg_ref *ref = *ref_ptr;
 478        Dwarf_Die type;
 479        Dwarf_Word offs;
 480        int ret, tag;
 481
 482        pr_debug("converting %s in %s\n", field->name, varname);
 483        if (die_get_real_type(vr_die, &type) == NULL) {
 484                pr_warning("Failed to get the type of %s.\n", varname);
 485                return -ENOENT;
 486        }
 487        pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
 488        tag = dwarf_tag(&type);
 489
 490        if (field->name[0] == '[' &&
 491            (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
 492                if (field->next)
 493                        /* Save original type for next field */
 494                        memcpy(die_mem, &type, sizeof(*die_mem));
 495                /* Get the type of this array */
 496                if (die_get_real_type(&type, &type) == NULL) {
 497                        pr_warning("Failed to get the type of %s.\n", varname);
 498                        return -ENOENT;
 499                }
 500                pr_debug2("Array real type: (%x)\n",
 501                         (unsigned)dwarf_dieoffset(&type));
 502                if (tag == DW_TAG_pointer_type) {
 503                        ref = zalloc(sizeof(struct probe_trace_arg_ref));
 504                        if (ref == NULL)
 505                                return -ENOMEM;
 506                        if (*ref_ptr)
 507                                (*ref_ptr)->next = ref;
 508                        else
 509                                *ref_ptr = ref;
 510                }
 511                ref->offset += dwarf_bytesize(&type) * field->index;
 512                if (!field->next)
 513                        /* Save vr_die for converting types */
 514                        memcpy(die_mem, vr_die, sizeof(*die_mem));
 515                goto next;
 516        } else if (tag == DW_TAG_pointer_type) {
 517                /* Check the pointer and dereference */
 518                if (!field->ref) {
 519                        pr_err("Semantic error: %s must be referred by '->'\n",
 520                               field->name);
 521                        return -EINVAL;
 522                }
 523                /* Get the type pointed by this pointer */
 524                if (die_get_real_type(&type, &type) == NULL) {
 525                        pr_warning("Failed to get the type of %s.\n", varname);
 526                        return -ENOENT;
 527                }
 528                /* Verify it is a data structure  */
 529                if (dwarf_tag(&type) != DW_TAG_structure_type) {
 530                        pr_warning("%s is not a data structure.\n", varname);
 531                        return -EINVAL;
 532                }
 533
 534                ref = zalloc(sizeof(struct probe_trace_arg_ref));
 535                if (ref == NULL)
 536                        return -ENOMEM;
 537                if (*ref_ptr)
 538                        (*ref_ptr)->next = ref;
 539                else
 540                        *ref_ptr = ref;
 541        } else {
 542                /* Verify it is a data structure  */
 543                if (tag != DW_TAG_structure_type) {
 544                        pr_warning("%s is not a data structure.\n", varname);
 545                        return -EINVAL;
 546                }
 547                if (field->name[0] == '[') {
 548                        pr_err("Semantic error: %s is not a pointor"
 549                               " nor array.\n", varname);
 550                        return -EINVAL;
 551                }
 552                if (field->ref) {
 553                        pr_err("Semantic error: %s must be referred by '.'\n",
 554                               field->name);
 555                        return -EINVAL;
 556                }
 557                if (!ref) {
 558                        pr_warning("Structure on a register is not "
 559                                   "supported yet.\n");
 560                        return -ENOTSUP;
 561                }
 562        }
 563
 564        if (die_find_member(&type, field->name, die_mem) == NULL) {
 565                pr_warning("%s(tyep:%s) has no member %s.\n", varname,
 566                           dwarf_diename(&type), field->name);
 567                return -EINVAL;
 568        }
 569
 570        /* Get the offset of the field */
 571        ret = die_get_data_member_location(die_mem, &offs);
 572        if (ret < 0) {
 573                pr_warning("Failed to get the offset of %s.\n", field->name);
 574                return ret;
 575        }
 576        ref->offset += (long)offs;
 577
 578next:
 579        /* Converting next field */
 580        if (field->next)
 581                return convert_variable_fields(die_mem, field->name,
 582                                        field->next, &ref, die_mem);
 583        else
 584                return 0;
 585}
 586
 587/* Show a variables in kprobe event format */
 588static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 589{
 590        Dwarf_Die die_mem;
 591        int ret;
 592
 593        pr_debug("Converting variable %s into trace event.\n",
 594                 dwarf_diename(vr_die));
 595
 596        ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
 597                                        pf->tvar);
 598        if (ret == -ENOENT)
 599                pr_err("Failed to find the location of %s at this address.\n"
 600                       " Perhaps, it has been optimized out.\n", pf->pvar->var);
 601        else if (ret == -ENOTSUP)
 602                pr_err("Sorry, we don't support this variable location yet.\n");
 603        else if (pf->pvar->field) {
 604                ret = convert_variable_fields(vr_die, pf->pvar->var,
 605                                              pf->pvar->field, &pf->tvar->ref,
 606                                              &die_mem);
 607                vr_die = &die_mem;
 608        }
 609        if (ret == 0)
 610                ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
 611        /* *expr will be cached in libdw. Don't free it. */
 612        return ret;
 613}
 614
 615/* Find a variable in a scope DIE */
 616static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
 617{
 618        Dwarf_Die vr_die;
 619        char buf[32], *ptr;
 620        int ret = 0;
 621
 622        if (!is_c_varname(pf->pvar->var)) {
 623                /* Copy raw parameters */
 624                pf->tvar->value = strdup(pf->pvar->var);
 625                if (pf->tvar->value == NULL)
 626                        return -ENOMEM;
 627                if (pf->pvar->type) {
 628                        pf->tvar->type = strdup(pf->pvar->type);
 629                        if (pf->tvar->type == NULL)
 630                                return -ENOMEM;
 631                }
 632                if (pf->pvar->name) {
 633                        pf->tvar->name = strdup(pf->pvar->name);
 634                        if (pf->tvar->name == NULL)
 635                                return -ENOMEM;
 636                } else
 637                        pf->tvar->name = NULL;
 638                return 0;
 639        }
 640
 641        if (pf->pvar->name)
 642                pf->tvar->name = strdup(pf->pvar->name);
 643        else {
 644                ret = synthesize_perf_probe_arg(pf->pvar, buf, 32);
 645                if (ret < 0)
 646                        return ret;
 647                ptr = strchr(buf, ':'); /* Change type separator to _ */
 648                if (ptr)
 649                        *ptr = '_';
 650                pf->tvar->name = strdup(buf);
 651        }
 652        if (pf->tvar->name == NULL)
 653                return -ENOMEM;
 654
 655        pr_debug("Searching '%s' variable in context.\n", pf->pvar->var);
 656        /* Search child die for local variables and parameters. */
 657        if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
 658                /* Search again in global variables */
 659                if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
 660                        ret = -ENOENT;
 661        }
 662        if (ret >= 0)
 663                ret = convert_variable(&vr_die, pf);
 664
 665        if (ret < 0)
 666                pr_warning("Failed to find '%s' in this function.\n",
 667                           pf->pvar->var);
 668        return ret;
 669}
 670
 671/* Convert subprogram DIE to trace point */
 672static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
 673                                  bool retprobe, struct probe_trace_point *tp)
 674{
 675        Dwarf_Addr eaddr;
 676        const char *name;
 677
 678        /* Copy the name of probe point */
 679        name = dwarf_diename(sp_die);
 680        if (name) {
 681                if (dwarf_entrypc(sp_die, &eaddr) != 0) {
 682                        pr_warning("Failed to get entry address of %s\n",
 683                                   dwarf_diename(sp_die));
 684                        return -ENOENT;
 685                }
 686                tp->symbol = strdup(name);
 687                if (tp->symbol == NULL)
 688                        return -ENOMEM;
 689                tp->offset = (unsigned long)(paddr - eaddr);
 690        } else
 691                /* This function has no name. */
 692                tp->offset = (unsigned long)paddr;
 693
 694        /* Return probe must be on the head of a subprogram */
 695        if (retprobe) {
 696                if (eaddr != paddr) {
 697                        pr_warning("Return probe must be on the head of"
 698                                   " a real function.\n");
 699                        return -EINVAL;
 700                }
 701                tp->retprobe = true;
 702        }
 703
 704        return 0;
 705}
 706
 707/* Call probe_finder callback with scope DIE */
 708static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
 709{
 710        Dwarf_Attribute fb_attr;
 711        size_t nops;
 712        int ret;
 713
 714        if (!sc_die) {
 715                pr_err("Caller must pass a scope DIE. Program error.\n");
 716                return -EINVAL;
 717        }
 718
 719        /* If not a real subprogram, find a real one */
 720        if (dwarf_tag(sc_die) != DW_TAG_subprogram) {
 721                if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
 722                        pr_warning("Failed to find probe point in any "
 723                                   "functions.\n");
 724                        return -ENOENT;
 725                }
 726        } else
 727                memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die));
 728
 729        /* Get the frame base attribute/ops from subprogram */
 730        dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr);
 731        ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
 732        if (ret <= 0 || nops == 0) {
 733                pf->fb_ops = NULL;
 734#if _ELFUTILS_PREREQ(0, 142)
 735        } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
 736                   pf->cfi != NULL) {
 737                Dwarf_Frame *frame;
 738                if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
 739                    dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
 740                        pr_warning("Failed to get call frame on 0x%jx\n",
 741                                   (uintmax_t)pf->addr);
 742                        return -ENOENT;
 743                }
 744#endif
 745        }
 746
 747        /* Call finder's callback handler */
 748        ret = pf->callback(sc_die, pf);
 749
 750        /* *pf->fb_ops will be cached in libdw. Don't free it. */
 751        pf->fb_ops = NULL;
 752
 753        return ret;
 754}
 755
 756struct find_scope_param {
 757        const char *function;
 758        const char *file;
 759        int line;
 760        int diff;
 761        Dwarf_Die *die_mem;
 762        bool found;
 763};
 764
 765static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
 766{
 767        struct find_scope_param *fsp = data;
 768        const char *file;
 769        int lno;
 770
 771        /* Skip if declared file name does not match */
 772        if (fsp->file) {
 773                file = dwarf_decl_file(fn_die);
 774                if (!file || strcmp(fsp->file, file) != 0)
 775                        return 0;
 776        }
 777        /* If the function name is given, that's what user expects */
 778        if (fsp->function) {
 779                if (die_compare_name(fn_die, fsp->function)) {
 780                        memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
 781                        fsp->found = true;
 782                        return 1;
 783                }
 784        } else {
 785                /* With the line number, find the nearest declared DIE */
 786                dwarf_decl_line(fn_die, &lno);
 787                if (lno < fsp->line && fsp->diff > fsp->line - lno) {
 788                        /* Keep a candidate and continue */
 789                        fsp->diff = fsp->line - lno;
 790                        memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
 791                        fsp->found = true;
 792                }
 793        }
 794        return 0;
 795}
 796
 797/* Find an appropriate scope fits to given conditions */
 798static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
 799{
 800        struct find_scope_param fsp = {
 801                .function = pf->pev->point.function,
 802                .file = pf->fname,
 803                .line = pf->lno,
 804                .diff = INT_MAX,
 805                .die_mem = die_mem,
 806                .found = false,
 807        };
 808
 809        cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp);
 810
 811        return fsp.found ? die_mem : NULL;
 812}
 813
 814static int probe_point_line_walker(const char *fname, int lineno,
 815                                   Dwarf_Addr addr, void *data)
 816{
 817        struct probe_finder *pf = data;
 818        Dwarf_Die *sc_die, die_mem;
 819        int ret;
 820
 821        if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
 822                return 0;
 823
 824        pf->addr = addr;
 825        sc_die = find_best_scope(pf, &die_mem);
 826        if (!sc_die) {
 827                pr_warning("Failed to find scope of probe point.\n");
 828                return -ENOENT;
 829        }
 830
 831        ret = call_probe_finder(sc_die, pf);
 832
 833        /* Continue if no error, because the line will be in inline function */
 834        return ret < 0 ? ret : 0;
 835}
 836
 837/* Find probe point from its line number */
 838static int find_probe_point_by_line(struct probe_finder *pf)
 839{
 840        return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
 841}
 842
 843/* Find lines which match lazy pattern */
 844static int find_lazy_match_lines(struct list_head *head,
 845                                 const char *fname, const char *pat)
 846{
 847        FILE *fp;
 848        char *line = NULL;
 849        size_t line_len;
 850        ssize_t len;
 851        int count = 0, linenum = 1;
 852
 853        fp = fopen(fname, "r");
 854        if (!fp) {
 855                pr_warning("Failed to open %s: %s\n", fname, strerror(errno));
 856                return -errno;
 857        }
 858
 859        while ((len = getline(&line, &line_len, fp)) > 0) {
 860
 861                if (line[len - 1] == '\n')
 862                        line[len - 1] = '\0';
 863
 864                if (strlazymatch(line, pat)) {
 865                        line_list__add_line(head, linenum);
 866                        count++;
 867                }
 868                linenum++;
 869        }
 870
 871        if (ferror(fp))
 872                count = -errno;
 873        free(line);
 874        fclose(fp);
 875
 876        if (count == 0)
 877                pr_debug("No matched lines found in %s.\n", fname);
 878        return count;
 879}
 880
 881static int probe_point_lazy_walker(const char *fname, int lineno,
 882                                   Dwarf_Addr addr, void *data)
 883{
 884        struct probe_finder *pf = data;
 885        Dwarf_Die *sc_die, die_mem;
 886        int ret;
 887
 888        if (!line_list__has_line(&pf->lcache, lineno) ||
 889            strtailcmp(fname, pf->fname) != 0)
 890                return 0;
 891
 892        pr_debug("Probe line found: line:%d addr:0x%llx\n",
 893                 lineno, (unsigned long long)addr);
 894        pf->addr = addr;
 895        pf->lno = lineno;
 896        sc_die = find_best_scope(pf, &die_mem);
 897        if (!sc_die) {
 898                pr_warning("Failed to find scope of probe point.\n");
 899                return -ENOENT;
 900        }
 901
 902        ret = call_probe_finder(sc_die, pf);
 903
 904        /*
 905         * Continue if no error, because the lazy pattern will match
 906         * to other lines
 907         */
 908        return ret < 0 ? ret : 0;
 909}
 910
 911/* Find probe points from lazy pattern  */
 912static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 913{
 914        int ret = 0;
 915
 916        if (list_empty(&pf->lcache)) {
 917                /* Matching lazy line pattern */
 918                ret = find_lazy_match_lines(&pf->lcache, pf->fname,
 919                                            pf->pev->point.lazy_line);
 920                if (ret <= 0)
 921                        return ret;
 922        }
 923
 924        return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
 925}
 926
 927static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 928{
 929        struct probe_finder *pf = data;
 930        struct perf_probe_point *pp = &pf->pev->point;
 931        Dwarf_Addr addr;
 932        int ret;
 933
 934        if (pp->lazy_line)
 935                ret = find_probe_point_lazy(in_die, pf);
 936        else {
 937                /* Get probe address */
 938                if (dwarf_entrypc(in_die, &addr) != 0) {
 939                        pr_warning("Failed to get entry address of %s.\n",
 940                                   dwarf_diename(in_die));
 941                        return -ENOENT;
 942                }
 943                pf->addr = addr;
 944                pf->addr += pp->offset;
 945                pr_debug("found inline addr: 0x%jx\n",
 946                         (uintmax_t)pf->addr);
 947
 948                ret = call_probe_finder(in_die, pf);
 949        }
 950
 951        return ret;
 952}
 953
 954/* Callback parameter with return value for libdw */
 955struct dwarf_callback_param {
 956        void *data;
 957        int retval;
 958};
 959
 960/* Search function from function name */
 961static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 962{
 963        struct dwarf_callback_param *param = data;
 964        struct probe_finder *pf = param->data;
 965        struct perf_probe_point *pp = &pf->pev->point;
 966
 967        /* Check tag and diename */
 968        if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
 969            !die_compare_name(sp_die, pp->function))
 970                return DWARF_CB_OK;
 971
 972        /* Check declared file */
 973        if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die)))
 974                return DWARF_CB_OK;
 975
 976        pf->fname = dwarf_decl_file(sp_die);
 977        if (pp->line) { /* Function relative line */
 978                dwarf_decl_line(sp_die, &pf->lno);
 979                pf->lno += pp->line;
 980                param->retval = find_probe_point_by_line(pf);
 981        } else if (!dwarf_func_inline(sp_die)) {
 982                /* Real function */
 983                if (pp->lazy_line)
 984                        param->retval = find_probe_point_lazy(sp_die, pf);
 985                else {
 986                        if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
 987                                pr_warning("Failed to get entry address of "
 988                                           "%s.\n", dwarf_diename(sp_die));
 989                                param->retval = -ENOENT;
 990                                return DWARF_CB_ABORT;
 991                        }
 992                        pf->addr += pp->offset;
 993                        /* TODO: Check the address in this function */
 994                        param->retval = call_probe_finder(sp_die, pf);
 995                }
 996        } else
 997                /* Inlined function: search instances */
 998                param->retval = die_walk_instances(sp_die,
 999                                        probe_point_inline_cb, (void *)pf);
1000
1001        return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
1002}
1003
1004static int find_probe_point_by_func(struct probe_finder *pf)
1005{
1006        struct dwarf_callback_param _param = {.data = (void *)pf,
1007                                              .retval = 0};
1008        dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0);
1009        return _param.retval;
1010}
1011
1012struct pubname_callback_param {
1013        char *function;
1014        char *file;
1015        Dwarf_Die *cu_die;
1016        Dwarf_Die *sp_die;
1017        int found;
1018};
1019
1020static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
1021{
1022        struct pubname_callback_param *param = data;
1023
1024        if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) {
1025                if (dwarf_tag(param->sp_die) != DW_TAG_subprogram)
1026                        return DWARF_CB_OK;
1027
1028                if (die_compare_name(param->sp_die, param->function)) {
1029                        if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die))
1030                                return DWARF_CB_OK;
1031
1032                        if (param->file &&
1033                            strtailcmp(param->file, dwarf_decl_file(param->sp_die)))
1034                                return DWARF_CB_OK;
1035
1036                        param->found = 1;
1037                        return DWARF_CB_ABORT;
1038                }
1039        }
1040
1041        return DWARF_CB_OK;
1042}
1043
1044/* Find probe points from debuginfo */
1045static int debuginfo__find_probes(struct debuginfo *self,
1046                                  struct probe_finder *pf)
1047{
1048        struct perf_probe_point *pp = &pf->pev->point;
1049        Dwarf_Off off, noff;
1050        size_t cuhl;
1051        Dwarf_Die *diep;
1052        int ret = 0;
1053
1054#if _ELFUTILS_PREREQ(0, 142)
1055        /* Get the call frame information from this dwarf */
1056        pf->cfi = dwarf_getcfi(self->dbg);
1057#endif
1058
1059        off = 0;
1060        line_list__init(&pf->lcache);
1061
1062        /* Fastpath: lookup by function name from .debug_pubnames section */
1063        if (pp->function) {
1064                struct pubname_callback_param pubname_param = {
1065                        .function = pp->function,
1066                        .file     = pp->file,
1067                        .cu_die   = &pf->cu_die,
1068                        .sp_die   = &pf->sp_die,
1069                        .found    = 0,
1070                };
1071                struct dwarf_callback_param probe_param = {
1072                        .data = pf,
1073                };
1074
1075                dwarf_getpubnames(self->dbg, pubname_search_cb,
1076                                  &pubname_param, 0);
1077                if (pubname_param.found) {
1078                        ret = probe_point_search_cb(&pf->sp_die, &probe_param);
1079                        if (ret)
1080                                goto found;
1081                }
1082        }
1083
1084        /* Loop on CUs (Compilation Unit) */
1085        while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
1086                /* Get the DIE(Debugging Information Entry) of this CU */
1087                diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die);
1088                if (!diep)
1089                        continue;
1090
1091                /* Check if target file is included. */
1092                if (pp->file)
1093                        pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
1094                else
1095                        pf->fname = NULL;
1096
1097                if (!pp->file || pf->fname) {
1098                        if (pp->function)
1099                                ret = find_probe_point_by_func(pf);
1100                        else if (pp->lazy_line)
1101                                ret = find_probe_point_lazy(NULL, pf);
1102                        else {
1103                                pf->lno = pp->line;
1104                                ret = find_probe_point_by_line(pf);
1105                        }
1106                        if (ret < 0)
1107                                break;
1108                }
1109                off = noff;
1110        }
1111
1112found:
1113        line_list__free(&pf->lcache);
1114
1115        return ret;
1116}
1117
1118/* Add a found probe point into trace event list */
1119static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1120{
1121        struct trace_event_finder *tf =
1122                        container_of(pf, struct trace_event_finder, pf);
1123        struct probe_trace_event *tev;
1124        int ret, i;
1125
1126        /* Check number of tevs */
1127        if (tf->ntevs == tf->max_tevs) {
1128                pr_warning("Too many( > %d) probe point found.\n",
1129                           tf->max_tevs);
1130                return -ERANGE;
1131        }
1132        tev = &tf->tevs[tf->ntevs++];
1133
1134        /* Trace point should be converted from subprogram DIE */
1135        ret = convert_to_trace_point(&pf->sp_die, pf->addr,
1136                                     pf->pev->point.retprobe, &tev->point);
1137        if (ret < 0)
1138                return ret;
1139
1140        pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1141                 tev->point.offset);
1142
1143        /* Find each argument */
1144        tev->nargs = pf->pev->nargs;
1145        tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1146        if (tev->args == NULL)
1147                return -ENOMEM;
1148        for (i = 0; i < pf->pev->nargs; i++) {
1149                pf->pvar = &pf->pev->args[i];
1150                pf->tvar = &tev->args[i];
1151                /* Variable should be found from scope DIE */
1152                ret = find_variable(sc_die, pf);
1153                if (ret != 0)
1154                        return ret;
1155        }
1156
1157        return 0;
1158}
1159
1160/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1161int debuginfo__find_trace_events(struct debuginfo *self,
1162                                 struct perf_probe_event *pev,
1163                                 struct probe_trace_event **tevs, int max_tevs)
1164{
1165        struct trace_event_finder tf = {
1166                        .pf = {.pev = pev, .callback = add_probe_trace_event},
1167                        .max_tevs = max_tevs};
1168        int ret;
1169
1170        /* Allocate result tevs array */
1171        *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
1172        if (*tevs == NULL)
1173                return -ENOMEM;
1174
1175        tf.tevs = *tevs;
1176        tf.ntevs = 0;
1177
1178        ret = debuginfo__find_probes(self, &tf.pf);
1179        if (ret < 0) {
1180                free(*tevs);
1181                *tevs = NULL;
1182                return ret;
1183        }
1184
1185        return (ret < 0) ? ret : tf.ntevs;
1186}
1187
1188#define MAX_VAR_LEN 64
1189
1190/* Collect available variables in this scope */
1191static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1192{
1193        struct available_var_finder *af = data;
1194        struct variable_list *vl;
1195        char buf[MAX_VAR_LEN];
1196        int tag, ret;
1197
1198        vl = &af->vls[af->nvls - 1];
1199
1200        tag = dwarf_tag(die_mem);
1201        if (tag == DW_TAG_formal_parameter ||
1202            tag == DW_TAG_variable) {
1203                ret = convert_variable_location(die_mem, af->pf.addr,
1204                                                af->pf.fb_ops, NULL);
1205                if (ret == 0) {
1206                        ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
1207                        pr_debug2("Add new var: %s\n", buf);
1208                        if (ret > 0)
1209                                strlist__add(vl->vars, buf);
1210                }
1211        }
1212
1213        if (af->child && dwarf_haspc(die_mem, af->pf.addr))
1214                return DIE_FIND_CB_CONTINUE;
1215        else
1216                return DIE_FIND_CB_SIBLING;
1217}
1218
1219/* Add a found vars into available variables list */
1220static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
1221{
1222        struct available_var_finder *af =
1223                        container_of(pf, struct available_var_finder, pf);
1224        struct variable_list *vl;
1225        Dwarf_Die die_mem;
1226        int ret;
1227
1228        /* Check number of tevs */
1229        if (af->nvls == af->max_vls) {
1230                pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
1231                return -ERANGE;
1232        }
1233        vl = &af->vls[af->nvls++];
1234
1235        /* Trace point should be converted from subprogram DIE */
1236        ret = convert_to_trace_point(&pf->sp_die, pf->addr,
1237                                     pf->pev->point.retprobe, &vl->point);
1238        if (ret < 0)
1239                return ret;
1240
1241        pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
1242                 vl->point.offset);
1243
1244        /* Find local variables */
1245        vl->vars = strlist__new(true, NULL);
1246        if (vl->vars == NULL)
1247                return -ENOMEM;
1248        af->child = true;
1249        die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem);
1250
1251        /* Find external variables */
1252        if (!af->externs)
1253                goto out;
1254        /* Don't need to search child DIE for externs. */
1255        af->child = false;
1256        die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem);
1257
1258out:
1259        if (strlist__empty(vl->vars)) {
1260                strlist__delete(vl->vars);
1261                vl->vars = NULL;
1262        }
1263
1264        return ret;
1265}
1266
1267/* Find available variables at given probe point */
1268int debuginfo__find_available_vars_at(struct debuginfo *self,
1269                                      struct perf_probe_event *pev,
1270                                      struct variable_list **vls,
1271                                      int max_vls, bool externs)
1272{
1273        struct available_var_finder af = {
1274                        .pf = {.pev = pev, .callback = add_available_vars},
1275                        .max_vls = max_vls, .externs = externs};
1276        int ret;
1277
1278        /* Allocate result vls array */
1279        *vls = zalloc(sizeof(struct variable_list) * max_vls);
1280        if (*vls == NULL)
1281                return -ENOMEM;
1282
1283        af.vls = *vls;
1284        af.nvls = 0;
1285
1286        ret = debuginfo__find_probes(self, &af.pf);
1287        if (ret < 0) {
1288                /* Free vlist for error */
1289                while (af.nvls--) {
1290                        if (af.vls[af.nvls].point.symbol)
1291                                free(af.vls[af.nvls].point.symbol);
1292                        if (af.vls[af.nvls].vars)
1293                                strlist__delete(af.vls[af.nvls].vars);
1294                }
1295                free(af.vls);
1296                *vls = NULL;
1297                return ret;
1298        }
1299
1300        return (ret < 0) ? ret : af.nvls;
1301}
1302
1303/* Reverse search */
1304int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
1305                                struct perf_probe_point *ppt)
1306{
1307        Dwarf_Die cudie, spdie, indie;
1308        Dwarf_Addr _addr, baseaddr;
1309        const char *fname = NULL, *func = NULL, *tmp;
1310        int baseline = 0, lineno = 0, ret = 0;
1311
1312        /* Adjust address with bias */
1313        addr += self->bias;
1314
1315        /* Find cu die */
1316        if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) {
1317                pr_warning("Failed to find debug information for address %lx\n",
1318                           addr);
1319                ret = -EINVAL;
1320                goto end;
1321        }
1322
1323        /* Find a corresponding line (filename and lineno) */
1324        cu_find_lineinfo(&cudie, addr, &fname, &lineno);
1325        /* Don't care whether it failed or not */
1326
1327        /* Find a corresponding function (name, baseline and baseaddr) */
1328        if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) {
1329                /* Get function entry information */
1330                tmp = dwarf_diename(&spdie);
1331                if (!tmp ||
1332                    dwarf_entrypc(&spdie, &baseaddr) != 0 ||
1333                    dwarf_decl_line(&spdie, &baseline) != 0)
1334                        goto post;
1335                func = tmp;
1336
1337                if (addr == (unsigned long)baseaddr)
1338                        /* Function entry - Relative line number is 0 */
1339                        lineno = baseline;
1340                else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
1341                                             &indie)) {
1342                        if (dwarf_entrypc(&indie, &_addr) == 0 &&
1343                            _addr == addr)
1344                                /*
1345                                 * addr is at an inline function entry.
1346                                 * In this case, lineno should be the call-site
1347                                 * line number.
1348                                 */
1349                                lineno = die_get_call_lineno(&indie);
1350                        else {
1351                                /*
1352                                 * addr is in an inline function body.
1353                                 * Since lineno points one of the lines
1354                                 * of the inline function, baseline should
1355                                 * be the entry line of the inline function.
1356                                 */
1357                                tmp = dwarf_diename(&indie);
1358                                if (tmp &&
1359                                    dwarf_decl_line(&spdie, &baseline) == 0)
1360                                        func = tmp;
1361                        }
1362                }
1363        }
1364
1365post:
1366        /* Make a relative line number or an offset */
1367        if (lineno)
1368                ppt->line = lineno - baseline;
1369        else if (func)
1370                ppt->offset = addr - (unsigned long)baseaddr;
1371
1372        /* Duplicate strings */
1373        if (func) {
1374                ppt->function = strdup(func);
1375                if (ppt->function == NULL) {
1376                        ret = -ENOMEM;
1377                        goto end;
1378                }
1379        }
1380        if (fname) {
1381                ppt->file = strdup(fname);
1382                if (ppt->file == NULL) {
1383                        if (ppt->function) {
1384                                free(ppt->function);
1385                                ppt->function = NULL;
1386                        }
1387                        ret = -ENOMEM;
1388                        goto end;
1389                }
1390        }
1391end:
1392        if (ret == 0 && (fname || func))
1393                ret = 1;        /* Found a point */
1394        return ret;
1395}
1396
1397/* Add a line and store the src path */
1398static int line_range_add_line(const char *src, unsigned int lineno,
1399                               struct line_range *lr)
1400{
1401        /* Copy source path */
1402        if (!lr->path) {
1403                lr->path = strdup(src);
1404                if (lr->path == NULL)
1405                        return -ENOMEM;
1406        }
1407        return line_list__add_line(&lr->line_list, lineno);
1408}
1409
1410static int line_range_walk_cb(const char *fname, int lineno,
1411                              Dwarf_Addr addr __used,
1412                              void *data)
1413{
1414        struct line_finder *lf = data;
1415
1416        if ((strtailcmp(fname, lf->fname) != 0) ||
1417            (lf->lno_s > lineno || lf->lno_e < lineno))
1418                return 0;
1419
1420        if (line_range_add_line(fname, lineno, lf->lr) < 0)
1421                return -EINVAL;
1422
1423        return 0;
1424}
1425
1426/* Find line range from its line number */
1427static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1428{
1429        int ret;
1430
1431        ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);
1432
1433        /* Update status */
1434        if (ret >= 0)
1435                if (!list_empty(&lf->lr->line_list))
1436                        ret = lf->found = 1;
1437                else
1438                        ret = 0;        /* Lines are not found */
1439        else {
1440                free(lf->lr->path);
1441                lf->lr->path = NULL;
1442        }
1443        return ret;
1444}
1445
1446static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
1447{
1448        find_line_range_by_line(in_die, data);
1449
1450        /*
1451         * We have to check all instances of inlined function, because
1452         * some execution paths can be optimized out depends on the
1453         * function argument of instances
1454         */
1455        return 0;
1456}
1457
1458/* Search function from function name */
1459static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1460{
1461        struct dwarf_callback_param *param = data;
1462        struct line_finder *lf = param->data;
1463        struct line_range *lr = lf->lr;
1464
1465        /* Check declared file */
1466        if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
1467                return DWARF_CB_OK;
1468
1469        if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1470            die_compare_name(sp_die, lr->function)) {
1471                lf->fname = dwarf_decl_file(sp_die);
1472                dwarf_decl_line(sp_die, &lr->offset);
1473                pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
1474                lf->lno_s = lr->offset + lr->start;
1475                if (lf->lno_s < 0)      /* Overflow */
1476                        lf->lno_s = INT_MAX;
1477                lf->lno_e = lr->offset + lr->end;
1478                if (lf->lno_e < 0)      /* Overflow */
1479                        lf->lno_e = INT_MAX;
1480                pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
1481                lr->start = lf->lno_s;
1482                lr->end = lf->lno_e;
1483                if (dwarf_func_inline(sp_die))
1484                        param->retval = die_walk_instances(sp_die,
1485                                                line_range_inline_cb, lf);
1486                else
1487                        param->retval = find_line_range_by_line(sp_die, lf);
1488                return DWARF_CB_ABORT;
1489        }
1490        return DWARF_CB_OK;
1491}
1492
1493static int find_line_range_by_func(struct line_finder *lf)
1494{
1495        struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1496        dwarf_getfuncs(&lf->cu_die, line_range_search_cb, &param, 0);
1497        return param.retval;
1498}
1499
1500int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr)
1501{
1502        struct line_finder lf = {.lr = lr, .found = 0};
1503        int ret = 0;
1504        Dwarf_Off off = 0, noff;
1505        size_t cuhl;
1506        Dwarf_Die *diep;
1507        const char *comp_dir;
1508
1509        /* Fastpath: lookup by function name from .debug_pubnames section */
1510        if (lr->function) {
1511                struct pubname_callback_param pubname_param = {
1512                        .function = lr->function, .file = lr->file,
1513                        .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0};
1514                struct dwarf_callback_param line_range_param = {
1515                        .data = (void *)&lf, .retval = 0};
1516
1517                dwarf_getpubnames(self->dbg, pubname_search_cb,
1518                                  &pubname_param, 0);
1519                if (pubname_param.found) {
1520                        line_range_search_cb(&lf.sp_die, &line_range_param);
1521                        if (lf.found)
1522                                goto found;
1523                }
1524        }
1525
1526        /* Loop on CUs (Compilation Unit) */
1527        while (!lf.found && ret >= 0) {
1528                if (dwarf_nextcu(self->dbg, off, &noff, &cuhl,
1529                                 NULL, NULL, NULL) != 0)
1530                        break;
1531
1532                /* Get the DIE(Debugging Information Entry) of this CU */
1533                diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die);
1534                if (!diep)
1535                        continue;
1536
1537                /* Check if target file is included. */
1538                if (lr->file)
1539                        lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
1540                else
1541                        lf.fname = 0;
1542
1543                if (!lr->file || lf.fname) {
1544                        if (lr->function)
1545                                ret = find_line_range_by_func(&lf);
1546                        else {
1547                                lf.lno_s = lr->start;
1548                                lf.lno_e = lr->end;
1549                                ret = find_line_range_by_line(NULL, &lf);
1550                        }
1551                }
1552                off = noff;
1553        }
1554
1555found:
1556        /* Store comp_dir */
1557        if (lf.found) {
1558                comp_dir = cu_get_comp_dir(&lf.cu_die);
1559                if (comp_dir) {
1560                        lr->comp_dir = strdup(comp_dir);
1561                        if (!lr->comp_dir)
1562                                ret = -ENOMEM;
1563                }
1564        }
1565
1566        pr_debug("path: %s\n", lr->path);
1567        return (ret < 0) ? ret : lf.found;
1568}
1569
1570