From: Richard Biener <rguenther@suse.de>
To: Jakub Jelinek <jakub@redhat.com>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] lto: Stream current working directory for first streamed relative filename and adjust relative paths [PR93865]
Date: Thu, 10 Sep 2020 11:17:28 +0200 (CEST) [thread overview]
Message-ID: <nycvar.YFH.7.76.2009101117090.9963@zhemvz.fhfr.qr> (raw)
In-Reply-To: <20200910083811.GU18149@tucnak>
On Thu, 10 Sep 2020, Jakub Jelinek wrote:
> Hi!
>
> If the gcc -c -flto ... commands to compile some or all objects are run in a
> different directory (or in different directories) from the directory in
> which the gcc -flto link line is invoked, then the .debug_line will be
> incorrect if there are any relative filenames, it will use those relative
> filenames while .debug_info will contain a different DW_AT_comp_dir.
>
> The following patch streams (at most once after each clear_line_info)
> the current working directory (what we record in DW_AT_comp_dir) when
> encountering the first relative pathname, and when reading the location info
> reads it back and if the current working directory at that point is
> different from the saved one, adjusts relative paths by adding a relative
> prefix how to go from the current working directory to the previously saved
> path (with a fallback e.g. for DOS e:\\foo vs. d:\\bar change to use
> absolute directory).
>
> Bootstrapped/regtested on x86_64-linux (both lto bootstrap and normal one;
> i686-linux doesn't build due to some unrelated libgo bugs), ok for trunk?
>
> 2020-09-10 Jakub Jelinek <jakub@redhat.com>
>
> PR debug/93865
> * lto-streamer.h (struct output_block): Add emit_pad member.
emit_pwd.
OK.
Thanks for working on these issues,
Richard.
> * lto-streamer-out.c: Include toplev.h.
> (clear_line_info): Set emit_pwd.
> (lto_output_location_1): Encode the ob->current_file != xloc.file
> bit directly into the location number. If changing file, emit
> additionally a bit whether pwd is emitted and emit it before the
> first relative pathname since clear_line_info.
> (output_function, output_constructor): Don't call clear_line_info
> here.
> * lto-streamer-in.c (struct string_pair_map): New type.
> (struct string_pair_map_hasher): New type.
> (string_pair_map_hasher::hash): New method.
> (string_pair_map_hasher::equal): New method.
> (path_name_pair_hash_table, string_pair_map_allocator): New variables.
> (relative_path_prefix, canon_relative_path_prefix,
> canon_relative_file_name): New functions.
> (canon_file_name): Add relative_prefix argument, if non-NULL
> and string is a relative path, return canon_relative_file_name.
> (lto_location_cache::input_location_and_block): Decode file change
> bit from the location number. If changing file, unpack bit whether
> pwd is streamed and stream in pwd. Adjust canon_file_name caller.
> (lto_free_file_name_hash): Delete path_name_pair_hash_table
> and string_pair_map_allocator.
>
> --- gcc/lto-streamer.h.jj 2020-09-09 09:08:13.102815586 +0200
> +++ gcc/lto-streamer.h 2020-09-09 12:36:13.120070769 +0200
> @@ -718,6 +718,7 @@ struct output_block
> int current_col;
> bool current_sysp;
> bool reset_locus;
> + bool emit_pwd;
> tree current_block;
>
> /* Cache of nodes written in this section. */
> --- gcc/lto-streamer-out.c.jj 2020-09-09 09:08:13.077815963 +0200
> +++ gcc/lto-streamer-out.c 2020-09-09 13:21:34.093021582 +0200
> @@ -47,6 +47,7 @@ along with GCC; see the file COPYING3.
> #include "file-prefix-map.h" /* remap_debug_filename() */
> #include "output.h"
> #include "ipa-utils.h"
> +#include "toplev.h"
>
>
> static void lto_write_tree (struct output_block*, tree, bool);
> @@ -61,6 +62,7 @@ clear_line_info (struct output_block *ob
> ob->current_col = 0;
> ob->current_sysp = false;
> ob->reset_locus = true;
> + ob->emit_pwd = true;
> /* Initialize to something that will never appear as block,
> so that the first location with block in a function etc.
> always streams a change_block bit and the first block. */
> @@ -189,9 +191,6 @@ lto_output_location_1 (struct output_blo
> {
> location_t loc = LOCATION_LOCUS (orig_loc);
>
> - bp_pack_int_in_range (bp, 0, RESERVED_LOCATION_COUNT,
> - loc < RESERVED_LOCATION_COUNT
> - ? loc : RESERVED_LOCATION_COUNT);
> if (loc >= RESERVED_LOCATION_COUNT)
> {
> expanded_location xloc = expand_location (loc);
> @@ -207,13 +206,30 @@ lto_output_location_1 (struct output_blo
> ob->reset_locus = false;
> }
>
> - bp_pack_value (bp, ob->current_file != xloc.file, 1);
> + /* As RESERVED_LOCATION_COUNT is 2, we can use the spare value of
> + 3 without wasting additional bits to signalize file change.
> + If RESERVED_LOCATION_COUNT changes, reconsider this. */
> + gcc_checking_assert (RESERVED_LOCATION_COUNT == 2);
> + bp_pack_int_in_range (bp, 0, RESERVED_LOCATION_COUNT + 1,
> + RESERVED_LOCATION_COUNT
> + + (ob->current_file != xloc.file));
> +
> bp_pack_value (bp, ob->current_line != xloc.line, 1);
> bp_pack_value (bp, ob->current_col != xloc.column, 1);
>
> if (ob->current_file != xloc.file)
> {
> - bp_pack_string (ob, bp, remap_debug_filename (xloc.file), true);
> + bool stream_pwd = false;
> + const char *remapped = remap_debug_filename (xloc.file);
> + if (ob->emit_pwd && remapped && !IS_ABSOLUTE_PATH (remapped))
> + {
> + stream_pwd = true;
> + ob->emit_pwd = false;
> + }
> + bp_pack_value (bp, stream_pwd, 1);
> + if (stream_pwd)
> + bp_pack_string (ob, bp, get_src_pwd (), true);
> + bp_pack_string (ob, bp, remapped, true);
> bp_pack_value (bp, xloc.sysp, 1);
> }
> ob->current_file = xloc.file;
> @@ -227,6 +243,8 @@ lto_output_location_1 (struct output_blo
> bp_pack_var_len_unsigned (bp, xloc.column);
> ob->current_col = xloc.column;
> }
> + else
> + bp_pack_int_in_range (bp, 0, RESERVED_LOCATION_COUNT + 1, loc);
>
> if (block_p)
> {
> @@ -2376,7 +2394,6 @@ output_function (struct cgraph_node *nod
> fn = DECL_STRUCT_FUNCTION (function);
> ob = create_output_block (LTO_section_function_body);
>
> - clear_line_info (ob);
> ob->symbol = node;
>
> gcc_assert (current_function_decl == NULL_TREE && cfun == NULL);
> @@ -2462,7 +2479,6 @@ output_constructor (struct varpool_node
> timevar_push (TV_IPA_LTO_CTORS_OUT);
> ob = create_output_block (LTO_section_function_body);
>
> - clear_line_info (ob);
> ob->symbol = node;
>
> /* Make string 0 be a NULL string. */
> --- gcc/lto-streamer-in.c.jj 2020-09-09 09:08:13.076815979 +0200
> +++ gcc/lto-streamer-in.c 2020-09-09 17:04:08.015377451 +0200
> @@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.
> #include "cfgloop.h"
> #include "debug.h"
> #include "alloc-pool.h"
> +#include "toplev.h"
>
> /* Allocator used to hold string slot entries for line map streaming. */
> static struct object_allocator<struct string_slot> *string_slot_allocator;
> @@ -50,11 +51,58 @@ static struct object_allocator<struct st
> /* The table to hold the file names. */
> static hash_table<string_slot_hasher> *file_name_hash_table;
>
> +/* The table to hold the relative pathname prefixes. */
> +
> /* This obstack holds file names used in locators. Line map datastructures
> points here and thus it needs to be kept allocated as long as linemaps
> exists. */
> static struct obstack file_name_obstack;
>
> +/* Map a pair of nul terminated strings where the first one can be
> + pointer compared, but the second can't, to another string. */
> +struct string_pair_map
> +{
> + const char *str1;
> + const char *str2;
> + const char *str3;
> + hashval_t hash;
> + bool prefix;
> +};
> +
> +/* Allocator used to hold string pair map entries for line map streaming. */
> +static struct object_allocator<struct string_pair_map>
> + *string_pair_map_allocator;
> +
> +struct string_pair_map_hasher : nofree_ptr_hash <string_pair_map>
> +{
> + static inline hashval_t hash (const string_pair_map *);
> + static inline bool equal (const string_pair_map *, const string_pair_map *);
> +};
> +
> +inline hashval_t
> +string_pair_map_hasher::hash (const string_pair_map *spm)
> +{
> + return spm->hash;
> +}
> +
> +inline bool
> +string_pair_map_hasher::equal (const string_pair_map *spm1,
> + const string_pair_map *spm2)
> +{
> + return (spm1->hash == spm2->hash
> + && spm1->str1 == spm2->str1
> + && spm1->prefix == spm2->prefix
> + && strcmp (spm1->str2, spm2->str2) == 0);
> +}
> +
> +/* The table to hold the pairs of pathnames and corresponding
> + resulting pathname. Used for both mapping of get_src_pwd ()
> + and recorded source working directory to relative path prefix
> + from current working directory to the recorded one, and for
> + mapping of that relative path prefix and some relative path
> + to those concatenated. */
> +static hash_table<string_pair_map_hasher> *path_name_pair_hash_table;
> +
>
> /* Check that tag ACTUAL has one of the given values. NUM_TAGS is the
> number of valid tag values to check. */
> @@ -90,13 +138,216 @@ lto_input_data_block (class lto_input_bl
> buffer[i] = streamer_read_uchar (ib);
> }
>
> +/* Compute the relative path to get to DATA_WD (absolute directory name)
> + from CWD (another absolute directory name). E.g. for
> + DATA_WD of "/tmp/foo/bar" and CWD of "/tmp/baz/qux" return
> + "../../foo/bar". Returned string should be freed by the caller.
> + Return NULL if absolute file name needs to be used. */
> +
> +static char *
> +relative_path_prefix (const char *data_wd, const char *cwd)
> +{
> + const char *d = data_wd;
> + const char *c = cwd;
> +#ifdef HAVE_DOS_BASED_FILE_SYSTEM
> + if (d[1] == ':')
> + {
> + if (!IS_DIR_SEPARATOR (d[2]))
> + return NULL;
> + if (c[0] == d[0] && c[1] == ':' && IS_DIR_SEPARATOR (c[2]))
> + {
> + c += 3;
> + d += 3;
> + }
> + else
> + return NULL;
> + }
> + else if (c[1] == ':')
> + return NULL;
> +#endif
> + do
> + {
> + while (IS_DIR_SEPARATOR (*d))
> + d++;
> + while (IS_DIR_SEPARATOR (*c))
> + c++;
> + size_t i;
> + for (i = 0; c[i] && !IS_DIR_SEPARATOR (c[i]) && c[i] == d[i]; i++)
> + ;
> + if ((c[i] == '\0' || IS_DIR_SEPARATOR (c[i]))
> + && (d[i] == '\0' || IS_DIR_SEPARATOR (d[i])))
> + {
> + c += i;
> + d += i;
> + if (*c == '\0' || *d == '\0')
> + break;
> + }
> + else
> + break;
> + }
> + while (1);
> + size_t num_up = 0;
> + do
> + {
> + while (IS_DIR_SEPARATOR (*c))
> + c++;
> + if (*c == '\0')
> + break;
> + num_up++;
> + while (*c && !IS_DIR_SEPARATOR (*c))
> + c++;
> + }
> + while (1);
> + while (IS_DIR_SEPARATOR (*d))
> + d++;
> + size_t len = strlen (d);
> + if (len == 0 && num_up == 0)
> + return xstrdup (".");
> + char *ret = XNEWVEC (char, num_up * 3 + len + 1);
> + char *p = ret;
> + for (; num_up; num_up--)
> + {
> + const char dir_up[3] = { '.', '.', DIR_SEPARATOR };
> + memcpy (p, dir_up, 3);
> + p += 3;
> + }
> + memcpy (p, d, len + 1);
> + return ret;
> +}
> +
> +/* Look up DATA_WD in hash table of relative prefixes. If found,
> + return relative path from CWD to DATA_WD from the hash table,
> + otherwise create it. */
> +
> +static const char *
> +canon_relative_path_prefix (const char *data_wd, const char *cwd)
> +{
> + if (!IS_ABSOLUTE_PATH (data_wd) || !IS_ABSOLUTE_PATH (cwd))
> + return NULL;
> +
> + if (!path_name_pair_hash_table)
> + {
> + path_name_pair_hash_table
> + = new hash_table<string_pair_map_hasher> (37);
> + string_pair_map_allocator
> + = new object_allocator <struct string_pair_map>
> + ("line map string pair map hash");
> + }
> +
> + inchash::hash h;
> + h.add_ptr (cwd);
> + h.merge_hash (htab_hash_string (data_wd));
> + h.add_int (true);
> +
> + string_pair_map s_slot;
> + s_slot.str1 = cwd;
> + s_slot.str2 = data_wd;
> + s_slot.str3 = NULL;
> + s_slot.hash = h.end ();
> + s_slot.prefix = true;
> +
> + string_pair_map **slot
> + = path_name_pair_hash_table->find_slot (&s_slot, INSERT);
> + if (*slot == NULL)
> + {
> + /* Compute relative path from cwd directory to data_wd directory.
> + E.g. if cwd is /tmp/foo/bar and data_wd is /tmp/baz/qux ,
> + it will return ../../baz/qux . */
> + char *relative_path = relative_path_prefix (data_wd, cwd);
> + const char *relative = relative_path ? relative_path : data_wd;
> + size_t relative_len = strlen (relative);
> + gcc_assert (relative_len);
> +
> + size_t data_wd_len = strlen (data_wd);
> + bool add_separator = false;
> + if (!IS_DIR_SEPARATOR (relative[relative_len - 1]))
> + add_separator = true;
> +
> + size_t len = relative_len + 1 + data_wd_len + 1 + add_separator;
> +
> + char *saved_string = XOBNEWVEC (&file_name_obstack, char, len);
> + struct string_pair_map *new_slot
> + = string_pair_map_allocator->allocate ();
> + memcpy (saved_string, data_wd, data_wd_len + 1);
> + memcpy (saved_string + data_wd_len + 1, relative, relative_len);
> + if (add_separator)
> + saved_string[len - 2] = DIR_SEPARATOR;
> + saved_string[len - 1] = '\0';
> + new_slot->str1 = cwd;
> + new_slot->str2 = saved_string;
> + new_slot->str3 = saved_string + data_wd_len + 1;
> + if (relative_len == 1 && relative[0] == '.')
> + new_slot->str3 = NULL;
> + new_slot->hash = s_slot.hash;
> + new_slot->prefix = true;
> + *slot = new_slot;
> + free (relative_path);
> + return new_slot->str3;
> + }
> + else
> + {
> + string_pair_map *old_slot = *slot;
> + return old_slot->str3;
> + }
> +}
> +
> +/* Look up the pair of RELATIVE_PREFIX and STRING strings in a hash table.
> + If found, return the concatenation of those from the hash table,
> + otherwise concatenate them. */
> +
> +static const char *
> +canon_relative_file_name (const char *relative_prefix, const char *string)
> +{
> + inchash::hash h;
> + h.add_ptr (relative_prefix);
> + h.merge_hash (htab_hash_string (string));
> +
> + string_pair_map s_slot;
> + s_slot.str1 = relative_prefix;
> + s_slot.str2 = string;
> + s_slot.str3 = NULL;
> + s_slot.hash = h.end ();
> + s_slot.prefix = false;
> +
> + string_pair_map **slot
> + = path_name_pair_hash_table->find_slot (&s_slot, INSERT);
> + if (*slot == NULL)
> + {
> + size_t relative_prefix_len = strlen (relative_prefix);
> + size_t string_len = strlen (string);
> + size_t len = relative_prefix_len + string_len + 1;
> +
> + char *saved_string = XOBNEWVEC (&file_name_obstack, char, len);
> + struct string_pair_map *new_slot
> + = string_pair_map_allocator->allocate ();
> + memcpy (saved_string, relative_prefix, relative_prefix_len);
> + memcpy (saved_string + relative_prefix_len, string, string_len + 1);
> + new_slot->str1 = relative_prefix;
> + new_slot->str2 = saved_string + relative_prefix_len;
> + new_slot->str3 = saved_string;
> + new_slot->hash = s_slot.hash;
> + new_slot->prefix = false;
> + *slot = new_slot;
> + return new_slot->str3;
> + }
> + else
> + {
> + string_pair_map *old_slot = *slot;
> + return old_slot->str3;
> + }
> +}
>
> /* Lookup STRING in file_name_hash_table. If found, return the existing
> - string, otherwise insert STRING as the canonical version. */
> + string, otherwise insert STRING as the canonical version.
> + If STRING is a relative pathname and RELATIVE_PREFIX is non-NULL, use
> + canon_relative_file_name instead. */
>
> static const char *
> -canon_file_name (const char *string)
> +canon_file_name (const char *relative_prefix, const char *string)
> {
> + if (relative_prefix && !IS_ABSOLUTE_PATH (string))
> + return canon_relative_file_name (relative_prefix, string);
> +
> string_slot **slot;
> struct string_slot s_slot;
> size_t len = strlen (string);
> @@ -261,10 +512,12 @@ lto_location_cache::input_location_and_b
> static int stream_col;
> static bool stream_sysp;
> static tree stream_block;
> + static const char *stream_relative_path_prefix;
>
> gcc_assert (current_cache == this);
>
> - *loc = bp_unpack_int_in_range (bp, "location", 0, RESERVED_LOCATION_COUNT);
> + *loc = bp_unpack_int_in_range (bp, "location", 0,
> + RESERVED_LOCATION_COUNT + 1);
>
> if (*loc < RESERVED_LOCATION_COUNT)
> {
> @@ -279,16 +532,28 @@ lto_location_cache::input_location_and_b
> return;
> }
>
> + bool file_change = (*loc == RESERVED_LOCATION_COUNT + 1);
> /* Keep value RESERVED_LOCATION_COUNT in *loc as linemap lookups will
> ICE on it. */
> -
> - bool file_change = bp_unpack_value (bp, 1);
> + *loc = RESERVED_LOCATION_COUNT;
> bool line_change = bp_unpack_value (bp, 1);
> bool column_change = bp_unpack_value (bp, 1);
>
> if (file_change)
> {
> - stream_file = canon_file_name (bp_unpack_string (data_in, bp));
> + bool pwd_change = bp_unpack_value (bp, 1);
> + if (pwd_change)
> + {
> + const char *pwd = bp_unpack_string (data_in, bp);
> + const char *src_pwd = get_src_pwd ();
> + if (strcmp (pwd, src_pwd) == 0)
> + stream_relative_path_prefix = NULL;
> + else
> + stream_relative_path_prefix
> + = canon_relative_path_prefix (pwd, src_pwd);
> + }
> + stream_file = canon_file_name (stream_relative_path_prefix,
> + bp_unpack_string (data_in, bp));
> stream_sysp = bp_unpack_value (bp, 1);
> }
>
> @@ -1857,6 +2122,10 @@ lto_free_file_name_hash (void)
> file_name_hash_table = NULL;
> delete string_slot_allocator;
> string_slot_allocator = NULL;
> + delete path_name_pair_hash_table;
> + path_name_pair_hash_table = NULL;
> + delete string_pair_map_allocator;
> + string_pair_map_allocator = NULL;
> /* file_name_obstack must stay allocated since it is referred to by
> line map table. */
> }
>
> Jakub
>
>
--
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
next prev parent reply other threads:[~2020-09-10 9:17 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-10 8:38 Jakub Jelinek
2020-09-10 9:17 ` Richard Biener [this message]
2022-11-15 1:35 ` Ian Lance Taylor
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=nycvar.YFH.7.76.2009101117090.9963@zhemvz.fhfr.qr \
--to=rguenther@suse.de \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).