diff mbox series

[V4,1/4] Add dso__is_pie call to identify ELF PIE

Message ID ee7a0b4944093db90a589040be39ef3e7e747f63.1724820993.git.scclevenger@os.amperecomputing.com (mailing list archive)
State New, archived
Headers show
Series arm-cs-trace-disasm.py/perf must accommodate non-zero DSO text offset | expand

Commit Message

Steve Clevenger Aug. 28, 2024, 5:09 a.m. UTC
Add dso__is_pie global to read the .dynamic section DT_FLAGS_1 entry for
the DF_1_PIE flag. This identifies position executable code.

Signed-off-by: Steve Clevenger <scclevenger@os.amperecomputing.com>
---
 tools/perf/util/symbol-elf.c | 60 ++++++++++++++++++++++++++++++++++++
 tools/perf/util/symbol.h     |  1 +
 2 files changed, 61 insertions(+)

Comments

Leo Yan Aug. 28, 2024, 8:23 a.m. UTC | #1
On 8/28/2024 6:09 AM, Steve Clevenger wrote:
> 
> Add dso__is_pie global to read the .dynamic section DT_FLAGS_1 entry for
> the DF_1_PIE flag. This identifies position executable code.
> 
> Signed-off-by: Steve Clevenger <scclevenger@os.amperecomputing.com>
> ---
>  tools/perf/util/symbol-elf.c | 60 ++++++++++++++++++++++++++++++++++++
>  tools/perf/util/symbol.h     |  1 +
>  2 files changed, 61 insertions(+)
> 
> diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
> index e398abfd13a0..0e49c1345a67 100644
> --- a/tools/perf/util/symbol-elf.c
> +++ b/tools/perf/util/symbol-elf.c
> @@ -662,6 +662,66 @@ static int dso__synthesize_plt_got_symbols(struct dso *dso, Elf *elf,
>         return err;
>  }
> 
> +/*
> + * Check dynamic section DT_FLAGS_1 for a Position Independent
> + * Executable (PIE).
> + */
> +bool dso__is_pie(struct dso *dso)
> +{
> +       Elf *elf = NULL;
> +       Elf_Scn *scn = NULL;
> +       GElf_Ehdr ehdr;
> +       GElf_Shdr shdr;
> +       bool is_pie = false;
> +       char dso_path[PATH_MAX];
> +       int fd = -1;
> +
> +       if (!dso || (elf_version(EV_CURRENT) == EV_NONE))
> +               goto exit;      // false
> +
> +       dso__build_id_filename(dso, dso_path, sizeof(dso_path), false);
> +
> +       fd = open(dso_path, O_RDONLY);
> +
> +       if (fd < 0) {
> +               pr_debug("%s: cannot read cached %s.\n", __func__, dso_path);
> +               goto exit;      // false
> +       }
> +
> +       elf = elf_begin(fd, ELF_C_READ, NULL);
> +       gelf_getehdr(elf, &ehdr);
> +
> +       if (ehdr.e_type == ET_DYN) {
> +               Elf_Data *data;
> +               GElf_Dyn *entry;
> +               int n_entries = shdr.sh_size / sizeof(GElf_Dyn);
> +
> +               scn = elf_section_by_name(elf, &ehdr, &shdr, ".dynamic", NULL);
> +               if (!scn)
> +                       goto exit;      // false

It should goto a new tag (e.g. exit_failed) so can invoke elf_end(elf) and
close(fd).

> +
> +               data = (Elf_Data *) elf_getdata(scn, NULL);
> +               if (!data || !data->d_buf)
> +                       goto exit;      // false

Ditto.

> +
> +               // check DT_FLAGS_1
> +               for (int i = 0; i < n_entries; i++) {
> +                       entry = ((GElf_Dyn *) data->d_buf) + i;
> +                       if (entry->d_tag == DT_FLAGS_1) {
> +                               if ((entry->d_un.d_val & DF_1_PIE) != 0) {
> +                                       is_pie = true;
> +                                       break;
> +                               }
> +                       }
> +               } // end for
> +       }
> +

Put 'exit_failed' tag at here.

With the changes:

Reviewed-by: Leo Yan <leo.yan@arm.com>

> +       elf_end(elf);
> +       close(fd);
> +exit:
> +       return is_pie;
> +}
> +
>  /*
>   * We need to check if we have a .dynsym, so that we can handle the
>   * .plt, synthesizing its symbols, that aren't on the symtabs (be it
> diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
> index 3fb5d146d9b1..33ea2596ce31 100644
> --- a/tools/perf/util/symbol.h
> +++ b/tools/perf/util/symbol.h
> @@ -127,6 +127,7 @@ void dso__insert_symbol(struct dso *dso,
>                         struct symbol *sym);
>  void dso__delete_symbol(struct dso *dso,
>                         struct symbol *sym);
> +bool dso__is_pie(struct dso *dso);
> 
>  struct symbol *dso__find_symbol(struct dso *dso, u64 addr);
>  struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr);
> --
> 2.25.1
>
Steve Clevenger Aug. 28, 2024, 3:48 p.m. UTC | #2
On 8/28/2024 1:23 AM, Leo Yan wrote:
> On 8/28/2024 6:09 AM, Steve Clevenger wrote:
>>
>> Add dso__is_pie global to read the .dynamic section DT_FLAGS_1 entry for
>> the DF_1_PIE flag. This identifies position executable code.
>>
>> Signed-off-by: Steve Clevenger <scclevenger@os.amperecomputing.com>
>> ---
>>  tools/perf/util/symbol-elf.c | 60 ++++++++++++++++++++++++++++++++++++
>>  tools/perf/util/symbol.h     |  1 +
>>  2 files changed, 61 insertions(+)
>>
>> diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
>> index e398abfd13a0..0e49c1345a67 100644
>> --- a/tools/perf/util/symbol-elf.c
>> +++ b/tools/perf/util/symbol-elf.c
>> @@ -662,6 +662,66 @@ static int dso__synthesize_plt_got_symbols(struct dso *dso, Elf *elf,
>>         return err;
>>  }
>>
>> +/*
>> + * Check dynamic section DT_FLAGS_1 for a Position Independent
>> + * Executable (PIE).
>> + */
>> +bool dso__is_pie(struct dso *dso)
>> +{
>> +       Elf *elf = NULL;
>> +       Elf_Scn *scn = NULL;
>> +       GElf_Ehdr ehdr;
>> +       GElf_Shdr shdr;
>> +       bool is_pie = false;
>> +       char dso_path[PATH_MAX];
>> +       int fd = -1;
>> +
>> +       if (!dso || (elf_version(EV_CURRENT) == EV_NONE))
>> +               goto exit;      // false
>> +
>> +       dso__build_id_filename(dso, dso_path, sizeof(dso_path), false);
>> +
>> +       fd = open(dso_path, O_RDONLY);
>> +
>> +       if (fd < 0) {
>> +               pr_debug("%s: cannot read cached %s.\n", __func__, dso_path);
>> +               goto exit;      // false
>> +       }
>> +
>> +       elf = elf_begin(fd, ELF_C_READ, NULL);
>> +       gelf_getehdr(elf, &ehdr);
>> +
>> +       if (ehdr.e_type == ET_DYN) {
>> +               Elf_Data *data;
>> +               GElf_Dyn *entry;
>> +               int n_entries = shdr.sh_size / sizeof(GElf_Dyn);
>> +
>> +               scn = elf_section_by_name(elf, &ehdr, &shdr, ".dynamic", NULL);
>> +               if (!scn)
>> +                       goto exit;      // false
> 
> It should goto a new tag (e.g. exit_failed) so can invoke elf_end(elf) and
> close(fd).
> 
>> +
>> +               data = (Elf_Data *) elf_getdata(scn, NULL);
>> +               if (!data || !data->d_buf)
>> +                       goto exit;      // false
> 
> Ditto.
> 
>> +
>> +               // check DT_FLAGS_1
>> +               for (int i = 0; i < n_entries; i++) {
>> +                       entry = ((GElf_Dyn *) data->d_buf) + i;
>> +                       if (entry->d_tag == DT_FLAGS_1) {
>> +                               if ((entry->d_un.d_val & DF_1_PIE) != 0) {
>> +                                       is_pie = true;
>> +                                       break;
>> +                               }
>> +                       }
>> +               } // end for
>> +       }
>> +
> 
> Put 'exit_failed' tag at here.
> 
> With the changes:
> 
> Reviewed-by: Leo Yan <leo.yan@arm.com>
> 
>> +       elf_end(elf);
>> +       close(fd);
>> +exit:
>> +       return is_pie;
>> +}
>> +

