1313#include <objtool/warn.h>
1414#include <objtool/endianness.h>
1515
16- int create_orc (struct objtool_file * file )
16+ static int init_orc_entry (struct orc_entry * orc , struct cfi_state * cfi )
1717{
18- struct instruction * insn ;
18+ struct instruction * insn = container_of (cfi , struct instruction , cfi );
19+ struct cfi_reg * bp = & cfi -> regs [CFI_BP ];
1920
20- for_each_insn (file , insn ) {
21- struct orc_entry * orc = & insn -> orc ;
22- struct cfi_reg * cfa = & insn -> cfi .cfa ;
23- struct cfi_reg * bp = & insn -> cfi .regs [CFI_BP ];
21+ memset (orc , 0 , sizeof (* orc ));
2422
25- if (!insn -> sec -> text )
26- continue ;
27-
28- orc -> end = insn -> cfi .end ;
23+ orc -> end = cfi -> end ;
2924
30- if (cfa -> base == CFI_UNDEFINED ) {
31- orc -> sp_reg = ORC_REG_UNDEFINED ;
32- continue ;
33- }
34-
35- switch (cfa -> base ) {
36- case CFI_SP :
37- orc -> sp_reg = ORC_REG_SP ;
38- break ;
39- case CFI_SP_INDIRECT :
40- orc -> sp_reg = ORC_REG_SP_INDIRECT ;
41- break ;
42- case CFI_BP :
43- orc -> sp_reg = ORC_REG_BP ;
44- break ;
45- case CFI_BP_INDIRECT :
46- orc -> sp_reg = ORC_REG_BP_INDIRECT ;
47- break ;
48- case CFI_R10 :
49- orc -> sp_reg = ORC_REG_R10 ;
50- break ;
51- case CFI_R13 :
52- orc -> sp_reg = ORC_REG_R13 ;
53- break ;
54- case CFI_DI :
55- orc -> sp_reg = ORC_REG_DI ;
56- break ;
57- case CFI_DX :
58- orc -> sp_reg = ORC_REG_DX ;
59- break ;
60- default :
61- WARN_FUNC ("unknown CFA base reg %d" ,
62- insn -> sec , insn -> offset , cfa -> base );
63- return -1 ;
64- }
25+ if (cfi -> cfa .base == CFI_UNDEFINED ) {
26+ orc -> sp_reg = ORC_REG_UNDEFINED ;
27+ return 0 ;
28+ }
6529
66- switch (bp -> base ) {
67- case CFI_UNDEFINED :
68- orc -> bp_reg = ORC_REG_UNDEFINED ;
69- break ;
70- case CFI_CFA :
71- orc -> bp_reg = ORC_REG_PREV_SP ;
72- break ;
73- case CFI_BP :
74- orc -> bp_reg = ORC_REG_BP ;
75- break ;
76- default :
77- WARN_FUNC ("unknown BP base reg %d" ,
78- insn -> sec , insn -> offset , bp -> base );
79- return -1 ;
80- }
30+ switch (cfi -> cfa .base ) {
31+ case CFI_SP :
32+ orc -> sp_reg = ORC_REG_SP ;
33+ break ;
34+ case CFI_SP_INDIRECT :
35+ orc -> sp_reg = ORC_REG_SP_INDIRECT ;
36+ break ;
37+ case CFI_BP :
38+ orc -> sp_reg = ORC_REG_BP ;
39+ break ;
40+ case CFI_BP_INDIRECT :
41+ orc -> sp_reg = ORC_REG_BP_INDIRECT ;
42+ break ;
43+ case CFI_R10 :
44+ orc -> sp_reg = ORC_REG_R10 ;
45+ break ;
46+ case CFI_R13 :
47+ orc -> sp_reg = ORC_REG_R13 ;
48+ break ;
49+ case CFI_DI :
50+ orc -> sp_reg = ORC_REG_DI ;
51+ break ;
52+ case CFI_DX :
53+ orc -> sp_reg = ORC_REG_DX ;
54+ break ;
55+ default :
56+ WARN_FUNC ("unknown CFA base reg %d" ,
57+ insn -> sec , insn -> offset , cfi -> cfa .base );
58+ return -1 ;
59+ }
8160
82- orc -> sp_offset = cfa -> offset ;
83- orc -> bp_offset = bp -> offset ;
84- orc -> type = insn -> cfi .type ;
61+ switch (bp -> base ) {
62+ case CFI_UNDEFINED :
63+ orc -> bp_reg = ORC_REG_UNDEFINED ;
64+ break ;
65+ case CFI_CFA :
66+ orc -> bp_reg = ORC_REG_PREV_SP ;
67+ break ;
68+ case CFI_BP :
69+ orc -> bp_reg = ORC_REG_BP ;
70+ break ;
71+ default :
72+ WARN_FUNC ("unknown BP base reg %d" ,
73+ insn -> sec , insn -> offset , bp -> base );
74+ return -1 ;
8575 }
8676
77+ orc -> sp_offset = cfi -> cfa .offset ;
78+ orc -> bp_offset = bp -> offset ;
79+ orc -> type = cfi -> type ;
80+
8781 return 0 ;
8882}
8983
90- static int create_orc_entry (struct elf * elf , struct section * u_sec , struct section * ip_relocsec ,
91- unsigned int idx , struct section * insn_sec ,
92- unsigned long insn_off , struct orc_entry * o )
84+ static int write_orc_entry (struct elf * elf , struct section * orc_sec ,
85+ struct section * ip_rsec , unsigned int idx ,
86+ struct section * insn_sec , unsigned long insn_off ,
87+ struct orc_entry * o )
9388{
9489 struct orc_entry * orc ;
9590 struct reloc * reloc ;
9691
9792 /* populate ORC data */
98- orc = (struct orc_entry * )u_sec -> data -> d_buf + idx ;
93+ orc = (struct orc_entry * )orc_sec -> data -> d_buf + idx ;
9994 memcpy (orc , o , sizeof (* orc ));
10095 orc -> sp_offset = bswap_if_needed (orc -> sp_offset );
10196 orc -> bp_offset = bswap_if_needed (orc -> bp_offset );
@@ -117,102 +112,109 @@ static int create_orc_entry(struct elf *elf, struct section *u_sec, struct secti
117112
118113 reloc -> type = R_X86_64_PC32 ;
119114 reloc -> offset = idx * sizeof (int );
120- reloc -> sec = ip_relocsec ;
115+ reloc -> sec = ip_rsec ;
121116
122117 elf_add_reloc (elf , reloc );
123118
124119 return 0 ;
125120}
126121
127- int create_orc_sections (struct objtool_file * file )
122+ struct orc_list_entry {
123+ struct list_head list ;
124+ struct orc_entry orc ;
125+ struct section * insn_sec ;
126+ unsigned long insn_off ;
127+ };
128+
129+ static int orc_list_add (struct list_head * orc_list , struct orc_entry * orc ,
130+ struct section * sec , unsigned long offset )
131+ {
132+ struct orc_list_entry * entry = malloc (sizeof (* entry ));
133+
134+ if (!entry ) {
135+ WARN ("malloc failed" );
136+ return -1 ;
137+ }
138+
139+ entry -> orc = * orc ;
140+ entry -> insn_sec = sec ;
141+ entry -> insn_off = offset ;
142+
143+ list_add_tail (& entry -> list , orc_list );
144+ return 0 ;
145+ }
146+
147+ int orc_create (struct objtool_file * file )
128148{
129- struct instruction * insn , * prev_insn ;
130- struct section * sec , * u_sec , * ip_relocsec ;
131- unsigned int idx ;
149+ struct section * sec , * ip_rsec , * orc_sec ;
150+ unsigned int nr = 0 , idx = 0 ;
151+ struct orc_list_entry * entry ;
152+ struct list_head orc_list ;
132153
133- struct orc_entry empty = {
134- .sp_reg = ORC_REG_UNDEFINED ,
154+ struct orc_entry null = {
155+ .sp_reg = ORC_REG_UNDEFINED ,
135156 .bp_reg = ORC_REG_UNDEFINED ,
136157 .type = UNWIND_HINT_TYPE_CALL ,
137158 };
138159
139- sec = find_section_by_name (file -> elf , ".orc_unwind" );
140- if (sec ) {
141- WARN ("file already has .orc_unwind section, skipping" );
142- return -1 ;
143- }
144-
145- /* count the number of needed orcs */
146- idx = 0 ;
160+ /* Build a deduplicated list of ORC entries: */
161+ INIT_LIST_HEAD (& orc_list );
147162 for_each_sec (file , sec ) {
163+ struct orc_entry orc , prev_orc = {0 };
164+ struct instruction * insn ;
165+ bool empty = true;
166+
148167 if (!sec -> text )
149168 continue ;
150169
151- prev_insn = NULL ;
152170 sec_for_each_insn (file , sec , insn ) {
153- if (!prev_insn ||
154- memcmp (& insn -> orc , & prev_insn -> orc ,
155- sizeof (struct orc_entry ))) {
156- idx ++ ;
157- }
158- prev_insn = insn ;
171+ if (init_orc_entry (& orc , & insn -> cfi ))
172+ return -1 ;
173+ if (!memcmp (& prev_orc , & orc , sizeof (orc )))
174+ continue ;
175+ if (orc_list_add (& orc_list , & orc , sec , insn -> offset ))
176+ return -1 ;
177+ nr ++ ;
178+ prev_orc = orc ;
179+ empty = false;
159180 }
160181
161- /* section terminator */
162- if (prev_insn )
163- idx ++ ;
182+ /* Add a section terminator */
183+ if (!empty ) {
184+ orc_list_add (& orc_list , & null , sec , sec -> len );
185+ nr ++ ;
186+ }
164187 }
165- if (!idx )
166- return -1 ;
188+ if (!nr )
189+ return 0 ;
167190
191+ /* Create .orc_unwind, .orc_unwind_ip and .rela.orc_unwind_ip sections: */
192+ sec = find_section_by_name (file -> elf , ".orc_unwind" );
193+ if (sec ) {
194+ WARN ("file already has .orc_unwind section, skipping" );
195+ return -1 ;
196+ }
197+ orc_sec = elf_create_section (file -> elf , ".orc_unwind" , 0 ,
198+ sizeof (struct orc_entry ), nr );
199+ if (!orc_sec )
200+ return -1 ;
168201
169- /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */
170- sec = elf_create_section (file -> elf , ".orc_unwind_ip" , 0 , sizeof (int ), idx );
202+ sec = elf_create_section (file -> elf , ".orc_unwind_ip" , 0 , sizeof (int ), nr );
171203 if (!sec )
172204 return -1 ;
173-
174- ip_relocsec = elf_create_reloc_section (file -> elf , sec , SHT_RELA );
175- if (!ip_relocsec )
205+ ip_rsec = elf_create_reloc_section (file -> elf , sec , SHT_RELA );
206+ if (!ip_rsec )
176207 return -1 ;
177208
178- /* create .orc_unwind section */
179- u_sec = elf_create_section (file -> elf , ".orc_unwind" , 0 ,
180- sizeof (struct orc_entry ), idx );
181-
182- /* populate sections */
183- idx = 0 ;
184- for_each_sec (file , sec ) {
185- if (!sec -> text )
186- continue ;
187-
188- prev_insn = NULL ;
189- sec_for_each_insn (file , sec , insn ) {
190- if (!prev_insn || memcmp (& insn -> orc , & prev_insn -> orc ,
191- sizeof (struct orc_entry ))) {
192-
193- if (create_orc_entry (file -> elf , u_sec , ip_relocsec , idx ,
194- insn -> sec , insn -> offset ,
195- & insn -> orc ))
196- return -1 ;
197-
198- idx ++ ;
199- }
200- prev_insn = insn ;
201- }
202-
203- /* section terminator */
204- if (prev_insn ) {
205- if (create_orc_entry (file -> elf , u_sec , ip_relocsec , idx ,
206- prev_insn -> sec ,
207- prev_insn -> offset + prev_insn -> len ,
208- & empty ))
209- return -1 ;
210-
211- idx ++ ;
212- }
209+ /* Write ORC entries to sections: */
210+ list_for_each_entry (entry , & orc_list , list ) {
211+ if (write_orc_entry (file -> elf , orc_sec , ip_rsec , idx ++ ,
212+ entry -> insn_sec , entry -> insn_off ,
213+ & entry -> orc ))
214+ return -1 ;
213215 }
214216
215- if (elf_rebuild_reloc_section (file -> elf , ip_relocsec ))
217+ if (elf_rebuild_reloc_section (file -> elf , ip_rsec ))
216218 return -1 ;
217219
218220 return 0 ;
0 commit comments