1 /* Append new section.
2    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc.
3    This file is part of elfutils.
4    Written by Ulrich Drepper <drepper@redhat.com>, 1998.
5 
6    This file is free software; you can redistribute it and/or modify
7    it under the terms of either
8 
9      * the GNU Lesser General Public License as published by the Free
10        Software Foundation; either version 3 of the License, or (at
11        your option) any later version
12 
13    or
14 
15      * the GNU General Public License as published by the Free
16        Software Foundation; either version 2 of the License, or (at
17        your option) any later version
18 
19    or both in parallel, as here.
20 
21    elfutils is distributed in the hope that it will be useful, but
22    WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24    General Public License for more details.
25 
26    You should have received copies of the GNU General Public License and
27    the GNU Lesser General Public License along with this program.  If
28    not, see <http://www.gnu.org/licenses/>.  */
29 
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33 
34 #include <assert.h>
35 #include <stdbool.h>
36 #include <stddef.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include "libelfP.h"
41 
42 
43 Elf_Scn *
elf_newscn(elf)44 elf_newscn (elf)
45      Elf *elf;
46 {
47   Elf_Scn *result = NULL;
48   bool first = false;
49 
50   if (elf == NULL)
51     return NULL;
52 
53   /* We rely on the prefix of the `elf', `elf32', and `elf64' element
54      being the same.  */
55   assert (offsetof (Elf, state.elf.scns_last)
56 	  == offsetof (Elf, state.elf32.scns_last));
57   assert (offsetof (Elf, state.elf.scns_last)
58 	  == offsetof (Elf, state.elf64.scns_last));
59   assert (offsetof (Elf, state.elf32.scns)
60 	  == offsetof (Elf, state.elf64.scns));
61 
62   rwlock_wrlock (elf->lock);
63 
64  again:
65   if (elf->state.elf.scns_last->cnt < elf->state.elf.scns_last->max)
66     {
67       result = &elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt];
68 
69       if (++elf->state.elf.scns_last->cnt == 1
70 	  && (elf->state.elf.scns_last
71 	      == (elf->class == ELFCLASS32
72 		  || (offsetof (Elf, state.elf32.scns)
73 		      == offsetof (Elf, state.elf64.scns))
74 		  ? &elf->state.elf32.scns : &elf->state.elf64.scns)))
75 	/* This is zeroth section.  */
76 	first = true;
77       else
78 	{
79 	  assert (elf->state.elf.scns_last->cnt > 1);
80 	  result->index = result[-1].index + 1;
81 	}
82     }
83   else
84     {
85       /* We must allocate a new element.  */
86       Elf_ScnList *newp = NULL;
87 
88       assert (elf->state.elf.scnincr > 0);
89 
90       if (
91 #if SIZE_MAX <= 4294967295U
92 	  likely (elf->state.elf.scnincr
93 		  < SIZE_MAX / 2 / sizeof (Elf_Scn) - sizeof (Elf_ScnList))
94 #else
95 	  1
96 #endif
97 	  )
98       newp = (Elf_ScnList *) calloc (sizeof (Elf_ScnList)
99 				     + ((elf->state.elf.scnincr *= 2)
100 					* sizeof (Elf_Scn)), 1);
101       if (newp == NULL)
102 	{
103 	  __libelf_seterrno (ELF_E_NOMEM);
104 	  goto out;
105 	}
106 
107       result = &newp->data[0];
108 
109       /* One section used.  */
110       ++newp->cnt;
111 
112       /* This is the number of sections we allocated.  */
113       newp->max = elf->state.elf.scnincr;
114 
115       /* Remember the index for the first section in this block.  */
116       newp->data[0].index
117 	= 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->max - 1].index;
118 
119       /* Enqueue the new list element.  */
120       elf->state.elf.scns_last = elf->state.elf.scns_last->next = newp;
121     }
122 
123   /* Create a section header for this section.  */
124   if (elf->class == ELFCLASS32)
125     {
126       result->shdr.e32 = (Elf32_Shdr *) calloc (1, sizeof (Elf32_Shdr));
127       if (result->shdr.e32 == NULL)
128 	{
129 	  __libelf_seterrno (ELF_E_NOMEM);
130 	  goto out;
131 	}
132     }
133   else
134     {
135       result->shdr.e64 = (Elf64_Shdr *) calloc (1, sizeof (Elf64_Shdr));
136       if (result->shdr.e64 == NULL)
137 	{
138 	  __libelf_seterrno (ELF_E_NOMEM);
139 	  goto out;
140 	}
141     }
142 
143   result->elf = elf;
144   result->shdr_flags = ELF_F_DIRTY | ELF_F_MALLOCED;
145   result->list = elf->state.elf.scns_last;
146 
147   /* Initialize the data part.  */
148   result->data_read = 1;
149   if (unlikely (first))
150     {
151       /* For the first section we mark the data as already available.  */
152       //result->data_list_rear = &result->data_list;
153       first = false;
154       goto again;
155     }
156 
157   result->flags |= ELF_F_DIRTY;
158 
159  out:
160   rwlock_unlock (elf->lock);
161 
162   return result;
163 }
164