Hi Leo,

It's been a long time since I've seen goto's used as a rule rather than
an exception. I see it introduced the problem you've mentioned. Is it ok
to simply update the cover letter (patch 0), and this one (patch 1) as
V5? If I don't hear from you, I'll resubmit all.

Thanks,
Steve

>>  /*
>>   * We need to check if we have a .dynsym, so that we can handle the
>>   * .plt, synthesizing its symbols, that aren't on the symtabs (be it
>> diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
>> index 3fb5d146d9b1..33ea2596ce31 100644
>> --- a/tools/perf/util/symbol.h
>> +++ b/tools/perf/util/symbol.h
>> @@ -127,6 +127,7 @@ void dso__insert_symbol(struct dso *dso,
>>                         struct symbol *sym);
>>  void dso__delete_symbol(struct dso *dso,
>>                         struct symbol *sym);
>> +bool dso__is_pie(struct dso *dso);
>>
>>  struct symbol *dso__find_symbol(struct dso *dso, u64 addr);
>>  struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr);
>> --
>> 2.25.1
>>
Leo Yan Aug. 28, 2024, 8:34 p.m. UTC | #3
On 8/28/2024 4:48 PM, Steve Clevenger wrote:
> 
> On 8/28/2024 1:23 AM, Leo Yan wrote:
>> On 8/28/2024 6:09 AM, Steve Clevenger wrote:
>>>
>>> Add dso__is_pie global to read the .dynamic section DT_FLAGS_1 entry for
>>> the DF_1_PIE flag. This identifies position executable code.
>>>
>>> Signed-off-by: Steve Clevenger <scclevenger@os.amperecomputing.com>
>>> ---
>>>  tools/perf/util/symbol-elf.c | 60 ++++++++++++++++++++++++++++++++++++
>>>  tools/perf/util/symbol.h     |  1 +
>>>  2 files changed, 61 insertions(+)
>>>
>>> diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
>>> index e398abfd13a0..0e49c1345a67 100644
>>> --- a/tools/perf/util/symbol-elf.c
>>> +++ b/tools/perf/util/symbol-elf.c
>>> @@ -662,6 +662,66 @@ static int dso__synthesize_plt_got_symbols(struct dso *dso, Elf *elf,
>>>         return err;
>>>  }
>>>
>>> +/*
>>> + * Check dynamic section DT_FLAGS_1 for a Position Independent
>>> + * Executable (PIE).
>>> + */
>>> +bool dso__is_pie(struct dso *dso)
>>> +{
>>> +       Elf *elf = NULL;
>>> +       Elf_Scn *scn = NULL;
>>> +       GElf_Ehdr ehdr;
>>> +       GElf_Shdr shdr;
>>> +       bool is_pie = false;
>>> +       char dso_path[PATH_MAX];
>>> +       int fd = -1;
>>> +
>>> +       if (!dso || (elf_version(EV_CURRENT) == EV_NONE))
>>> +               goto exit;      // false
>>> +
>>> +       dso__build_id_filename(dso, dso_path, sizeof(dso_path), false);
>>> +
>>> +       fd = open(dso_path, O_RDONLY);
>>> +
>>> +       if (fd < 0) {
>>> +               pr_debug("%s: cannot read cached %s.\n", __func__, dso_path);
>>> +               goto exit;      // false
>>> +       }
>>> +
>>> +       elf = elf_begin(fd, ELF_C_READ, NULL);
>>> +       gelf_getehdr(elf, &ehdr);
>>> +
>>> +       if (ehdr.e_type == ET_DYN) {
>>> +               Elf_Data *data;
>>> +               GElf_Dyn *entry;
>>> +               int n_entries = shdr.sh_size / sizeof(GElf_Dyn);
>>> +
>>> +               scn = elf_section_by_name(elf, &ehdr, &shdr, ".dynamic", NULL);
>>> +               if (!scn)
>>> +                       goto exit;      // false
>>
>> It should goto a new tag (e.g. exit_failed) so can invoke elf_end(elf) and
>> close(fd).
>>
>>> +
>>> +               data = (Elf_Data *) elf_getdata(scn, NULL);
>>> +               if (!data || !data->d_buf)
>>> +                       goto exit;      // false
>>
>> Ditto.
>>
>>> +
>>> +               // check DT_FLAGS_1
>>> +               for (int i = 0; i < n_entries; i++) {
>>> +                       entry = ((GElf_Dyn *) data->d_buf) + i;
>>> +                       if (entry->d_tag == DT_FLAGS_1) {
>>> +                               if ((entry->d_un.d_val & DF_1_PIE) != 0) {
>>> +                                       is_pie = true;
>>> +                                       break;
>>> +                               }
>>> +                       }
>>> +               } // end for
>>> +       }
>>> +
>>
>> Put 'exit_failed' tag at here.
>>
>> With the changes:
>>
>> Reviewed-by: Leo Yan <leo.yan@arm.com>
>>
>>> +       elf_end(elf);
>>> +       close(fd);
>>> +exit:
>>> +       return is_pie;
>>> +}
>>> +
> 
> Hi Leo,
> 
> It's been a long time since I've seen goto's used as a rule rather than
> an exception. I see it introduced the problem you've mentioned.

