Mark Wielaard 307d23
From 3aca5b5f1f1617db2220022d9061dcaf129e54c4 Mon Sep 17 00:00:00 2001
Mark Wielaard 307d23
From: Mark Wielaard <mark@klomp.org>
Mark Wielaard 307d23
Date: Wed, 21 Jun 2023 18:05:12 +0200
Mark Wielaard 307d23
Subject: [PATCH] libelf: Replace list of elf_getdata_rawchunk results with a
Mark Wielaard 307d23
 tree
Mark Wielaard 307d23
Mark Wielaard 307d23
elf_getdata_rawchunks did a linear search to see if a chunk was
Mark Wielaard 307d23
already fetched. Replace this list with a binary search tree to make
Mark Wielaard 307d23
lookup faster when a lot of Elf_Data_Chunk were created.
Mark Wielaard 307d23
Mark Wielaard 307d23
       * libelf/libelfP.h (Elf_Data_Chunk): Remove next field.
Mark Wielaard 307d23
       (struct Elf): Change the rawchunks type from Elf_Data_Chunk *
Mark Wielaard 307d23
       to void *.
Mark Wielaard 307d23
       * elf_getdata_rawchunk.c (chunk_compare): New static function.
Mark Wielaard 307d23
       (elf_getdata_rawchunk): Use tsearch instead of a manual linked
Mark Wielaard 307d23
       list.
Mark Wielaard 307d23
       * elf_end.c (free_chunk): New static function.
Mark Wielaard 307d23
       (elf_end): Call tdestroy instead of walking linked list.
Mark Wielaard 307d23
Mark Wielaard 307d23
Signed-off-by: Mark Wielaard <mark@klomp.org>
Mark Wielaard 307d23
---
Mark Wielaard 307d23
 libelf/elf_end.c              | 22 +++++++++-------
Mark Wielaard 307d23
 libelf/elf_getdata_rawchunk.c | 47 +++++++++++++++++++++++++----------
Mark Wielaard 307d23
 libelf/libelfP.h              | 13 ++++------
Mark Wielaard 307d23
 3 files changed, 52 insertions(+), 30 deletions(-)
