Rizin
unix-like reverse engineering framework and cli tools
pdb_downloader.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2014-2020 inisider <inisider@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <string.h>
5 #include <rz_util.h>
6 #include <rz_core.h>
7 #include <rz_windows.h>
8 #include <rz_socket.h>
9 #include "pdb_downloader.h"
10 
11 static bool download_and_write(SPDBDownloaderOpt *opt, const char *file) {
12  char *dir = rz_str_newf("%s%s%s%s%s",
14  opt->dbg_file, RZ_SYS_DIR,
15  opt->guid);
16  if (!rz_sys_mkdirp(dir)) {
17  free(dir);
18  return false;
19  }
20  char *path = rz_str_newf("%s%s%s", dir, RZ_SYS_DIR, opt->dbg_file);
21  if (rz_file_exists(path)) {
22  free(dir);
23  free(path);
24  return true;
25  }
26  char *url = rz_str_newf("%s/%s/%s/%s", opt->symbol_server, opt->dbg_file, opt->guid, file);
27 #if __WINDOWS__
28  if (rz_str_startswith(url, "\\\\")) { // Network path
29  wchar_t *origin = rz_utf8_to_utf16(url);
30  wchar_t *dest = rz_utf8_to_utf16(path);
31  BOOL ret = CopyFileW(origin, dest, FALSE);
32  free(dir);
33  free(path);
34  free(origin);
35  free(dest);
36  return ret;
37  }
38 #endif
39  int len;
40  char *file_buf = rz_socket_http_get(url, NULL, &len);
41  free(url);
42  if (!len || RZ_STR_ISEMPTY(file_buf)) {
43  free(dir);
44  free(file_buf);
45  free(path);
46  return false;
47  }
48  FILE *f = fopen(path, "wb");
49  if (f) {
50  fwrite(file_buf, sizeof(char), (size_t)len, f);
51  fclose(f);
52  }
53  free(dir);
54  free(path);
55  free(file_buf);
56  return true;
57 }
58 
59 static char *download(struct SPDBDownloader *pd) {
60  SPDBDownloaderOpt *opt = pd->opt;
61  bool downloaded = false;
62 
63  if (!opt->dbg_file || !*opt->dbg_file) {
64  // no pdb debug file
65  return NULL;
66  }
67 
68  char *abspath_to_file = rz_str_newf("%s%s%s%s%s%s%s",
70  opt->dbg_file, RZ_SYS_DIR,
71  opt->guid, RZ_SYS_DIR,
72  opt->dbg_file);
73 
74  if (rz_file_exists(abspath_to_file)) {
75  eprintf("File already downloaded.\n");
76  return abspath_to_file;
77  }
78 
79  if (opt->extract == 0) {
80  char *extractor_cmd = NULL;
81  char *archive_name = strdup(opt->dbg_file);
82  archive_name[strlen(archive_name) - 1] = '_';
83  char *abspath_to_archive = rz_str_newf("%s%s%s%s%s%s%s",
85  opt->dbg_file, RZ_SYS_DIR,
86  opt->guid, RZ_SYS_DIR,
87  archive_name);
88  char *abspath_to_dir = rz_file_dirname(abspath_to_archive);
89 
90  eprintf("Attempting to download compressed pdb in %s\n", abspath_to_archive);
91  downloaded = download_and_write(opt, archive_name);
92 
93  if (opt->extract > 0 && downloaded) {
94  eprintf("Attempting to decompress pdb\n");
95  if (!rz_bin_pdb_extract_in_folder(abspath_to_archive, abspath_to_dir)) {
96  downloaded = false;
97  }
98  rz_file_rm(abspath_to_archive);
99  }
100  free(archive_name);
101  free(abspath_to_dir);
102  free(abspath_to_archive);
103  free(extractor_cmd);
104  }
105  if (!downloaded) {
106  eprintf("Falling back to uncompressed pdb\n");
107  eprintf("Attempting to download uncompressed pdb in %s\n", abspath_to_file);
108  downloaded = download_and_write(opt, opt->dbg_file);
109  if (!downloaded) {
110  RZ_FREE(abspath_to_file);
111  }
112  }
113  return downloaded ? abspath_to_file : NULL;
114 }
115 
124  if (!pd->opt) {
125  pd->download = 0;
126  eprintf("Cannot allocate memory for SPDBDownloaderOpt.\n");
127  return;
128  }
129  pd->opt->dbg_file = strdup(opt->dbg_file);
130  pd->opt->guid = strdup(opt->guid);
131  pd->opt->symbol_server = strdup(opt->symbol_server);
133  pd->opt->extract = opt->extract;
134  pd->download = download;
135 }
136 
143  RZ_FREE(pd->opt->dbg_file);
144  RZ_FREE(pd->opt->guid);
145  RZ_FREE(pd->opt->symbol_server);
147  RZ_FREE(pd->opt);
148  pd->download = 0;
149 }
150 
151 static bool is_valid_guid(const char *guid) {
152  if (!guid) {
153  return false;
154  }
155  size_t i;
156  for (i = 0; guid[i]; i++) {
157  if (!isxdigit(guid[i])) {
158  return false;
159  }
160  }
161  return i >= 33; // len of GUID and age
162 }
163 
173  SPDBDownloaderOpt opt;
175 
176  if (!info || !info->debug_file_name) {
177  RZ_LOG_ERROR("Can't find debug filename\n");
178  return 1;
179  }
180 
181  if (!is_valid_guid(info->guid)) {
182  RZ_LOG_ERROR("Invalid GUID for file\n");
183  return 1;
184  }
185 
186  if (!options->symbol_server || !options->symbol_store_path) {
187  RZ_LOG_ERROR("Can't retrieve pdb configurations\n");
188  return 1;
189  }
190 
192  opt.guid = info->guid;
193  opt.symbol_server = options->symbol_server;
194  opt.symbol_store_path = options->symbol_store_path;
195  opt.extract = options->extract;
196 
197  char *path = rz_bin_symserver_download(&opt);
198 
199  if (isradjson) {
200  pj_ko(pj, "pdb");
201  pj_ks(pj, "file", opt.dbg_file);
202  pj_ks(pj, "guid", opt.guid);
203  pj_ks(pj, "path", path);
204  pj_kb(pj, "download", (bool)path);
205  pj_end(pj);
206  } else {
207  rz_cons_printf("PDB \"%s\" download %s\n",
208  opt.dbg_file, path ? "success" : "failed");
209  }
210  free(path);
211  return !path;
212 }
213 
221  SPDBDownloader downloader;
222  SPDBDownloaderOpt opt = *options;
223  char *path = NULL;
224  char *symbol_server = strdup(options->symbol_server);
225  char *server = strtok(symbol_server, ";");
226  while (server && !path) {
227  opt.symbol_server = server;
228  init_pdb_downloader(&opt, &downloader);
229  if (!downloader.download) {
230  break;
231  }
232  path = downloader.download(&downloader);
233  deinit_pdb_downloader(&downloader);
234  server = strtok(NULL, ";");
235  }
236  free(symbol_server);
237  return path;
238 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
RZ_DEPRECATE RZ_API RZ_BORROW RzBinInfo * rz_bin_get_info(RzBin *bin)
Definition: bin.c:585
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
RZ_API bool rz_bin_pdb_extract_in_folder(RZ_NONNULL const char *file_cab, RZ_NONNULL const char *output_dir)
Extracts compressed PDB files into a folder.
Definition: cab_extract.c:209
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
#define RZ_API
#define NULL
Definition: cris-opc.c:27
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf uLong int origin
Definition: ioapi.h:144
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
static const char struct stat static buf struct stat static buf static vhangup int options
Definition: sflib.h:145
char * dest
Definition: lz4.h:697
#define FALSE
Definition: mybfd.h:102
string FILE
Definition: benchmark.py:21
url
Definition: setup.py:262
RZ_API RZ_OWN char * rz_bin_symserver_download(RZ_NONNULL const SPDBDownloaderOpt *options)
downloads file from symbol server
void deinit_pdb_downloader(SPDBDownloader *pd)
deinitialization of PDB downloader
static bool is_valid_guid(const char *guid)
static bool download_and_write(SPDBDownloaderOpt *opt, const char *file)
static char * download(struct SPDBDownloader *pd)
RZ_API int rz_bin_pdb_download(RZ_NONNULL RzBin *bin, RZ_NULLABLE PJ *pj, int isradjson, RZ_NONNULL SPDBOptions *options)
Download PDB file for currently opened RzBin file.
void init_pdb_downloader(SPDBDownloaderOpt *opt, SPDBDownloader *pd)
initialization of pdb downloader by SPDBDownloaderOpt
#define eprintf(x, y...)
Definition: rlcc.c:7
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API const char * rz_file_dos_basename(RZ_BORROW RZ_NONNULL const char *path)
Definition: file.c:102
RZ_API bool rz_file_exists(const char *str)
Definition: file.c:192
RZ_API char * rz_file_dirname(const char *path)
Definition: file.c:120
RZ_API bool rz_file_rm(const char *file)
Definition: file.c:865
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API PJ * pj_ko(PJ *j, const char *k)
Definition: pj.c:156
RZ_API PJ * pj_kb(PJ *j, const char *k, bool v)
Definition: pj.c:177
RZ_API PJ * pj_end(PJ *j)
Definition: pj.c:87
RZ_API PJ * pj_ks(PJ *j, const char *k, const char *v)
Definition: pj.c:170
RZ_API char * rz_socket_http_get(const char *url, int *code, int *rlen)
Definition: socket_http.c:287
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
#define RZ_STR_ISEMPTY(x)
Definition: rz_str.h:67
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
Definition: str.c:3286
RZ_API bool rz_sys_mkdirp(const char *dir)
Definition: sys.c:691
#define RZ_SYS_DIR
Definition: rz_types.h:218
#define RZ_NULLABLE
Definition: rz_types.h:65
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NONNULL
Definition: rz_types.h:64
#define RZ_FREE(x)
Definition: rz_types.h:369
#define isxdigit(c)
Definition: safe-ctype.h:145
#define f(i)
Definition: sha256.c:46
const char * dbg_file
const char * symbol_server
const char * symbol_store_path
const char * guid
SPDBDownloaderOpt * opt
char *(* download)(struct SPDBDownloader *pdb_downloader)
Definition: malloc.c:26
Definition: gzappend.c:170
Definition: rz_pj.h:12
char * guid
Definition: rz_bin.h:222
char * debug_file_name
Definition: rz_bin.h:223