brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.9 KiB · 07fb206 Raw
344 lines · cpp
1//===-- main.cpp ------------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include <getopt.h>10#include <stdint.h>11#include <stdlib.h>12 13#if defined(__APPLE__)14#include <LLDB/LLDB.h>15#else16#include "LLDB/SBBlock.h"17#include "LLDB/SBCompileUnit.h"18#include "LLDB/SBDebugger.h"19#include "LLDB/SBFunction.h"20#include "LLDB/SBModule.h"21#include "LLDB/SBProcess.h"22#include "LLDB/SBStream.h"23#include "LLDB/SBSymbol.h"24#include "LLDB/SBTarget.h"25#include "LLDB/SBThread.h"26#endif27 28#include <string>29 30using namespace lldb;31 32// This quick sample code shows how to create a debugger instance and33// create an executable target without adding dependent shared34// libraries. It will then set a regular expression breakpoint to get35// breakpoint locations for all functions in the module, and use the36// locations to extract the symbol context for each location. Then it37// dumps all // information about the function: its name, file address38// range, the return type (if any), and all argument types.39//40// To build the program, type (while in this directory):41//42//    $ make43//44// then to run this on MacOSX, specify the path to your LLDB.framework45// library using the DYLD_FRAMEWORK_PATH option and run the executable46//47//    $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/tot/build/Debug ./a.out48//    executable_path1 [executable_path2 ...]49class LLDBSentry {50public:51  LLDBSentry() {52    // Initialize LLDB53    SBDebugger::Initialize();54  }55  ~LLDBSentry() {56    // Terminate LLDB57    SBDebugger::Terminate();58  }59};60 61static struct option g_long_options[] = {62    {"arch", required_argument, NULL, 'a'},63    {"canonical", no_argument, NULL, 'c'},64    {"extern", no_argument, NULL, 'x'},65    {"help", no_argument, NULL, 'h'},66    {"platform", required_argument, NULL, 'p'},67    {"verbose", no_argument, NULL, 'v'},68    {NULL, 0, NULL, 0}};69 70#define PROGRAM_NAME "lldb-functions"71void usage() {72  puts("NAME\n"73       "    " PROGRAM_NAME74       " -- extract all function signatures from one or more binaries.\n"75       "\n"76       "SYNOPSIS\n"77       "    " PROGRAM_NAME " [[--arch=<ARCH>] [--platform=<PLATFORM>] "78                           "[--verbose] [--help] [--canonical] --] <PATH> "79                           "[<PATH>....]\n"80       "\n"81       "DESCRIPTION\n"82       "    Loads the executable pointed to by <PATH> and dumps complete "83       "signatures for all functions that have debug information.\n"84       "\n"85       "EXAMPLE\n"86       "   " PROGRAM_NAME " --arch=x86_64 /usr/lib/dyld\n");87  exit(0);88}89int main(int argc, char const *argv[]) {90  // Use a sentry object to properly initialize/terminate LLDB.91  LLDBSentry sentry;92 93  SBDebugger debugger(SBDebugger::Create());94 95  // Create a debugger instance so we can create a target96  if (!debugger.IsValid())97    fprintf(stderr, "error: failed to create a debugger object\n");98 99  bool show_usage = false;100  bool verbose = false;101  bool canonical = false;102  bool external_only = false;103  const char *arch = NULL;104  const char *platform = NULL;105  std::string short_options("h?");106  for (const struct option *opt = g_long_options; opt->name; ++opt) {107    if (isprint(opt->val)) {108      short_options.append(1, (char)opt->val);109      switch (opt->has_arg) {110      case no_argument:111        break;112      case required_argument:113        short_options.append(1, ':');114        break;115      case optional_argument:116        short_options.append(2, ':');117        break;118      }119    }120  }121#ifdef __GLIBC__122  optind = 0;123#else124  optreset = 1;125  optind = 1;126#endif127  char ch;128  while ((ch = getopt_long_only(argc, (char *const *)argv,129                                short_options.c_str(), g_long_options, 0)) !=130         -1) {131    switch (ch) {132    case 0:133      break;134 135    case 'a':136      if (arch != NULL) {137        fprintf(stderr,138                "error: the --arch option can only be specified once\n");139        exit(1);140      }141      arch = optarg;142      break;143 144    case 'c':145      canonical = true;146      break;147 148    case 'x':149      external_only = true;150      break;151 152    case 'p':153      platform = optarg;154      break;155 156    case 'v':157      verbose = true;158      break;159 160    case 'h':161    case '?':162    default:163      show_usage = true;164      break;165    }166  }167  argc -= optind;168  argv += optind;169 170  const bool add_dependent_libs = false;171  SBError error;172  for (int arg_idx = 0; arg_idx < argc; ++arg_idx) {173    // The first argument is the file path we want to look something up in174    const char *exe_file_path = argv[arg_idx];175 176    // Create a target using the executable.177    SBTarget target = debugger.CreateTarget(exe_file_path, arch, platform,178                                            add_dependent_libs, error);179 180    if (error.Success()) {181      if (target.IsValid()) {182        SBFileSpec exe_file_spec(exe_file_path, true);183        SBModule module(target.FindModule(exe_file_spec));184        SBFileSpecList comp_unit_list;185 186        if (module.IsValid()) {187          char command[1024];188          lldb::SBCommandReturnObject command_result;189          snprintf(command, sizeof(command), "add-dsym --uuid %s",190                   module.GetUUIDString());191          debugger.GetCommandInterpreter().HandleCommand(command,192                                                         command_result);193          if (!command_result.Succeeded()) {194            fprintf(stderr, "error: couldn't locate debug symbols for '%s'\n",195                    exe_file_path);196            exit(1);197          }198 199          SBFileSpecList module_list;200          module_list.Append(exe_file_spec);201          SBBreakpoint bp =202              target.BreakpointCreateByRegex(".", module_list, comp_unit_list);203 204          const size_t num_locations = bp.GetNumLocations();205          for (uint32_t bp_loc_idx = 0; bp_loc_idx < num_locations;206               ++bp_loc_idx) {207            SBBreakpointLocation bp_loc = bp.GetLocationAtIndex(bp_loc_idx);208            SBSymbolContext sc(209                bp_loc.GetAddress().GetSymbolContext(eSymbolContextEverything));210            if (sc.IsValid()) {211              if (sc.GetBlock().GetContainingInlinedBlock().IsValid()) {212                // Skip inlined functions213                continue;214              }215              SBFunction function(sc.GetFunction());216              if (function.IsValid()) {217                addr_t lo_pc = function.GetStartAddress().GetFileAddress();218                if (lo_pc == LLDB_INVALID_ADDRESS) {219                  // Skip functions that don't have concrete instances in the220                  // binary221                  continue;222                }223                addr_t hi_pc = function.GetEndAddress().GetFileAddress();224                const char *func_demangled_name = function.GetName();225                const char *func_mangled_name = function.GetMangledName();226 227                bool dump = true;228                const bool is_objc_method = ((func_demangled_name[0] == '-') ||229                                             (func_demangled_name[0] == '+')) &&230                                            (func_demangled_name[1] == '[');231                if (external_only) {232                  // Dump all objective C methods, or external symbols233                  dump = is_objc_method;234                  if (!dump)235                    dump = sc.GetSymbol().IsExternal();236                }237 238                if (dump) {239                  if (verbose) {240                    printf("\n   name: %s\n", func_demangled_name);241                    if (func_mangled_name)242                      printf("mangled: %s\n", func_mangled_name);243                    printf("  range: [0x%16.16llx - 0x%16.16llx)\n   type: ",244                           lo_pc, hi_pc);245                  } else {246                    printf("[0x%16.16llx - 0x%16.16llx) ", lo_pc, hi_pc);247                  }248                  SBType function_type = function.GetType();249                  SBType return_type = function_type.GetFunctionReturnType();250 251                  if (canonical)252                    return_type = return_type.GetCanonicalType();253 254                  if (func_mangled_name && func_mangled_name[0] == '_' &&255                      func_mangled_name[1] == 'Z') {256                    printf("%s %s\n", return_type.GetName(),257                           func_demangled_name);258                  } else {259                    SBTypeList function_args =260                        function_type.GetFunctionArgumentTypes();261                    const size_t num_function_args = function_args.GetSize();262 263                    if (is_objc_method) {264                      const char *class_name_start = func_demangled_name + 2;265 266                      if (num_function_args == 0) {267                        printf("%c(%s)[%s\n", func_demangled_name[0],268                               return_type.GetName(), class_name_start);269                      } else {270                        const char *class_name_end =271                            strchr(class_name_start, ' ');272                        const int class_name_len =273                            class_name_end - class_name_start;274                        printf("%c(%s)[%*.*s", func_demangled_name[0],275                               return_type.GetName(), class_name_len,276                               class_name_len, class_name_start);277 278                        const char *selector_pos = class_name_end + 1;279                        for (uint32_t function_arg_idx = 0;280                             function_arg_idx < num_function_args;281                             ++function_arg_idx) {282                          const char *selector_end =283                              strchr(selector_pos, ':') + 1;284                          const int selector_len = selector_end - selector_pos;285                          SBType function_arg_type =286                              function_args.GetTypeAtIndex(function_arg_idx);287 288                          if (canonical)289                            function_arg_type =290                                function_arg_type.GetCanonicalType();291 292                          printf(" %*.*s", selector_len, selector_len,293                                 selector_pos);294                          if (function_arg_type.IsValid()) {295                            printf("(%s)", function_arg_type.GetName());296                          } else {297                            printf("(?)");298                          }299                          selector_pos = selector_end;300                        }301                        printf("]\n");302                      }303                    } else {304                      printf("%s ", return_type.GetName());305                      if (strchr(func_demangled_name, '('))306                        printf("(*)(");307                      else308                        printf("%s(", func_demangled_name);309 310                      for (uint32_t function_arg_idx = 0;311                           function_arg_idx < num_function_args;312                           ++function_arg_idx) {313                        SBType function_arg_type =314                            function_args.GetTypeAtIndex(function_arg_idx);315 316                        if (canonical)317                          function_arg_type =318                              function_arg_type.GetCanonicalType();319 320                        if (function_arg_type.IsValid()) {321                          printf("%s%s", function_arg_idx > 0 ? ", " : "",322                                 function_arg_type.GetName());323                        } else {324                          printf("%s???", function_arg_idx > 0 ? ", " : "");325                        }326                      }327                      printf(")\n");328                    }329                  }330                }331              }332            }333          }334        }335      }336    } else {337      fprintf(stderr, "error: %s\n", error.GetCString());338      exit(1);339    }340  }341 342  return 0;343}344