Mark Wielaard 307d23
Mark Wielaard 307d23
diff --git a/libelf/elf_end.c b/libelf/elf_end.c
Mark Wielaard 307d23
index 5c451f36..3e5d4c86 100644
Mark Wielaard 307d23
--- a/libelf/elf_end.c
Mark Wielaard 307d23
+++ b/libelf/elf_end.c
Mark Wielaard 307d23
@@ -1,5 +1,6 @@
Mark Wielaard 307d23
 /* Free resources associated with Elf descriptor.
Mark Wielaard 307d23
    Copyright (C) 1998,1999,2000,2001,2002,2004,2005,2007,2015,2016 Red Hat, Inc.
Mark Wielaard 307d23
+   Copyright (C) 2023 Mark J. Wielaard <mark@klomp.org>
Mark Wielaard 307d23
    This file is part of elfutils.
Mark Wielaard 307d23
    Written by Ulrich Drepper <drepper@redhat.com>, 1998.
Mark Wielaard 307d23
 
Mark Wielaard 307d23
@@ -32,12 +33,22 @@
Mark Wielaard 307d23
 #endif
Mark Wielaard 307d23
 
Mark Wielaard 307d23
 #include <assert.h>
Mark Wielaard 307d23
+#include <search.h>
Mark Wielaard 307d23
 #include <stddef.h>
Mark Wielaard 307d23
 #include <stdlib.h>
Mark Wielaard 307d23
 
Mark Wielaard 307d23
 #include "libelfP.h"
Mark Wielaard 307d23
 
Mark Wielaard 307d23
 
Mark Wielaard 307d23
+static void
Mark Wielaard 307d23
+free_chunk (void *n)
Mark Wielaard 307d23
+{
Mark Wielaard 307d23
+  Elf_Data_Chunk *rawchunk = (Elf_Data_Chunk *)n;
Mark Wielaard 307d23
+  if (rawchunk->dummy_scn.flags & ELF_F_MALLOCED)
Mark Wielaard 307d23
+    free (rawchunk->data.d.d_buf);
Mark Wielaard 307d23
+  free (rawchunk);
Mark Wielaard 307d23
+}
Mark Wielaard 307d23
+
Mark Wielaard 307d23
 int
Mark Wielaard 307d23
 elf_end (Elf *elf)
Mark Wielaard 307d23
 {
Mark Wielaard 307d23
@@ -112,20 +123,13 @@ elf_end (Elf *elf)
Mark Wielaard 307d23
 
Mark Wielaard 307d23
     case ELF_K_ELF:
Mark Wielaard 307d23
       {
Mark Wielaard 307d23
-	Elf_Data_Chunk *rawchunks
Mark Wielaard 307d23
+	void *rawchunks
Mark Wielaard 307d23
 	  = (elf->class == ELFCLASS32
Mark Wielaard 307d23
 	     || (offsetof (struct Elf, state.elf32.rawchunks)
Mark Wielaard 307d23
 		 == offsetof (struct Elf, state.elf64.rawchunks))
Mark Wielaard 307d23
 	     ? elf->state.elf32.rawchunks
Mark Wielaard 307d23
 	     : elf->state.elf64.rawchunks);
Mark Wielaard 307d23
-	while (rawchunks != NULL)
Mark Wielaard 307d23
-	  {
Mark Wielaard 307d23
-	    Elf_Data_Chunk *next = rawchunks->next;
Mark Wielaard 307d23
-	    if (rawchunks->dummy_scn.flags & ELF_F_MALLOCED)
Mark Wielaard 307d23
-	      free (rawchunks->data.d.d_buf);
Mark Wielaard 307d23
-	    free (rawchunks);
Mark Wielaard 307d23
-	    rawchunks = next;
Mark Wielaard 307d23
-	  }
Mark Wielaard 307d23
+	tdestroy (rawchunks, free_chunk);
Mark Wielaard 307d23
 
Mark Wielaard 307d23
 	Elf_ScnList *list = (elf->class == ELFCLASS32
Mark Wielaard 307d23
 			     || (offsetof (struct Elf, state.elf32.scns)
Mark Wielaard 307d23
diff --git a/libelf/elf_getdata_rawchunk.c b/libelf/elf_getdata_rawchunk.c
Mark Wielaard 307d23
index 5a35ccdc..cfd40396 100644
Mark Wielaard 307d23
--- a/libelf/elf_getdata_rawchunk.c
Mark Wielaard 307d23
+++ b/libelf/elf_getdata_rawchunk.c
Mark Wielaard 307d23
@@ -1,6 +1,6 @@
Mark Wielaard 307d23
 /* Return converted data from raw chunk of ELF file.
Mark Wielaard 307d23
    Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
Mark Wielaard 307d23
-   Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
Mark Wielaard 307d23
+   Copyright (C) 2022, 2023 Mark J. Wielaard <mark@klomp.org>
Mark Wielaard 307d23
    This file is part of elfutils.
Mark Wielaard 307d23
 
Mark Wielaard 307d23
    This file is free software; you can redistribute it and/or modify
Mark Wielaard 307d23
@@ -33,12 +33,28 @@
Mark Wielaard 307d23
 
Mark Wielaard 307d23
 #include <assert.h>
Mark Wielaard 307d23
 #include <errno.h>
Mark Wielaard 307d23
+#include <search.h>
Mark Wielaard 307d23
 #include <stdlib.h>
Mark Wielaard 307d23
 #include <string.h>
Mark Wielaard 307d23
 
Mark Wielaard 307d23
 #include "libelfP.h"
Mark Wielaard 307d23
 #include "common.h"
Mark Wielaard 307d23
 
Mark Wielaard 307d23
+static int
Mark Wielaard 307d23
+chunk_compare (const void *a, const void *b)
Mark Wielaard 307d23
+{
Mark Wielaard 307d23
+  Elf_Data_Chunk *da = (Elf_Data_Chunk *)a;
Mark Wielaard 307d23
+  Elf_Data_Chunk *db = (Elf_Data_Chunk *)b;
Mark Wielaard 307d23
+
Mark Wielaard 307d23
+  if (da->offset != db->offset)
Mark Wielaard 307d23
+    return da->offset - db->offset;
Mark Wielaard 307d23
+
Mark Wielaard 307d23
+  if (da->data.d.d_size != db->data.d.d_size)
Mark Wielaard 307d23
+    return da->data.d.d_size - db->data.d.d_size;
Mark Wielaard 307d23
+
Mark Wielaard 307d23
+  return da->data.d.d_type - db->data.d.d_type;
Mark Wielaard 307d23
+}
Mark Wielaard 307d23
+
Mark Wielaard 307d23
 Elf_Data *
Mark Wielaard 307d23
 elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
Mark Wielaard 307d23
 {
Mark Wielaard 307d23
@@ -75,19 +91,25 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
Mark Wielaard 307d23
   rwlock_rdlock (elf->lock);
Mark Wielaard 307d23
 
Mark Wielaard 307d23
   /* Maybe we already got this chunk?  */
