Linux perf tool cannot parse PE files for debug information, but it also looks for external debug info alongside to the binaries it detects.
We can use this feature to provide DWARF information for PE files by splitting the sections to a separate ELF that perf will understand.
This could also be used to support different debug information formats, or to support split-dwarf option on ELF binaries.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- tools/winegcc/utils.c | 47 ++++++++++++++++++++++++++++++++---- tools/winegcc/utils.h | 3 +++ tools/winegcc/winegcc.c | 33 +++++++++++++++++++++++++ tools/winegcc/winegcc.man.in | 4 +++ 4 files changed, 82 insertions(+), 5 deletions(-)
diff --git a/tools/winegcc/utils.c b/tools/winegcc/utils.c index 3197e46e47d..287a9e8a708 100644 --- a/tools/winegcc/utils.c +++ b/tools/winegcc/utils.c @@ -179,15 +179,36 @@ char* strarray_tostring(const strarray* arr, const char* sep) return str; }
+char* get_dirname(const char* file) +{ + char *dir_name, *p; + + dir_name = xstrdup(file); + if ((p = strrchr(dir_name, '/'))) *p = 0; + else + { + free(dir_name); + dir_name = xstrdup("."); + } + + return dir_name; +} + +char* get_filename(const char* file) +{ + const char *file_name; + + if ((file_name = strrchr(file, '/'))) file_name++; + else file_name = file; + + return xstrdup(file_name); +} + char* get_basename(const char* file) { - const char* name; char *base_name, *p;
- if ((name = strrchr(file, '/'))) name++; - else name = file; - - base_name = strdup(name); + base_name = get_filename(file); if ((p = strrchr(base_name, '.'))) *p = 0;
return base_name; @@ -208,6 +229,22 @@ void create_file(const char* name, int mode, const char* fmt, ...) chmod(name, mode); }
+void create_dir( const char *dir ) +{ + char *p, *path; + + p = path = xstrdup( dir ); + while ((p = strchr( p, '/' ))) + { + *p = 0; + if (mkdir( path, 0755 ) == -1 && errno != EEXIST) error( "mkdir %s", path ); + *p++ = '/'; + while (*p == '/') p++; + } + if (mkdir( path, 0755 ) == -1 && errno != EEXIST) error( "mkdir %s", path ); + free( path ); +} + file_type get_file_type(const char* filename) { /* see tools/winebuild/res32.c: check_header for details */ diff --git a/tools/winegcc/utils.h b/tools/winegcc/utils.h index 3d6b8f3665b..9f3d6f1785d 100644 --- a/tools/winegcc/utils.h +++ b/tools/winegcc/utils.h @@ -80,8 +80,11 @@ typedef enum { file_arh, file_dll, file_so, file_def, file_spec } file_type;
+char* get_dirname(const char* file); +char* get_filename(const char* file); char* get_basename(const char* file); void create_file(const char* name, int mode, const char* fmt, ...); +void create_dir( const char *dir ); file_type get_file_type(const char* filename); file_type get_lib_type(enum target_platform platform, strarray* path, const char *library, const char *suffix, char** file); diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index d1440a64367..98dc2d417a7 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -210,6 +210,7 @@ struct options int unwind_tables; int strip; int strip_debug; + int split_dwarf; int pic; const char* wine_objdir; const char* winebuild; @@ -1263,6 +1264,31 @@ static void build(struct options* opts) spawn(opts->prefix, link_args, 0); strarray_free (link_args);
+ if (build_platform != PLATFORM_APPLE && is_pe && opts->split_dwarf) + { + char const *bfd_format = (opts->target_cpu == CPU_x86_64) ? "-Oelf64-x86-64" : "-Oelf32-i386"; + strarray *objcopy_args = strarray_fromstring(build_tool_name(opts, "objcopy", "objcopy"), " "); + char *debug_path, *file_name; + + file_name = get_filename(output_path); + debug_path = get_dirname(output_path); + debug_path = realloc(debug_path, strlen(debug_path) + strlen("/.debug/") + strlen(file_name) + 1); + + strcat(debug_path, "/.debug/"); + create_dir(debug_path); + + strcat(debug_path, file_name); + free(file_name); + + strarray_add(objcopy_args, bfd_format); + strarray_add(objcopy_args, "--only-keep-debug"); + strarray_add(objcopy_args, output_path); + strarray_add(objcopy_args, debug_path); + spawn(opts->prefix, objcopy_args, 1); + strarray_free(objcopy_args); + free(debug_path); + } + if (opts->target_platform != PLATFORM_APPLE && is_pe && opts->strip) { strarray *strip_args = strarray_fromstring(build_tool_name(opts, "strip", "strip"), " "); @@ -1557,6 +1583,13 @@ int main(int argc, char **argv) case 'i': if (!strcmp( "-isysroot", argv[i] )) opts.isysroot = argv[i + 1]; break; + case 'g': + if (strcmp("-gsplit-dwarf", argv[i]) == 0) + { + opts.split_dwarf = 1; + raw_compiler_arg = 0; + } + break; case 'l': strarray_add(opts.files, strmake("-l%s", option_arg)); raw_compiler_arg = 0; diff --git a/tools/winegcc/winegcc.man.in b/tools/winegcc/winegcc.man.in index 5550767299b..7b6f420a2ed 100644 --- a/tools/winegcc/winegcc.man.in +++ b/tools/winegcc/winegcc.man.in @@ -41,6 +41,10 @@ precedence over the \fBWINEBUILD\fR environment variable. Override the underlying type for wchar_t to be the default for the target, instead of using short unsigned int, which is the default for Win32. +.IP \fB-gsplit-dwarf\fR +Split debug sections from PE files to a separate ELF binary. This can +be used to help tools like \fBperf\fR, that only support ELF parsing, +load the debug sections. .IP \fB-mconsole\fR This option passes '--subsystem console' to winebuild, to build console applications. It is the default.