1 /* Command-line frontend for retrieving ELF / DWARF / source files
3 Copyright (C) 2019-2020 Red Hat, Inc.
4 This file is part of elfutils.
6 This file 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 3 of the License, or
9 (at your option) any later version.
11 elfutils is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "printversion.h"
22 #include "debuginfod.h"
35 /* Name and version of program. */
36 ARGP_PROGRAM_VERSION_HOOK_DEF
= print_version
;
38 /* Bug report address. */
39 ARGP_PROGRAM_BUG_ADDRESS_DEF
= PACKAGE_BUGREPORT
;
41 /* Short description of program. */
42 static const char doc
[] = N_("Request debuginfo-related content "
43 "from debuginfods listed in $" DEBUGINFOD_URLS_ENV_VAR
".");
45 /* Strings for arguments in help texts. */
46 static const char args_doc
[] = N_("debuginfo BUILDID\n"
48 "executable BUILDID\n"
50 "source BUILDID /FILENAME\n"
51 "source PATH /FILENAME\n");
54 /* Definitions of arguments for argp functions. */
55 static const struct argp_option options
[] =
57 { "verbose", 'v', NULL
, 0, "Increase verbosity.", 0 },
58 { NULL
, 0, NULL
, 0, NULL
, 0 }
61 /* debuginfod connection handle. */
62 static debuginfod_client
*client
;
65 int progressfn(debuginfod_client
*c
__attribute__((__unused__
)),
68 static bool first
= true;
69 static struct timespec last
;
74 clock_gettime (CLOCK_MONOTONIC
, &now
);
75 delta
= ((now
.tv_sec
- last
.tv_sec
) * 1000000
76 + (now
.tv_nsec
- last
.tv_nsec
) / 1000);
84 /* Show progress the first time and then at most 5 times a second. */
87 fprintf (stderr
, "Progress %ld / %ld\n", a
, b
);
88 clock_gettime (CLOCK_MONOTONIC
, &last
);
94 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
)
101 debuginfod_set_progressfn (client
, & progressfn
); break;
102 default: return ARGP_ERR_UNKNOWN
;
108 /* Data structure to communicate with argp functions. */
109 static struct argp argp
=
111 options
, parse_opt
, args_doc
, doc
, NULL
, NULL
, NULL
117 main(int argc
, char** argv
)
119 elf_version (EV_CURRENT
);
121 client
= debuginfod_begin ();
124 fprintf(stderr
, "Couldn't create debuginfod client context\n");
128 /* Exercise user data pointer, to support testing only. */
129 debuginfod_set_user_data (client
, (void *)"Progress");
132 (void) argp_parse (&argp
, argc
, argv
, ARGP_IN_ORDER
|ARGP_NO_ARGS
, &remaining
, NULL
);
134 if (argc
< 2 || remaining
+1 == argc
) /* no arguments or at least two non-option words */
136 argp_help (&argp
, stderr
, ARGP_HELP_USAGE
, argv
[0]);
140 /* If we were passed an ELF file name in the BUILDID slot, look in there. */
141 unsigned char* build_id
= (unsigned char*) argv
[remaining
+1];
142 int build_id_len
= 0; /* assume text */
146 for (i
= 0; build_id
[i
] != '\0'; i
++)
147 if ((build_id
[i
] >= '0' && build_id
[i
] <= '9') ||
148 (build_id
[i
] >= 'a' && build_id
[i
] <= 'f'))
155 if (any_non_hex
) /* raw build-id */
157 fd
= open ((char*) build_id
, O_RDONLY
);
159 fprintf (stderr
, "Cannot open %s: %s\n", build_id
, strerror(errno
));
163 elf
= dwelf_elf_begin (fd
);
165 fprintf (stderr
, "Cannot open as ELF file %s: %s\n", build_id
,
170 const void *extracted_build_id
;
171 ssize_t s
= dwelf_elf_gnu_build_id(elf
, &extracted_build_id
);
174 /* Success: replace the build_id pointer/len with the binary blob
175 that elfutils is keeping for us. It'll remain valid until elf_end(). */
176 build_id
= (unsigned char*) extracted_build_id
;
180 fprintf (stderr
, "Cannot extract build-id from %s: %s\n", build_id
, elf_errmsg(-1));
186 /* Check whether FILETYPE is valid and call the appropriate
187 debuginfod_find_* function. If FILETYPE is "source"
188 then ensure a FILENAME was also supplied as an argument. */
189 if (strcmp(argv
[remaining
], "debuginfo") == 0)
190 rc
= debuginfod_find_debuginfo(client
,
191 build_id
, build_id_len
,
193 else if (strcmp(argv
[remaining
], "executable") == 0)
194 rc
= debuginfod_find_executable(client
,
195 build_id
, build_id_len
,
197 else if (strcmp(argv
[remaining
], "source") == 0)
199 if (remaining
+2 == argc
|| argv
[remaining
+2][0] != '/')
201 fprintf(stderr
, "If FILETYPE is \"source\" then absolute /FILENAME must be given\n");
204 rc
= debuginfod_find_source(client
,
205 build_id
, build_id_len
,
206 argv
[remaining
+2], &cache_name
);
210 argp_help (&argp
, stderr
, ARGP_HELP_USAGE
, argv
[0]);
216 const char* url
= debuginfod_get_url (client
);
218 fprintf(stderr
, "Downloaded from %s\n", url
);
221 debuginfod_end (client
);
229 fprintf(stderr
, "Server query failed: %s\n", strerror(-rc
));
233 printf("%s\n", cache_name
);