Mark Wielaard 307d23
-  Elf_Data_Chunk *rawchunks = elf->state.elf.rawchunks;
Mark Wielaard 307d23
-  while (rawchunks != NULL)
Mark Wielaard 307d23
+  Elf_Data_Chunk key;
Mark Wielaard 307d23
+  key.offset = offset;
Mark Wielaard 307d23
+  key.data.d.d_size = size;
Mark Wielaard 307d23
+  key.data.d.d_type = type;
Mark Wielaard 307d23
+  Elf_Data_Chunk **found = tsearch (&key, &elf->state.elf.rawchunks,
Mark Wielaard 307d23
+				    &chunk_compare);
Mark Wielaard 307d23
+  if (found == NULL)
Mark Wielaard 307d23
+    goto nomem;
Mark Wielaard 307d23
+
Mark Wielaard 307d23
+  /* Existing entry.  */
Mark Wielaard 307d23
+  if (*found != &key && *found != NULL)
Mark Wielaard 307d23
     {
Mark Wielaard 307d23
-      if ((rawchunks->offset == offset || size == 0)
Mark Wielaard 307d23
-	  && rawchunks->data.d.d_size == size
Mark Wielaard 307d23
-	  && rawchunks->data.d.d_type == type)
Mark Wielaard 307d23
-	{
Mark Wielaard 307d23
-	  result = &rawchunks->data.d;
Mark Wielaard 307d23
-	  goto out;
Mark Wielaard 307d23
-	}
Mark Wielaard 307d23
-      rawchunks = rawchunks->next;
Mark Wielaard 307d23
+      result = &(*found)->data.d;
Mark Wielaard 307d23
+      goto out;
Mark Wielaard 307d23
     }
Mark Wielaard 307d23
 
Mark Wielaard 307d23
+  /* New entry.  */
Mark Wielaard 307d23
+  *found = NULL;
Mark Wielaard 307d23
+
Mark Wielaard 307d23
   size_t align = __libelf_type_align (elf->class, type);
Mark Wielaard 307d23
   if (elf->map_address != NULL)
