Add an API that can parse the build ID out of a buffer, instead of a
vma, to support printing a kernel module's build ID for stack traces.

Cc: Jiri Olsa <jo...@kernel.org>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Jessica Yu <j...@kernel.org>
Cc: Evan Green <evgr...@chromium.org>
Cc: Hsin-Yi Wang <hsi...@chromium.org>
Signed-off-by: Stephen Boyd <swb...@chromium.org>
---
 include/linux/buildid.h |  1 +
 lib/buildid.c           | 50 ++++++++++++++++++++++++++++++-----------
 2 files changed, 38 insertions(+), 13 deletions(-)

diff --git a/include/linux/buildid.h b/include/linux/buildid.h
index 40232f90db6e..ebce93f26d06 100644
--- a/include/linux/buildid.h
+++ b/include/linux/buildid.h
@@ -8,5 +8,6 @@
 
 int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id,
                   __u32 *size);
+int build_id_parse_buf(const void *buf, unsigned char *build_id, u32 buf_size);
 
 #endif
diff --git a/lib/buildid.c b/lib/buildid.c
index 6156997c3895..010ab0674cb9 100644
--- a/lib/buildid.c
+++ b/lib/buildid.c
@@ -2,30 +2,23 @@
 
 #include <linux/buildid.h>
 #include <linux/elf.h>
+#include <linux/kernel.h>
 #include <linux/pagemap.h>
 
 #define BUILD_ID 3
+
 /*
  * Parse build id from the note segment. This logic can be shared between
  * 32-bit and 64-bit system, because Elf32_Nhdr and Elf64_Nhdr are
  * identical.
  */
-static inline int parse_build_id(void *page_addr,
-                                unsigned char *build_id,
-                                __u32 *size,
-                                void *note_start,
-                                Elf32_Word note_size)
+static int parse_build_id_buf(unsigned char *build_id,
+                             __u32 *size,
+                             const void *note_start,
+                             Elf32_Word note_size)
 {
        Elf32_Word note_offs = 0, new_offs;
 
-       /* check for overflow */
-       if (note_start < page_addr || note_start + note_size < note_start)
-               return -EINVAL;
-
-       /* only supports note that fits in the first page */
-       if (note_start + note_size > page_addr + PAGE_SIZE)
-               return -EINVAL;
-
        while (note_offs + sizeof(Elf32_Nhdr) < note_size) {
                Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs);
 
@@ -49,9 +42,27 @@ static inline int parse_build_id(void *page_addr,
                        break;
                note_offs = new_offs;
        }
+
        return -EINVAL;
 }
 
+static inline int parse_build_id(void *page_addr,
+                                unsigned char *build_id,
+                                __u32 *size,
+                                void *note_start,
+                                Elf32_Word note_size)
+{
+       /* check for overflow */
+       if (note_start < page_addr || note_start + note_size < note_start)
+               return -EINVAL;
+
+       /* only supports note that fits in the first page */
+       if (note_start + note_size > page_addr + PAGE_SIZE)
+               return -EINVAL;
+
+       return parse_build_id_buf(build_id, size, note_start, note_size);
+}
+
 /* Parse build ID from 32-bit ELF */
 static int get_build_id_32(void *page_addr, unsigned char *build_id,
                           __u32 *size)
@@ -147,3 +158,16 @@ int build_id_parse(struct vm_area_struct *vma, unsigned 
char *build_id,
        put_page(page);
        return ret;
 }
+
+/**
+ * build_id_parse_buf - Get build ID from a buffer
+ * @buf:      Elf note section(s) to parse
+ * @buf_size: Size of @buf in bytes
+ * @build_id: Build ID parsed from @buf, at least BUILD_ID_SIZE_MAX long
+ *
+ * Return: 0 on success, -EINVAL otherwise
+ */
+int build_id_parse_buf(const void *buf, unsigned char *build_id, u32 buf_size)
+{
+       return parse_build_id_buf(build_id, NULL, buf, buf_size);
+}
-- 
https://chromeos.dev

Reply via email to