I am not sure if I understand this. In the Linux code, it is quite common to
use goto to handle failure cases (for releasing resources).

> Is it ok to simply update the cover letter (patch 0), and this one (patch 1)
> as V5? If I don't hear from you, I'll resubmit all.

I assume you also need to address patch 03? It is good to send the all patches
in one go, this would be easier for maintainers to pick up the whole series
(e.g. using b4).

Thanks,
Leo
Leo Yan Aug. 28, 2024, 8:36 p.m. UTC | #4
On 8/28/2024 4:48 PM, Steve Clevenger wrote:
> 
> On 8/28/2024 1:23 AM, Leo Yan wrote:
>> On 8/28/2024 6:09 AM, Steve Clevenger wrote:
>>>
>>> Add dso__is_pie global to read the .dynamic section DT_FLAGS_1 entry for
>>> the DF_1_PIE flag. This identifies position executable code.
>>>
>>> Signed-off-by: Steve Clevenger <scclevenger@os.amperecomputing.com>
>>> ---
>>>  tools/perf/util/symbol-elf.c | 60 ++++++++++++++++++++++++++++++++++++
>>>  tools/perf/util/symbol.h     |  1 +
>>>  2 files changed, 61 insertions(+)
>>>
>>> diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
>>> index e398abfd13a0..0e49c1345a67 100644
>>> --- a/tools/perf/util/symbol-elf.c
>>> +++ b/tools/perf/util/symbol-elf.c
>>> @@ -662,6 +662,66 @@ static int dso__synthesize_plt_got_symbols(struct dso *dso, Elf *elf,
>>>         return err;
>>>  }
>>>
>>> +/*
>>> + * Check dynamic section DT_FLAGS_1 for a Position Independent
>>> + * Executable (PIE).
>>> + */
>>> +bool dso__is_pie(struct dso *dso)
>>> +{
>>> +       Elf *elf = NULL;
>>> +       Elf_Scn *scn = NULL;
>>> +       GElf_Ehdr ehdr;
>>> +       GElf_Shdr shdr;
>>> +       bool is_pie = false;
>>> +       char dso_path[PATH_MAX];
>>> +       int fd = -1;
>>> +
>>> +       if (!dso || (elf_version(EV_CURRENT) == EV_NONE))
>>> +               goto exit;      // false
>>> +
>>> +       dso__build_id_filename(dso, dso_path, sizeof(dso_path), false);
>>> +
>>> +       fd = open(dso_path, O_RDONLY);
>>> +
>>> +       if (fd < 0) {
>>> +               pr_debug("%s: cannot read cached %s.\n", __func__, dso_path);
>>> +               goto exit;      // false
>>> +       }
>>> +
>>> +       elf = elf_begin(fd, ELF_C_READ, NULL);
>>> +       gelf_getehdr(elf, &ehdr);
>>> +
>>> +       if (ehdr.e_type == ET_DYN) {
>>> +               Elf_Data *data;
>>> +               GElf_Dyn *entry;
>>> +               int n_entries = shdr.sh_size / sizeof(GElf_Dyn);
>>> +
>>> +               scn = elf_section_by_name(elf, &ehdr, &shdr, ".dynamic", NULL);
>>> +               if (!scn)
>>> +                       goto exit;      // false
>>
>> It should goto a new tag (e.g. exit_failed) so can invoke elf_end(elf) and
>> close(fd).
>>
>>> +
>>> +               data = (Elf_Data *) elf_getdata(scn, NULL);
>>> +               if (!data || !data->d_buf)
>>> +                       goto exit;      // false
>>
>> Ditto.
>>
>>> +
>>> +               // check DT_FLAGS_1
>>> +               for (int i = 0; i < n_entries; i++) {
>>> +                       entry = ((GElf_Dyn *) data->d_buf) + i;
>>> +                       if (entry->d_tag == DT_FLAGS_1) {
>>> +                               if ((entry->d_un.d_val & DF_1_PIE) != 0) {
>>> +                                       is_pie = true;
>>> +                                       break;
>>> +                               }
>>> +                       }
>>> +               } // end for
>>> +       }
>>> +
>>
>> Put 'exit_failed' tag at here.
>>
>> With the changes:
>>
>> Reviewed-by: Leo Yan <leo.yan@arm.com>
>>
>>> +       elf_end(elf);
>>> +       close(fd);
>>> +exit:
>>> +       return is_pie;
>>> +}
>>> +
> 
> Hi Leo,
> 
> It's been a long time since I've seen goto's used as a rule rather than
> an exception. I see it introduced the problem you've mentioned.