Mark Wielaard 307d23
     {
Mark Wielaard 307d23
@@ -189,8 +211,7 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
Mark Wielaard 307d23
   rwlock_unlock (elf->lock);
Mark Wielaard 307d23
   rwlock_wrlock (elf->lock);
Mark Wielaard 307d23
 
Mark Wielaard 307d23
-  chunk->next = elf->state.elf.rawchunks;
Mark Wielaard 307d23
-  elf->state.elf.rawchunks = chunk;
Mark Wielaard 307d23
+  *found = chunk;
Mark Wielaard 307d23
   result = &chunk->data.d;
Mark Wielaard 307d23
 
Mark Wielaard 307d23
  out:
Mark Wielaard 307d23
diff --git a/libelf/libelfP.h b/libelf/libelfP.h
Mark Wielaard 307d23
index 6624f38a..d3c241e5 100644
Mark Wielaard 307d23
--- a/libelf/libelfP.h
Mark Wielaard 307d23
+++ b/libelf/libelfP.h
Mark Wielaard 307d23
@@ -1,5 +1,6 @@
Mark Wielaard 307d23
 /* Internal interfaces for libelf.
Mark Wielaard 307d23
    Copyright (C) 1998-2010, 2015, 2016 Red Hat, Inc.
Mark Wielaard 307d23
+   Copyright (C) 2023 Mark J. Wielaard <mark@klomp.org>
Mark Wielaard 307d23
    This file is part of elfutils.
Mark Wielaard 307d23
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
Mark Wielaard 307d23
 
Mark Wielaard 307d23
@@ -262,11 +263,7 @@ typedef struct Elf_ScnList
Mark Wielaard 307d23
 typedef struct Elf_Data_Chunk
Mark Wielaard 307d23
 {
Mark Wielaard 307d23
   Elf_Data_Scn data;
Mark Wielaard 307d23
-  union
Mark Wielaard 307d23
-  {
Mark Wielaard 307d23
-    Elf_Scn dummy_scn;
Mark Wielaard 307d23
-    struct Elf_Data_Chunk *next;
Mark Wielaard 307d23
-  };
Mark Wielaard 307d23
+  Elf_Scn dummy_scn;
Mark Wielaard 307d23
   int64_t offset;		/* The original raw offset in the Elf image.  */
Mark Wielaard 307d23
 } Elf_Data_Chunk;
Mark Wielaard 307d23
 
Mark Wielaard 307d23
@@ -324,7 +321,7 @@ struct Elf
Mark Wielaard 307d23
       Elf_ScnList *scns_last;	/* Last element in the section list.
Mark Wielaard 307d23
 				   If NULL the data has not yet been
Mark Wielaard 307d23
 				   read from the file.  */
Mark Wielaard 307d23
-      Elf_Data_Chunk *rawchunks; /* List of elf_getdata_rawchunk results.  */
Mark Wielaard 307d23
+      void *rawchunks;		/* Tree of elf_getdata_rawchunk results.  */
Mark Wielaard 307d23
       unsigned int scnincr;	/* Number of sections allocate the last
Mark Wielaard 307d23
 				   time.  */
Mark Wielaard 307d23
       int ehdr_flags;		/* Flags (dirty) for ELF header.  */
Mark Wielaard 307d23
@@ -343,7 +340,7 @@ struct Elf
Mark Wielaard 307d23
       Elf_ScnList *scns_last;	/* Last element in the section list.
Mark Wielaard 307d23
 				   If NULL the data has not yet been
Mark Wielaard 307d23
 				   read from the file.  */
Mark Wielaard 307d23
-      Elf_Data_Chunk *rawchunks; /* List of elf_getdata_rawchunk results.  */
Mark Wielaard 307d23
+      void *rawchunks;		/* Tree of elf_getdata_rawchunk results.  */
Mark Wielaard 307d23
       unsigned int scnincr;	/* Number of sections allocate the last
Mark Wielaard 307d23
 				   time.  */
Mark Wielaard 307d23
       int ehdr_flags;		/* Flags (dirty) for ELF header.  */
Mark Wielaard 307d23
@@ -368,7 +365,7 @@ struct Elf
Mark Wielaard 307d23
       Elf_ScnList *scns_last;	/* Last element in the section list.
Mark Wielaard 307d23
 				   If NULL the data has not yet been
Mark Wielaard 307d23
 				   read from the file.  */
Mark Wielaard 307d23
-      Elf_Data_Chunk *rawchunks; /* List of elf_getdata_rawchunk results.  */
Mark Wielaard 307d23
+      void *rawchunks;		/* Tree of elf_getdata_rawchunk results.  */
Mark Wielaard 307d23
       unsigned int scnincr;	/* Number of sections allocate the last
Mark Wielaard 307d23
 				   time.  */
Mark Wielaard 307d23
       int ehdr_flags;		/* Flags (dirty) for ELF header.  */
Mark Wielaard 307d23
-- 
Mark Wielaard 307d23
2.40.1
Mark Wielaard 307d23