I am not sure if I understand this. In the Linux code, it is quite common to
use goto to handle failure cases (for releasing resources).

> Is it ok to simply update the cover letter (patch 0), and this one (patch 1)
> as V5? If I don't hear from you, I'll resubmit all.

I assume you also need to address patch 03? It is good to send the all patches
in one go, this would be easier for maintainers to pick up the whole series
(e.g. using b4).

Thanks,
Leo
diff mbox series

Patch

diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index e398abfd13a0..0e49c1345a67 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -662,6 +662,66 @@  static int dso__synthesize_plt_got_symbols(struct dso *dso, Elf *elf,
 	return err;
 }
 
+/*
+ * Check dynamic section DT_FLAGS_1 for a Position Independent
+ * Executable (PIE).
+ */
+bool dso__is_pie(struct dso *dso)
+{
+	Elf *elf = NULL;
+	Elf_Scn *scn = NULL;
+	GElf_Ehdr ehdr;
+	GElf_Shdr shdr;
+	bool is_pie = false;
+	char dso_path[PATH_MAX];
+	int fd = -1;
+
+	if (!dso || (elf_version(EV_CURRENT) == EV_NONE))
+		goto exit;	// false
+
+	dso__build_id_filename(dso, dso_path, sizeof(dso_path), false);
+
+	fd = open(dso_path, O_RDONLY);
+
+	if (fd < 0) {
+		pr_debug("%s: cannot read cached %s.\n", __func__, dso_path);
+		goto exit;	// false
+	}
+
+	elf = elf_begin(fd, ELF_C_READ, NULL);
+	gelf_getehdr(elf, &ehdr);
+
+	if (ehdr.e_type == ET_DYN) {
+		Elf_Data *data;
+		GElf_Dyn *entry;
+		int n_entries = shdr.sh_size / sizeof(GElf_Dyn);
+
+		scn = elf_section_by_name(elf, &ehdr, &shdr, ".dynamic", NULL);
+		if (!scn)
+			goto exit;	// false
+
+		data = (Elf_Data *) elf_getdata(scn, NULL);
+		if (!data || !data->d_buf)
+			goto exit;	// false
+
+		// check DT_FLAGS_1
+		for (int i = 0; i < n_entries; i++) {
+			entry = ((GElf_Dyn *) data->d_buf) + i;
+			if (entry->d_tag == DT_FLAGS_1) {
+				if ((entry->d_un.d_val & DF_1_PIE) != 0) {
+					is_pie = true;
+					break;
+				}
+			}
+		} // end for
+	}
+
+	elf_end(elf);
+	close(fd);
+exit:
+	return is_pie;
+}
+
 /*
  * We need to check if we have a .dynsym, so that we can handle the
  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 3fb5d146d9b1..33ea2596ce31 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -127,6 +127,7 @@  void dso__insert_symbol(struct dso *dso,
 			struct symbol *sym);
 void dso__delete_symbol(struct dso *dso,
 			struct symbol *sym);
+bool dso__is_pie(struct dso *dso);
 
 struct symbol *dso__find_symbol(struct dso *dso, u64 addr);
 struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr);