xref: /third_party/elfutils/src/elfclassify.c (revision da0c48c4)
1da0c48c4Sopenharmony_ci/* Classification of ELF files.
2da0c48c4Sopenharmony_ci   Copyright (C) 2019 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of the GNU General Public License as published by
7da0c48c4Sopenharmony_ci   the Free Software Foundation; either version 3 of the License, or
8da0c48c4Sopenharmony_ci   (at your option) any later version.
9da0c48c4Sopenharmony_ci
10da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
11da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
12da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13da0c48c4Sopenharmony_ci   GNU General Public License for more details.
14da0c48c4Sopenharmony_ci
15da0c48c4Sopenharmony_ci   You should have received a copy of the GNU General Public License
16da0c48c4Sopenharmony_ci   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci#include <config.h>
19da0c48c4Sopenharmony_ci#include <system.h>
20da0c48c4Sopenharmony_ci
21da0c48c4Sopenharmony_ci#include <argp.h>
22da0c48c4Sopenharmony_ci#include <fcntl.h>
23da0c48c4Sopenharmony_ci#include <gelf.h>
24da0c48c4Sopenharmony_ci#include <stdbool.h>
25da0c48c4Sopenharmony_ci#include <stddef.h>
26da0c48c4Sopenharmony_ci#include <stdio.h>
27da0c48c4Sopenharmony_ci#include <stdlib.h>
28da0c48c4Sopenharmony_ci#include <string.h>
29da0c48c4Sopenharmony_ci#include <sys/stat.h>
30da0c48c4Sopenharmony_ci#include <unistd.h>
31da0c48c4Sopenharmony_ci
32da0c48c4Sopenharmony_ci#include ELFUTILS_HEADER(elf)
33da0c48c4Sopenharmony_ci#include ELFUTILS_HEADER(dwelf)
34da0c48c4Sopenharmony_ci#include "printversion.h"
35da0c48c4Sopenharmony_ci
36da0c48c4Sopenharmony_ci/* Name and version of program.  */
37da0c48c4Sopenharmony_ciARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
38da0c48c4Sopenharmony_ci
39da0c48c4Sopenharmony_ci/* Bug report address.  */
40da0c48c4Sopenharmony_ciARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
41da0c48c4Sopenharmony_ci
42da0c48c4Sopenharmony_ci/* Set by parse_opt.  */
43da0c48c4Sopenharmony_cistatic int verbose;
44da0c48c4Sopenharmony_ci
45da0c48c4Sopenharmony_ci/* Set by the main function.  */
46da0c48c4Sopenharmony_cistatic const char *current_path;
47da0c48c4Sopenharmony_ci
48da0c48c4Sopenharmony_ci/* Set by open_file.  */
49da0c48c4Sopenharmony_cistatic int file_fd = -1;
50da0c48c4Sopenharmony_ci
51da0c48c4Sopenharmony_ci/* Set by issue or elf_issue.  */
52da0c48c4Sopenharmony_cistatic bool issue_found;
53da0c48c4Sopenharmony_ci
54da0c48c4Sopenharmony_ci/* Non-fatal issue occurred while processing the current_path.  */
55da0c48c4Sopenharmony_cistatic void
56da0c48c4Sopenharmony_ciissue (int e, const char *msg)
57da0c48c4Sopenharmony_ci{
58da0c48c4Sopenharmony_ci  if (verbose >= 0)
59da0c48c4Sopenharmony_ci    {
60da0c48c4Sopenharmony_ci      if (current_path == NULL)
61da0c48c4Sopenharmony_ci	error (0, e, "%s", msg);
62da0c48c4Sopenharmony_ci      else
63da0c48c4Sopenharmony_ci	error (0, e, "%s '%s'", msg, current_path);
64da0c48c4Sopenharmony_ci    }
65da0c48c4Sopenharmony_ci  issue_found = true;
66da0c48c4Sopenharmony_ci}
67da0c48c4Sopenharmony_ci
68da0c48c4Sopenharmony_ci/* Non-fatal issue occurred while processing the current ELF.  */
69da0c48c4Sopenharmony_cistatic void
70da0c48c4Sopenharmony_cielf_issue (const char *msg)
71da0c48c4Sopenharmony_ci{
72da0c48c4Sopenharmony_ci  if (verbose >= 0)
73da0c48c4Sopenharmony_ci    error (0, 0, "%s: %s: '%s'", msg, elf_errmsg (-1), current_path);
74da0c48c4Sopenharmony_ci  issue_found = true;
75da0c48c4Sopenharmony_ci}
76da0c48c4Sopenharmony_ci
77da0c48c4Sopenharmony_ci/* Set by parse_opt.  */
78da0c48c4Sopenharmony_cistatic bool flag_only_regular_files;
79da0c48c4Sopenharmony_ci
80da0c48c4Sopenharmony_cistatic bool
81da0c48c4Sopenharmony_ciopen_file (void)
82da0c48c4Sopenharmony_ci{
83da0c48c4Sopenharmony_ci  if (verbose > 1)
84da0c48c4Sopenharmony_ci    fprintf (stderr, "debug: processing file: %s\n", current_path);
85da0c48c4Sopenharmony_ci
86da0c48c4Sopenharmony_ci  file_fd = open (current_path, O_RDONLY | (flag_only_regular_files
87da0c48c4Sopenharmony_ci					    ? O_NOFOLLOW : 0));
88da0c48c4Sopenharmony_ci  if (file_fd < 0)
89da0c48c4Sopenharmony_ci    {
90da0c48c4Sopenharmony_ci      if (!flag_only_regular_files || errno != ELOOP)
91da0c48c4Sopenharmony_ci	issue (errno, N_("opening"));
92da0c48c4Sopenharmony_ci      return false;
93da0c48c4Sopenharmony_ci    }
94da0c48c4Sopenharmony_ci
95da0c48c4Sopenharmony_ci  struct stat st;
96da0c48c4Sopenharmony_ci  if (fstat (file_fd, &st) != 0)
97da0c48c4Sopenharmony_ci    {
98da0c48c4Sopenharmony_ci      issue (errno, N_("reading"));
99da0c48c4Sopenharmony_ci      return false;
100da0c48c4Sopenharmony_ci    }
101da0c48c4Sopenharmony_ci
102da0c48c4Sopenharmony_ci  /* Don't even bother with directories.  */
103da0c48c4Sopenharmony_ci  if (S_ISDIR (st.st_mode)
104da0c48c4Sopenharmony_ci      || (flag_only_regular_files && !S_ISREG (st.st_mode)))
105da0c48c4Sopenharmony_ci    return false;
106da0c48c4Sopenharmony_ci
107da0c48c4Sopenharmony_ci  return true;
108da0c48c4Sopenharmony_ci}
109da0c48c4Sopenharmony_ci
110da0c48c4Sopenharmony_cistatic void
111da0c48c4Sopenharmony_ciclose_file (void)
112da0c48c4Sopenharmony_ci{
113da0c48c4Sopenharmony_ci  if (file_fd >= 0)
114da0c48c4Sopenharmony_ci    {
115da0c48c4Sopenharmony_ci      close (file_fd);
116da0c48c4Sopenharmony_ci      file_fd = -1;
117da0c48c4Sopenharmony_ci    }
118da0c48c4Sopenharmony_ci}
119da0c48c4Sopenharmony_ci
120da0c48c4Sopenharmony_ci/* Set by open_elf.  */
121da0c48c4Sopenharmony_cistatic Elf *elf;
122da0c48c4Sopenharmony_ci
123da0c48c4Sopenharmony_ci/* Set by parse_opt.  */
124da0c48c4Sopenharmony_cistatic bool flag_compressed;
125da0c48c4Sopenharmony_ci
126da0c48c4Sopenharmony_cistatic bool
127da0c48c4Sopenharmony_ciopen_elf (void)
128da0c48c4Sopenharmony_ci{
129da0c48c4Sopenharmony_ci  if (!open_file ())
130da0c48c4Sopenharmony_ci    {
131da0c48c4Sopenharmony_ci      /* Make sure the file descriptor is gone.  */
132da0c48c4Sopenharmony_ci      close_file ();
133da0c48c4Sopenharmony_ci      return false;
134da0c48c4Sopenharmony_ci    }
135da0c48c4Sopenharmony_ci
136da0c48c4Sopenharmony_ci  if (flag_compressed)
137da0c48c4Sopenharmony_ci    elf = dwelf_elf_begin (file_fd);
138da0c48c4Sopenharmony_ci  else
139da0c48c4Sopenharmony_ci    elf = elf_begin (file_fd, ELF_C_READ, NULL);
140da0c48c4Sopenharmony_ci
141da0c48c4Sopenharmony_ci  if (elf == NULL)
142da0c48c4Sopenharmony_ci    {
143da0c48c4Sopenharmony_ci      elf_issue ("opening ELF file");
144da0c48c4Sopenharmony_ci      close_file ();
145da0c48c4Sopenharmony_ci      return false;
146da0c48c4Sopenharmony_ci    }
147da0c48c4Sopenharmony_ci
148da0c48c4Sopenharmony_ci  return true;
149da0c48c4Sopenharmony_ci}
150da0c48c4Sopenharmony_ci
151da0c48c4Sopenharmony_cistatic void
152da0c48c4Sopenharmony_ciclose_elf (void)
153da0c48c4Sopenharmony_ci{
154da0c48c4Sopenharmony_ci  if (elf != NULL)
155da0c48c4Sopenharmony_ci    {
156da0c48c4Sopenharmony_ci      elf_end (elf);
157da0c48c4Sopenharmony_ci      elf = NULL;
158da0c48c4Sopenharmony_ci    }
159da0c48c4Sopenharmony_ci
160da0c48c4Sopenharmony_ci  close_file ();
161da0c48c4Sopenharmony_ci}
162da0c48c4Sopenharmony_ci
163da0c48c4Sopenharmony_cistatic const char *
164da0c48c4Sopenharmony_cielf_kind_string (int kind)
165da0c48c4Sopenharmony_ci{
166da0c48c4Sopenharmony_ci  switch (kind)
167da0c48c4Sopenharmony_ci    {
168da0c48c4Sopenharmony_ci    case ELF_K_NONE:
169da0c48c4Sopenharmony_ci      return "ELF_K_NONE";
170da0c48c4Sopenharmony_ci    case ELF_K_AR:
171da0c48c4Sopenharmony_ci      return "ELF_K_AR";
172da0c48c4Sopenharmony_ci    case ELF_K_COFF:
173da0c48c4Sopenharmony_ci      return "ELF_K_COFF"; /* libelf doesn't really support this.  */
174da0c48c4Sopenharmony_ci    case ELF_K_ELF:
175da0c48c4Sopenharmony_ci      return "ELF_K_ELF";
176da0c48c4Sopenharmony_ci    default:
177da0c48c4Sopenharmony_ci      return "<unknown>";
178da0c48c4Sopenharmony_ci    }
179da0c48c4Sopenharmony_ci}
180da0c48c4Sopenharmony_ci
181da0c48c4Sopenharmony_cistatic const char *
182da0c48c4Sopenharmony_cielf_type_string (int type)
183da0c48c4Sopenharmony_ci{
184da0c48c4Sopenharmony_ci  switch (type)
185da0c48c4Sopenharmony_ci    {
186da0c48c4Sopenharmony_ci    case ET_NONE:
187da0c48c4Sopenharmony_ci      return "ET_NONE";
188da0c48c4Sopenharmony_ci    case ET_REL:
189da0c48c4Sopenharmony_ci      return "ET_REL";
190da0c48c4Sopenharmony_ci    case ET_EXEC:
191da0c48c4Sopenharmony_ci      return "ET_EXEC";
192da0c48c4Sopenharmony_ci    case ET_DYN:
193da0c48c4Sopenharmony_ci      return "ET_DYN";
194da0c48c4Sopenharmony_ci    case ET_CORE:
195da0c48c4Sopenharmony_ci      return "ET_CORE";
196da0c48c4Sopenharmony_ci    default:
197da0c48c4Sopenharmony_ci      return "<unknown>";
198da0c48c4Sopenharmony_ci    }
199da0c48c4Sopenharmony_ci}
200da0c48c4Sopenharmony_ci
201da0c48c4Sopenharmony_cistatic int elf_type;
202da0c48c4Sopenharmony_cistatic bool has_program_load;
203da0c48c4Sopenharmony_cistatic bool has_sections;
204da0c48c4Sopenharmony_cistatic bool has_bits_alloc;
205da0c48c4Sopenharmony_cistatic bool has_program_interpreter;
206da0c48c4Sopenharmony_cistatic bool has_dynamic;
207da0c48c4Sopenharmony_cistatic bool has_soname;
208da0c48c4Sopenharmony_cistatic bool has_pie_flag;
209da0c48c4Sopenharmony_cistatic bool has_dt_debug;
210da0c48c4Sopenharmony_cistatic bool has_symtab;
211da0c48c4Sopenharmony_cistatic bool has_debug_sections;
212da0c48c4Sopenharmony_cistatic bool has_modinfo;
213da0c48c4Sopenharmony_cistatic bool has_gnu_linkonce_this_module;
214da0c48c4Sopenharmony_ci
215da0c48c4Sopenharmony_cistatic bool
216da0c48c4Sopenharmony_cirun_classify (void)
217da0c48c4Sopenharmony_ci{
218da0c48c4Sopenharmony_ci  /* Reset to unanalyzed default.  */
219da0c48c4Sopenharmony_ci  elf_type = 0;
220da0c48c4Sopenharmony_ci  has_program_load = false;
221da0c48c4Sopenharmony_ci  has_sections = false;
222da0c48c4Sopenharmony_ci  has_bits_alloc = false;
223da0c48c4Sopenharmony_ci  has_program_interpreter = false;
224da0c48c4Sopenharmony_ci  has_dynamic = false;
225da0c48c4Sopenharmony_ci  has_soname = false;
226da0c48c4Sopenharmony_ci  has_pie_flag = false;
227da0c48c4Sopenharmony_ci  has_dt_debug = false;
228da0c48c4Sopenharmony_ci  has_symtab = false;
229da0c48c4Sopenharmony_ci  has_debug_sections = false;
230da0c48c4Sopenharmony_ci  has_modinfo = false;
231da0c48c4Sopenharmony_ci  has_gnu_linkonce_this_module = false;
232da0c48c4Sopenharmony_ci
233da0c48c4Sopenharmony_ci  int kind = elf_kind (elf);
234da0c48c4Sopenharmony_ci  if (verbose > 0)
235da0c48c4Sopenharmony_ci    fprintf (stderr, "info: %s: ELF kind: %s (0x%x)\n", current_path,
236da0c48c4Sopenharmony_ci	     elf_kind_string (kind), kind);
237da0c48c4Sopenharmony_ci  if (kind != ELF_K_ELF)
238da0c48c4Sopenharmony_ci    return true;
239da0c48c4Sopenharmony_ci
240da0c48c4Sopenharmony_ci  GElf_Ehdr ehdr_storage;
241da0c48c4Sopenharmony_ci  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_storage);
242da0c48c4Sopenharmony_ci  if (ehdr == NULL)
243da0c48c4Sopenharmony_ci    {
244da0c48c4Sopenharmony_ci      elf_issue (N_("ELF header"));
245da0c48c4Sopenharmony_ci      return false;
246da0c48c4Sopenharmony_ci    }
247da0c48c4Sopenharmony_ci  elf_type = ehdr->e_type;
248da0c48c4Sopenharmony_ci
249da0c48c4Sopenharmony_ci  /* Examine program headers.  */
250da0c48c4Sopenharmony_ci  GElf_Phdr dyn_seg = { .p_type = 0 };
251da0c48c4Sopenharmony_ci  {
252da0c48c4Sopenharmony_ci    size_t nphdrs;
253da0c48c4Sopenharmony_ci    if (elf_getphdrnum (elf, &nphdrs) != 0)
254da0c48c4Sopenharmony_ci      {
255da0c48c4Sopenharmony_ci	elf_issue (N_("program headers"));
256da0c48c4Sopenharmony_ci	return false;
257da0c48c4Sopenharmony_ci      }
258da0c48c4Sopenharmony_ci    for (size_t phdr_idx = 0; phdr_idx < nphdrs; ++phdr_idx)
259da0c48c4Sopenharmony_ci      {
260da0c48c4Sopenharmony_ci	GElf_Phdr phdr_storage;
261da0c48c4Sopenharmony_ci	GElf_Phdr *phdr = gelf_getphdr (elf, phdr_idx, &phdr_storage);
262da0c48c4Sopenharmony_ci	if (phdr == NULL)
263da0c48c4Sopenharmony_ci	  {
264da0c48c4Sopenharmony_ci	    elf_issue (N_("program header"));
265da0c48c4Sopenharmony_ci	    return false;
266da0c48c4Sopenharmony_ci	  }
267da0c48c4Sopenharmony_ci	if (phdr->p_type == PT_DYNAMIC)
268da0c48c4Sopenharmony_ci	  {
269da0c48c4Sopenharmony_ci	    dyn_seg = *phdr;
270da0c48c4Sopenharmony_ci	    has_dynamic = true;
271da0c48c4Sopenharmony_ci	  }
272da0c48c4Sopenharmony_ci	if (phdr->p_type == PT_INTERP)
273da0c48c4Sopenharmony_ci	  has_program_interpreter = true;
274da0c48c4Sopenharmony_ci	if (phdr->p_type == PT_LOAD)
275da0c48c4Sopenharmony_ci	  has_program_load = true;
276da0c48c4Sopenharmony_ci      }
277da0c48c4Sopenharmony_ci  }
278da0c48c4Sopenharmony_ci
279da0c48c4Sopenharmony_ci  /* Do we have sections?  */
280da0c48c4Sopenharmony_ci  {
281da0c48c4Sopenharmony_ci    size_t nshdrs;
282da0c48c4Sopenharmony_ci    if (elf_getshdrnum (elf, &nshdrs) != 0)
283da0c48c4Sopenharmony_ci      {
284da0c48c4Sopenharmony_ci	elf_issue (N_("section headers"));
285da0c48c4Sopenharmony_ci	return false;
286da0c48c4Sopenharmony_ci      }
287da0c48c4Sopenharmony_ci    if (nshdrs > 0)
288da0c48c4Sopenharmony_ci      has_sections = true;
289da0c48c4Sopenharmony_ci  }
290da0c48c4Sopenharmony_ci
291da0c48c4Sopenharmony_ci  {
292da0c48c4Sopenharmony_ci    size_t shstrndx;
293da0c48c4Sopenharmony_ci    if (unlikely (elf_getshdrstrndx (elf, &shstrndx) < 0))
294da0c48c4Sopenharmony_ci      {
295da0c48c4Sopenharmony_ci	elf_issue (N_("section header string table index"));
296da0c48c4Sopenharmony_ci	return false;
297da0c48c4Sopenharmony_ci      }
298da0c48c4Sopenharmony_ci
299da0c48c4Sopenharmony_ci    Elf_Scn *scn = NULL;
300da0c48c4Sopenharmony_ci    while (true)
301da0c48c4Sopenharmony_ci      {
302da0c48c4Sopenharmony_ci        scn = elf_nextscn (elf, scn);
303da0c48c4Sopenharmony_ci        if (scn == NULL)
304da0c48c4Sopenharmony_ci          break;
305da0c48c4Sopenharmony_ci        GElf_Shdr shdr_storage;
306da0c48c4Sopenharmony_ci        GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_storage);
307da0c48c4Sopenharmony_ci        if (shdr == NULL)
308da0c48c4Sopenharmony_ci	  {
309da0c48c4Sopenharmony_ci            elf_issue (N_("could not obtain section header"));
310da0c48c4Sopenharmony_ci	    return false;
311da0c48c4Sopenharmony_ci	  }
312da0c48c4Sopenharmony_ci        const char *section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
313da0c48c4Sopenharmony_ci        if (section_name == NULL)
314da0c48c4Sopenharmony_ci	  {
315da0c48c4Sopenharmony_ci            elf_issue(N_("could not obtain section name"));
316da0c48c4Sopenharmony_ci	    return false;
317da0c48c4Sopenharmony_ci	  }
318da0c48c4Sopenharmony_ci        if (verbose > 2)
319da0c48c4Sopenharmony_ci          fprintf (stderr, "debug: section header %s (type %d) found\n",
320da0c48c4Sopenharmony_ci                   section_name, shdr->sh_type);
321da0c48c4Sopenharmony_ci        if (shdr->sh_type == SHT_SYMTAB)
322da0c48c4Sopenharmony_ci          {
323da0c48c4Sopenharmony_ci            if (verbose > 1)
324da0c48c4Sopenharmony_ci              fputs ("debug: symtab section found\n", stderr);
325da0c48c4Sopenharmony_ci            has_symtab = true;
326da0c48c4Sopenharmony_ci          }
327da0c48c4Sopenharmony_ci	/* NOBITS and NOTE sections can be in any file.  We want to be
328da0c48c4Sopenharmony_ci	   sure there is at least one other allocated section.  */
329da0c48c4Sopenharmony_ci	if (shdr->sh_type != SHT_NOBITS
330da0c48c4Sopenharmony_ci	    && shdr->sh_type != SHT_NOTE
331da0c48c4Sopenharmony_ci	    && (shdr->sh_flags & SHF_ALLOC) != 0)
332da0c48c4Sopenharmony_ci	  {
333da0c48c4Sopenharmony_ci	    if (verbose > 1 && !has_bits_alloc)
334da0c48c4Sopenharmony_ci	      fputs ("debug: allocated (non-nobits/note) section found\n",
335da0c48c4Sopenharmony_ci		     stderr);
336da0c48c4Sopenharmony_ci	    has_bits_alloc = true;
337da0c48c4Sopenharmony_ci	  }
338da0c48c4Sopenharmony_ci        if (startswith (section_name, ".debug_")
339da0c48c4Sopenharmony_ci	    || startswith (section_name, ".zdebug_"))
340da0c48c4Sopenharmony_ci          {
341da0c48c4Sopenharmony_ci            if (verbose > 1 && !has_debug_sections)
342da0c48c4Sopenharmony_ci              fputs ("debug: .debug_* section found\n", stderr);
343da0c48c4Sopenharmony_ci            has_debug_sections = true;
344da0c48c4Sopenharmony_ci          }
345da0c48c4Sopenharmony_ci	if (strcmp (section_name, ".modinfo") == 0)
346da0c48c4Sopenharmony_ci	  {
347da0c48c4Sopenharmony_ci	    if (verbose > 1)
348da0c48c4Sopenharmony_ci	      fputs ("debug: .modinfo section found\n", stderr);
349da0c48c4Sopenharmony_ci	    has_modinfo = true;
350da0c48c4Sopenharmony_ci	  }
351da0c48c4Sopenharmony_ci	if (strcmp (section_name, ".gnu.linkonce.this_module") == 0)
352da0c48c4Sopenharmony_ci	  {
353da0c48c4Sopenharmony_ci	    if (verbose > 1)
354da0c48c4Sopenharmony_ci	      fputs ("debug: .gnu.linkonce.this_module section found\n",
355da0c48c4Sopenharmony_ci		     stderr);
356da0c48c4Sopenharmony_ci	    has_gnu_linkonce_this_module = true;
357da0c48c4Sopenharmony_ci	  }
358da0c48c4Sopenharmony_ci      }
359da0c48c4Sopenharmony_ci  }
360da0c48c4Sopenharmony_ci
361da0c48c4Sopenharmony_ci  /* Examine the dynamic section.  */
362da0c48c4Sopenharmony_ci  if (has_dynamic)
363da0c48c4Sopenharmony_ci    {
364da0c48c4Sopenharmony_ci      Elf_Data *data = elf_getdata_rawchunk (elf, dyn_seg.p_offset,
365da0c48c4Sopenharmony_ci					     dyn_seg.p_filesz,
366da0c48c4Sopenharmony_ci					     ELF_T_DYN);
367da0c48c4Sopenharmony_ci      if (data != NULL)
368da0c48c4Sopenharmony_ci	for (int dyn_idx = 0; ; ++dyn_idx)
369da0c48c4Sopenharmony_ci	  {
370da0c48c4Sopenharmony_ci	    GElf_Dyn dyn_storage;
371da0c48c4Sopenharmony_ci	    GElf_Dyn *dyn = gelf_getdyn (data, dyn_idx, &dyn_storage);
372da0c48c4Sopenharmony_ci	    if (dyn == NULL)
373da0c48c4Sopenharmony_ci	      break;
374da0c48c4Sopenharmony_ci	    if (verbose > 2)
375da0c48c4Sopenharmony_ci	      fprintf (stderr, "debug: dynamic entry %d"
376da0c48c4Sopenharmony_ci		       " with tag %llu found\n",
377da0c48c4Sopenharmony_ci		       dyn_idx, (unsigned long long int) dyn->d_tag);
378da0c48c4Sopenharmony_ci	    if (dyn->d_tag == DT_SONAME)
379da0c48c4Sopenharmony_ci	      has_soname = true;
380da0c48c4Sopenharmony_ci	    if (dyn->d_tag == DT_FLAGS_1 && (dyn->d_un.d_val & DF_1_PIE))
381da0c48c4Sopenharmony_ci	      has_pie_flag = true;
382da0c48c4Sopenharmony_ci	    if (dyn->d_tag == DT_DEBUG)
383da0c48c4Sopenharmony_ci	      has_dt_debug = true;
384da0c48c4Sopenharmony_ci	    if (dyn->d_tag == DT_NULL)
385da0c48c4Sopenharmony_ci	      break;
386da0c48c4Sopenharmony_ci	  }
387da0c48c4Sopenharmony_ci    }
388da0c48c4Sopenharmony_ci
389da0c48c4Sopenharmony_ci  if (verbose > 0)
390da0c48c4Sopenharmony_ci    {
391da0c48c4Sopenharmony_ci      fprintf (stderr, "info: %s: ELF type: %s (0x%x)\n", current_path,
392da0c48c4Sopenharmony_ci	       elf_type_string (elf_type), elf_type);
393da0c48c4Sopenharmony_ci      if (has_program_load)
394da0c48c4Sopenharmony_ci        fprintf (stderr, "info: %s: PT_LOAD found\n", current_path);
395da0c48c4Sopenharmony_ci      if (has_sections)
396da0c48c4Sopenharmony_ci	fprintf (stderr, "info: %s: has sections\n", current_path);
397da0c48c4Sopenharmony_ci      if (has_bits_alloc)
398da0c48c4Sopenharmony_ci	fprintf (stderr, "info: %s: allocated (real) section found\n",
399da0c48c4Sopenharmony_ci		 current_path);
400da0c48c4Sopenharmony_ci      if (has_program_interpreter)
401da0c48c4Sopenharmony_ci        fprintf (stderr, "info: %s: program interpreter found\n",
402da0c48c4Sopenharmony_ci                 current_path);
403da0c48c4Sopenharmony_ci      if (has_dynamic)
404da0c48c4Sopenharmony_ci        fprintf (stderr, "info: %s: dynamic segment found\n", current_path);
405da0c48c4Sopenharmony_ci      if (has_soname)
406da0c48c4Sopenharmony_ci        fprintf (stderr, "info: %s: soname found\n", current_path);
407da0c48c4Sopenharmony_ci      if (has_pie_flag)
408da0c48c4Sopenharmony_ci        fprintf (stderr, "info: %s: DF_1_PIE flag found\n", current_path);
409da0c48c4Sopenharmony_ci      if (has_dt_debug)
410da0c48c4Sopenharmony_ci        fprintf (stderr, "info: %s: DT_DEBUG found\n", current_path);
411da0c48c4Sopenharmony_ci      if (has_symtab)
412da0c48c4Sopenharmony_ci        fprintf (stderr, "info: %s: symbol table found\n", current_path);
413da0c48c4Sopenharmony_ci      if (has_debug_sections)
414da0c48c4Sopenharmony_ci        fprintf (stderr, "info: %s: .debug_* section found\n", current_path);
415da0c48c4Sopenharmony_ci      if (has_modinfo)
416da0c48c4Sopenharmony_ci        fprintf (stderr, "info: %s: .modinfo section found\n", current_path);
417da0c48c4Sopenharmony_ci      if (has_gnu_linkonce_this_module)
418da0c48c4Sopenharmony_ci        fprintf (stderr,
419da0c48c4Sopenharmony_ci		 "info: %s: .gnu.linkonce.this_module section found\n",
420da0c48c4Sopenharmony_ci		 current_path);
421da0c48c4Sopenharmony_ci    }
422da0c48c4Sopenharmony_ci
423da0c48c4Sopenharmony_ci  return true;
424da0c48c4Sopenharmony_ci}
425da0c48c4Sopenharmony_ci
426da0c48c4Sopenharmony_cistatic bool
427da0c48c4Sopenharmony_ciis_elf (void)
428da0c48c4Sopenharmony_ci{
429da0c48c4Sopenharmony_ci  return elf_kind (elf) != ELF_K_NONE;
430da0c48c4Sopenharmony_ci}
431da0c48c4Sopenharmony_ci
432da0c48c4Sopenharmony_cistatic bool
433da0c48c4Sopenharmony_ciis_elf_file (void)
434da0c48c4Sopenharmony_ci{
435da0c48c4Sopenharmony_ci  return elf_kind (elf) == ELF_K_ELF;
436da0c48c4Sopenharmony_ci}
437da0c48c4Sopenharmony_ci
438da0c48c4Sopenharmony_cistatic bool
439da0c48c4Sopenharmony_ciis_elf_archive (void)
440da0c48c4Sopenharmony_ci{
441da0c48c4Sopenharmony_ci  return elf_kind (elf) == ELF_K_AR;
442da0c48c4Sopenharmony_ci}
443da0c48c4Sopenharmony_ci
444da0c48c4Sopenharmony_cistatic bool
445da0c48c4Sopenharmony_ciis_core (void)
446da0c48c4Sopenharmony_ci{
447da0c48c4Sopenharmony_ci  return elf_kind (elf) == ELF_K_ELF && elf_type == ET_CORE;
448da0c48c4Sopenharmony_ci}
449da0c48c4Sopenharmony_ci
450da0c48c4Sopenharmony_ci/* Return true if the file is a loadable object, which basically means
451da0c48c4Sopenharmony_ci   it is an ELF file, but not a relocatable object or a core dump
452da0c48c4Sopenharmony_ci   file.  (The kernel and various userspace components can load ET_REL
453da0c48c4Sopenharmony_ci   files, but we disregard that for our classification purposes.)  */
454da0c48c4Sopenharmony_cistatic bool
455da0c48c4Sopenharmony_ciis_loadable (void)
456da0c48c4Sopenharmony_ci{
457da0c48c4Sopenharmony_ci  return elf_kind (elf) == ELF_K_ELF
458da0c48c4Sopenharmony_ci    && (elf_type == ET_EXEC || elf_type == ET_DYN)
459da0c48c4Sopenharmony_ci    && has_program_load
460da0c48c4Sopenharmony_ci    && (!has_sections || has_bits_alloc); /* It isn't debug-only.  */
461da0c48c4Sopenharmony_ci}
462da0c48c4Sopenharmony_ci
463da0c48c4Sopenharmony_ci/* Return true if the file is an ELF file which has a symbol table or
464da0c48c4Sopenharmony_ci   .debug_* sections (and thus can be stripped further).  */
465da0c48c4Sopenharmony_cistatic bool
466da0c48c4Sopenharmony_ciis_unstripped (void)
467da0c48c4Sopenharmony_ci{
468da0c48c4Sopenharmony_ci  return elf_kind (elf) != ELF_K_NONE
469da0c48c4Sopenharmony_ci    && (elf_type == ET_REL || elf_type == ET_EXEC || elf_type == ET_DYN)
470da0c48c4Sopenharmony_ci    && (has_symtab || has_debug_sections);
471da0c48c4Sopenharmony_ci}
472da0c48c4Sopenharmony_ci
473da0c48c4Sopenharmony_ci/* Return true if the file contains only debuginfo, but no loadable
474da0c48c4Sopenharmony_ci   program bits.  Then it is most likely a separate .debug file, a dwz
475da0c48c4Sopenharmony_ci   multi-file or a .dwo file.  Note that it can still be loadable,
476da0c48c4Sopenharmony_ci   but in that case the phdrs shouldn't be trusted.  */
477da0c48c4Sopenharmony_cistatic bool
478da0c48c4Sopenharmony_ciis_debug_only (void)
479da0c48c4Sopenharmony_ci{
480da0c48c4Sopenharmony_ci  return elf_kind (elf) != ELF_K_NONE
481da0c48c4Sopenharmony_ci    && (elf_type == ET_REL || elf_type == ET_EXEC || elf_type == ET_DYN)
482da0c48c4Sopenharmony_ci    && (has_debug_sections || has_symtab)
483da0c48c4Sopenharmony_ci    && !has_bits_alloc;
484da0c48c4Sopenharmony_ci}
485da0c48c4Sopenharmony_ci
486da0c48c4Sopenharmony_cistatic bool
487da0c48c4Sopenharmony_ciis_shared (void)
488da0c48c4Sopenharmony_ci{
489da0c48c4Sopenharmony_ci  if (!is_loadable ())
490da0c48c4Sopenharmony_ci    return false;
491da0c48c4Sopenharmony_ci
492da0c48c4Sopenharmony_ci  /* The ELF type is very clear: this is an executable.  */
493da0c48c4Sopenharmony_ci  if (elf_type == ET_EXEC)
494da0c48c4Sopenharmony_ci    return false;
495da0c48c4Sopenharmony_ci
496da0c48c4Sopenharmony_ci  /* If there is no dynamic section, the file cannot be loaded as a
497da0c48c4Sopenharmony_ci     shared object.  */
498da0c48c4Sopenharmony_ci  if (!has_dynamic)
499da0c48c4Sopenharmony_ci    return false;
500da0c48c4Sopenharmony_ci
501da0c48c4Sopenharmony_ci  /* If the object is marked as PIE, it is definitely an executable,
502da0c48c4Sopenharmony_ci     and not a loadlable shared object.  */
503da0c48c4Sopenharmony_ci  if (has_pie_flag)
504da0c48c4Sopenharmony_ci    return false;
505da0c48c4Sopenharmony_ci
506da0c48c4Sopenharmony_ci  /* Treat a DT_SONAME tag as a strong indicator that this is a shared
507da0c48c4Sopenharmony_ci     object.  */
508da0c48c4Sopenharmony_ci  if (has_soname)
509da0c48c4Sopenharmony_ci    return true;
510da0c48c4Sopenharmony_ci
511da0c48c4Sopenharmony_ci  /* This is probably a PIE program: there is no soname, but a program
512da0c48c4Sopenharmony_ci     interpreter.  In theory, this file could be also a DSO with a
513da0c48c4Sopenharmony_ci     soname implied by its file name that can be run as a program.
514da0c48c4Sopenharmony_ci     This situation is impossible to resolve in the general case. */
515da0c48c4Sopenharmony_ci  if (has_program_interpreter)
516da0c48c4Sopenharmony_ci    return false;
517da0c48c4Sopenharmony_ci
518da0c48c4Sopenharmony_ci  /* Roland McGrath mentions in
519da0c48c4Sopenharmony_ci     <https://www.sourceware.org/ml/libc-alpha/2015-03/msg00605.html>,
520da0c48c4Sopenharmony_ci     that “we defined a PIE as an ET_DYN with a DT_DEBUG”.  This
521da0c48c4Sopenharmony_ci     matches current binutils behavior (version 2.32).  DT_DEBUG is
522da0c48c4Sopenharmony_ci     added if bfd_link_executable returns true or if bfd_link_pic
523da0c48c4Sopenharmony_ci     returns false, depending on the architectures.  However, DT_DEBUG
524da0c48c4Sopenharmony_ci     is not documented as being specific to executables, therefore use
525da0c48c4Sopenharmony_ci     it only as a low-priority discriminator.  */
526da0c48c4Sopenharmony_ci  if (has_dt_debug)
527da0c48c4Sopenharmony_ci    return false;
528da0c48c4Sopenharmony_ci
529da0c48c4Sopenharmony_ci  return true;
530da0c48c4Sopenharmony_ci}
531da0c48c4Sopenharmony_ci
532da0c48c4Sopenharmony_cistatic bool
533da0c48c4Sopenharmony_ciis_executable (void)
534da0c48c4Sopenharmony_ci{
535da0c48c4Sopenharmony_ci  if (!is_loadable ())
536da0c48c4Sopenharmony_ci    return false;
537da0c48c4Sopenharmony_ci
538da0c48c4Sopenharmony_ci  /* A loadable object which is not a shared object is treated as an
539da0c48c4Sopenharmony_ci     executable.  */
540da0c48c4Sopenharmony_ci  return !is_shared ();
541da0c48c4Sopenharmony_ci}
542da0c48c4Sopenharmony_ci
543da0c48c4Sopenharmony_ci/* Like is_executable, but the object can also be a shared library at
544da0c48c4Sopenharmony_ci   the same time.  */
545da0c48c4Sopenharmony_cistatic bool
546da0c48c4Sopenharmony_ciis_program (void)
547da0c48c4Sopenharmony_ci{
548da0c48c4Sopenharmony_ci  if (!is_loadable ())
549da0c48c4Sopenharmony_ci    return false;
550da0c48c4Sopenharmony_ci
551da0c48c4Sopenharmony_ci  /* The ELF type is very clear: this is an executable.  */
552da0c48c4Sopenharmony_ci  if (elf_type == ET_EXEC)
553da0c48c4Sopenharmony_ci    return true;
554da0c48c4Sopenharmony_ci
555da0c48c4Sopenharmony_ci  /* If the object is marked as PIE, it is definitely an executable,
556da0c48c4Sopenharmony_ci     and not a loadlable shared object.  */
557da0c48c4Sopenharmony_ci  if (has_pie_flag)
558da0c48c4Sopenharmony_ci    return true;
559da0c48c4Sopenharmony_ci
560da0c48c4Sopenharmony_ci  /* This is probably a PIE program. It isn't ET_EXEC, but has a
561da0c48c4Sopenharmony_ci     program interpreter. In theory, this file could be also a DSO
562da0c48c4Sopenharmony_ci     with a soname. This situation is impossible to resolve in the
563da0c48c4Sopenharmony_ci     general case. See is_shared. This is different from
564da0c48c4Sopenharmony_ci     is_executable.  */
565da0c48c4Sopenharmony_ci  if (has_program_interpreter)
566da0c48c4Sopenharmony_ci    return true;
567da0c48c4Sopenharmony_ci
568da0c48c4Sopenharmony_ci  /* Roland McGrath mentions in
569da0c48c4Sopenharmony_ci     <https://www.sourceware.org/ml/libc-alpha/2015-03/msg00605.html>,
570da0c48c4Sopenharmony_ci     that “we defined a PIE as an ET_DYN with a DT_DEBUG”.  This
571da0c48c4Sopenharmony_ci     matches current binutils behavior (version 2.32).  DT_DEBUG is
572da0c48c4Sopenharmony_ci     added if bfd_link_executable returns true or if bfd_link_pic
573da0c48c4Sopenharmony_ci     returns false, depending on the architectures.  However, DT_DEBUG
574da0c48c4Sopenharmony_ci     is not documented as being specific to executables, therefore use
575da0c48c4Sopenharmony_ci     it only as a low-priority discriminator.  */
576da0c48c4Sopenharmony_ci  if (has_dt_debug)
577da0c48c4Sopenharmony_ci    return true;
578da0c48c4Sopenharmony_ci
579da0c48c4Sopenharmony_ci  return false;
580da0c48c4Sopenharmony_ci}
581da0c48c4Sopenharmony_ci
582da0c48c4Sopenharmony_ci/* Like is_shared but the library could also be an executable.  */
583da0c48c4Sopenharmony_cistatic bool
584da0c48c4Sopenharmony_ciis_library  (void)
585da0c48c4Sopenharmony_ci{
586da0c48c4Sopenharmony_ci  /* Only ET_DYN can be shared libraries.  */
587da0c48c4Sopenharmony_ci  if (elf_type != ET_DYN)
588da0c48c4Sopenharmony_ci    return false;
589da0c48c4Sopenharmony_ci
590da0c48c4Sopenharmony_ci  if (!is_loadable ())
591da0c48c4Sopenharmony_ci    return false;
592da0c48c4Sopenharmony_ci
593da0c48c4Sopenharmony_ci  /* Without a PT_DYNAMIC segment the library cannot be loaded.  */
594da0c48c4Sopenharmony_ci  if (!has_dynamic)
595da0c48c4Sopenharmony_ci    return false;
596da0c48c4Sopenharmony_ci
597da0c48c4Sopenharmony_ci  /* This really is a (PIE) executable.  See is_shared.  */
598da0c48c4Sopenharmony_ci  if (has_pie_flag || has_dt_debug)
599da0c48c4Sopenharmony_ci    return false;
600da0c48c4Sopenharmony_ci
601da0c48c4Sopenharmony_ci  /* It could still (also) be a (PIE) executable, but most likely you
602da0c48c4Sopenharmony_ci     can dlopen it just fine.  */
603da0c48c4Sopenharmony_ci  return true;
604da0c48c4Sopenharmony_ci}
605da0c48c4Sopenharmony_ci
606da0c48c4Sopenharmony_ci/* Returns true if the file is a linux kernel module (is ET_REL and
607da0c48c4Sopenharmony_ci   has the two magic sections .modinfo and .gnu.linkonce.this_module).  */
608da0c48c4Sopenharmony_cistatic bool
609da0c48c4Sopenharmony_ciis_linux_kernel_module (void)
610da0c48c4Sopenharmony_ci{
611da0c48c4Sopenharmony_ci  return (elf_kind (elf) == ELF_K_ELF
612da0c48c4Sopenharmony_ci	  && elf_type == ET_REL
613da0c48c4Sopenharmony_ci	  && has_modinfo
614da0c48c4Sopenharmony_ci	  && has_gnu_linkonce_this_module);
615da0c48c4Sopenharmony_ci}
616da0c48c4Sopenharmony_ci
617da0c48c4Sopenharmony_cienum classify_requirement { do_not_care, required, forbidden };
618da0c48c4Sopenharmony_ci
619da0c48c4Sopenharmony_cienum classify_check
620da0c48c4Sopenharmony_ci{
621da0c48c4Sopenharmony_ci  classify_elf,
622da0c48c4Sopenharmony_ci  classify_elf_file,
623da0c48c4Sopenharmony_ci  classify_elf_archive,
624da0c48c4Sopenharmony_ci  classify_core,
625da0c48c4Sopenharmony_ci  classify_unstripped,
626da0c48c4Sopenharmony_ci  classify_executable,
627da0c48c4Sopenharmony_ci  classify_program,
628da0c48c4Sopenharmony_ci  classify_shared,
629da0c48c4Sopenharmony_ci  classify_library,
630da0c48c4Sopenharmony_ci  classify_linux_kernel_module,
631da0c48c4Sopenharmony_ci  classify_debug_only,
632da0c48c4Sopenharmony_ci  classify_loadable,
633da0c48c4Sopenharmony_ci
634da0c48c4Sopenharmony_ci  classify_check_last = classify_loadable
635da0c48c4Sopenharmony_ci};
636da0c48c4Sopenharmony_ci
637da0c48c4Sopenharmony_cienum
638da0c48c4Sopenharmony_ci{
639da0c48c4Sopenharmony_ci  classify_check_offset = 1000,
640da0c48c4Sopenharmony_ci  classify_check_not_offset = 2000,
641da0c48c4Sopenharmony_ci
642da0c48c4Sopenharmony_ci  classify_flag_stdin = 3000,
643da0c48c4Sopenharmony_ci  classify_flag_stdin0,
644da0c48c4Sopenharmony_ci  classify_flag_no_stdin,
645da0c48c4Sopenharmony_ci  classify_flag_print,
646da0c48c4Sopenharmony_ci  classify_flag_print0,
647da0c48c4Sopenharmony_ci  classify_flag_no_print,
648da0c48c4Sopenharmony_ci  classify_flag_matching,
649da0c48c4Sopenharmony_ci  classify_flag_not_matching,
650da0c48c4Sopenharmony_ci};
651da0c48c4Sopenharmony_ci
652da0c48c4Sopenharmony_cistatic bool
653da0c48c4Sopenharmony_ciclassify_check_positive (int key)
654da0c48c4Sopenharmony_ci{
655da0c48c4Sopenharmony_ci  return key >= classify_check_offset
656da0c48c4Sopenharmony_ci    && key <= classify_check_offset + classify_check_last;
657da0c48c4Sopenharmony_ci}
658da0c48c4Sopenharmony_ci
659da0c48c4Sopenharmony_cistatic bool
660da0c48c4Sopenharmony_ciclassify_check_negative (int key)
661da0c48c4Sopenharmony_ci{
662da0c48c4Sopenharmony_ci  return key >= classify_check_not_offset
663da0c48c4Sopenharmony_ci    && key <= classify_check_not_offset + classify_check_last;
664da0c48c4Sopenharmony_ci}
665da0c48c4Sopenharmony_ci
666da0c48c4Sopenharmony_ci/* Set by parse_opt.  */
667da0c48c4Sopenharmony_cistatic enum classify_requirement requirements[classify_check_last + 1];
668da0c48c4Sopenharmony_cistatic enum { no_stdin, do_stdin, do_stdin0 } flag_stdin;
669da0c48c4Sopenharmony_cistatic enum { no_print, do_print, do_print0 } flag_print;
670da0c48c4Sopenharmony_cistatic bool flag_print_matching = true;
671da0c48c4Sopenharmony_ci
672da0c48c4Sopenharmony_cistatic error_t
673da0c48c4Sopenharmony_ciparse_opt (int key, char *arg __attribute__ ((unused)),
674da0c48c4Sopenharmony_ci           struct argp_state *state __attribute__ ((unused)))
675da0c48c4Sopenharmony_ci{
676da0c48c4Sopenharmony_ci  if (classify_check_positive (key))
677da0c48c4Sopenharmony_ci    requirements[key - classify_check_offset] = required;
678da0c48c4Sopenharmony_ci  else if (classify_check_negative (key))
679da0c48c4Sopenharmony_ci    requirements[key - classify_check_not_offset] = forbidden;
680da0c48c4Sopenharmony_ci  else
681da0c48c4Sopenharmony_ci    switch (key)
682da0c48c4Sopenharmony_ci      {
683da0c48c4Sopenharmony_ci      case 'v':
684da0c48c4Sopenharmony_ci        ++verbose;
685da0c48c4Sopenharmony_ci        break;
686da0c48c4Sopenharmony_ci
687da0c48c4Sopenharmony_ci      case 'q':
688da0c48c4Sopenharmony_ci	--verbose;
689da0c48c4Sopenharmony_ci	break;
690da0c48c4Sopenharmony_ci
691da0c48c4Sopenharmony_ci      case 'z':
692da0c48c4Sopenharmony_ci	flag_compressed = true;
693da0c48c4Sopenharmony_ci	break;
694da0c48c4Sopenharmony_ci
695da0c48c4Sopenharmony_ci      case 'f':
696da0c48c4Sopenharmony_ci	flag_only_regular_files = true;
697da0c48c4Sopenharmony_ci	break;
698da0c48c4Sopenharmony_ci
699da0c48c4Sopenharmony_ci      case classify_flag_stdin:
700da0c48c4Sopenharmony_ci        flag_stdin = do_stdin;
701da0c48c4Sopenharmony_ci        break;
702da0c48c4Sopenharmony_ci
703da0c48c4Sopenharmony_ci      case classify_flag_stdin0:
704da0c48c4Sopenharmony_ci        flag_stdin = do_stdin0;
705da0c48c4Sopenharmony_ci        break;
706da0c48c4Sopenharmony_ci
707da0c48c4Sopenharmony_ci      case classify_flag_no_stdin:
708da0c48c4Sopenharmony_ci        flag_stdin = no_stdin;
709da0c48c4Sopenharmony_ci        break;
710da0c48c4Sopenharmony_ci
711da0c48c4Sopenharmony_ci      case classify_flag_print:
712da0c48c4Sopenharmony_ci        flag_print = do_print;
713da0c48c4Sopenharmony_ci        break;
714da0c48c4Sopenharmony_ci
715da0c48c4Sopenharmony_ci      case classify_flag_print0:
716da0c48c4Sopenharmony_ci        flag_print = do_print0;
717da0c48c4Sopenharmony_ci        break;
718da0c48c4Sopenharmony_ci
719da0c48c4Sopenharmony_ci      case classify_flag_no_print:
720da0c48c4Sopenharmony_ci        flag_print = no_print;
721da0c48c4Sopenharmony_ci        break;
722da0c48c4Sopenharmony_ci
723da0c48c4Sopenharmony_ci      case classify_flag_matching:
724da0c48c4Sopenharmony_ci        flag_print_matching = true;
725da0c48c4Sopenharmony_ci        break;
726da0c48c4Sopenharmony_ci
727da0c48c4Sopenharmony_ci      case classify_flag_not_matching:
728da0c48c4Sopenharmony_ci        flag_print_matching = false;
729da0c48c4Sopenharmony_ci        break;
730da0c48c4Sopenharmony_ci
731da0c48c4Sopenharmony_ci      default:
732da0c48c4Sopenharmony_ci        return ARGP_ERR_UNKNOWN;
733da0c48c4Sopenharmony_ci      }
734da0c48c4Sopenharmony_ci
735da0c48c4Sopenharmony_ci  return 0;
736da0c48c4Sopenharmony_ci}
737da0c48c4Sopenharmony_ci
738da0c48c4Sopenharmony_ci/* Perform requested checks against the file at current_path.  If
739da0c48c4Sopenharmony_ci   necessary, sets *STATUS to 1 if checks failed.  */
740da0c48c4Sopenharmony_cistatic void
741da0c48c4Sopenharmony_ciprocess_current_path (int *status)
742da0c48c4Sopenharmony_ci{
743da0c48c4Sopenharmony_ci  bool checks_passed = true;
744da0c48c4Sopenharmony_ci
745da0c48c4Sopenharmony_ci  if (open_elf () && run_classify ())
746da0c48c4Sopenharmony_ci    {
747da0c48c4Sopenharmony_ci      bool checks[] =
748da0c48c4Sopenharmony_ci        {
749da0c48c4Sopenharmony_ci	 [classify_elf] = is_elf (),
750da0c48c4Sopenharmony_ci	 [classify_elf_file] = is_elf_file (),
751da0c48c4Sopenharmony_ci	 [classify_elf_archive] = is_elf_archive (),
752da0c48c4Sopenharmony_ci	 [classify_core] = is_core (),
753da0c48c4Sopenharmony_ci	 [classify_unstripped] = is_unstripped (),
754da0c48c4Sopenharmony_ci	 [classify_executable] = is_executable (),
755da0c48c4Sopenharmony_ci	 [classify_program] = is_program (),
756da0c48c4Sopenharmony_ci	 [classify_shared] = is_shared (),
757da0c48c4Sopenharmony_ci	 [classify_library] = is_library (),
758da0c48c4Sopenharmony_ci	 [classify_linux_kernel_module] = is_linux_kernel_module (),
759da0c48c4Sopenharmony_ci	 [classify_debug_only] = is_debug_only (),
760da0c48c4Sopenharmony_ci	 [classify_loadable] = is_loadable (),
761da0c48c4Sopenharmony_ci	};
762da0c48c4Sopenharmony_ci
763da0c48c4Sopenharmony_ci      if (verbose > 1)
764da0c48c4Sopenharmony_ci        {
765da0c48c4Sopenharmony_ci	  if (checks[classify_elf])
766da0c48c4Sopenharmony_ci	    fprintf (stderr, "debug: %s: elf\n", current_path);
767da0c48c4Sopenharmony_ci	  if (checks[classify_elf_file])
768da0c48c4Sopenharmony_ci	    fprintf (stderr, "debug: %s: elf_file\n", current_path);
769da0c48c4Sopenharmony_ci	  if (checks[classify_elf_archive])
770da0c48c4Sopenharmony_ci	    fprintf (stderr, "debug: %s: elf_archive\n", current_path);
771da0c48c4Sopenharmony_ci	  if (checks[classify_core])
772da0c48c4Sopenharmony_ci	    fprintf (stderr, "debug: %s: core\n", current_path);
773da0c48c4Sopenharmony_ci          if (checks[classify_unstripped])
774da0c48c4Sopenharmony_ci            fprintf (stderr, "debug: %s: unstripped\n", current_path);
775da0c48c4Sopenharmony_ci          if (checks[classify_executable])
776da0c48c4Sopenharmony_ci            fprintf (stderr, "debug: %s: executable\n", current_path);
777da0c48c4Sopenharmony_ci          if (checks[classify_program])
778da0c48c4Sopenharmony_ci            fprintf (stderr, "debug: %s: program\n", current_path);
779da0c48c4Sopenharmony_ci          if (checks[classify_shared])
780da0c48c4Sopenharmony_ci            fprintf (stderr, "debug: %s: shared\n", current_path);
781da0c48c4Sopenharmony_ci          if (checks[classify_library])
782da0c48c4Sopenharmony_ci            fprintf (stderr, "debug: %s: library\n", current_path);
783da0c48c4Sopenharmony_ci	  if (checks[classify_linux_kernel_module])
784da0c48c4Sopenharmony_ci	    fprintf (stderr, "debug: %s: linux kernel module\n", current_path);
785da0c48c4Sopenharmony_ci	  if (checks[classify_debug_only])
786da0c48c4Sopenharmony_ci	    fprintf (stderr, "debug: %s: debug-only\n", current_path);
787da0c48c4Sopenharmony_ci          if (checks[classify_loadable])
788da0c48c4Sopenharmony_ci            fprintf (stderr, "debug: %s: loadable\n", current_path);
789da0c48c4Sopenharmony_ci        }
790da0c48c4Sopenharmony_ci
791da0c48c4Sopenharmony_ci      for (enum classify_check check = 0;
792da0c48c4Sopenharmony_ci           check <= classify_check_last; ++check)
793da0c48c4Sopenharmony_ci        switch (requirements[check])
794da0c48c4Sopenharmony_ci          {
795da0c48c4Sopenharmony_ci          case required:
796da0c48c4Sopenharmony_ci            if (!checks[check])
797da0c48c4Sopenharmony_ci              checks_passed = false;
798da0c48c4Sopenharmony_ci            break;
799da0c48c4Sopenharmony_ci          case forbidden:
800da0c48c4Sopenharmony_ci            if (checks[check])
801da0c48c4Sopenharmony_ci              checks_passed = false;
802da0c48c4Sopenharmony_ci            break;
803da0c48c4Sopenharmony_ci          case do_not_care:
804da0c48c4Sopenharmony_ci            break;
805da0c48c4Sopenharmony_ci          }
806da0c48c4Sopenharmony_ci    }
807da0c48c4Sopenharmony_ci  else if (file_fd == -1)
808da0c48c4Sopenharmony_ci    checks_passed = false; /* There is nothing to check, bad file.  */
809da0c48c4Sopenharmony_ci  else
810da0c48c4Sopenharmony_ci    {
811da0c48c4Sopenharmony_ci      for (enum classify_check check = 0;
812da0c48c4Sopenharmony_ci           check <= classify_check_last; ++check)
813da0c48c4Sopenharmony_ci        if (requirements[check] == required)
814da0c48c4Sopenharmony_ci          checks_passed = false;
815da0c48c4Sopenharmony_ci    }
816da0c48c4Sopenharmony_ci
817da0c48c4Sopenharmony_ci  close_elf ();
818da0c48c4Sopenharmony_ci
819da0c48c4Sopenharmony_ci  switch (flag_print)
820da0c48c4Sopenharmony_ci    {
821da0c48c4Sopenharmony_ci    case do_print:
822da0c48c4Sopenharmony_ci      if (checks_passed == flag_print_matching)
823da0c48c4Sopenharmony_ci        puts (current_path);
824da0c48c4Sopenharmony_ci      break;
825da0c48c4Sopenharmony_ci    case do_print0:
826da0c48c4Sopenharmony_ci      if (checks_passed == flag_print_matching)
827da0c48c4Sopenharmony_ci        if (fwrite (current_path, strlen (current_path) + 1, 1, stdout) < 1)
828da0c48c4Sopenharmony_ci	  issue (errno, N_("writing to standard output"));
829da0c48c4Sopenharmony_ci      break;
830da0c48c4Sopenharmony_ci    case no_print:
831da0c48c4Sopenharmony_ci      if (!checks_passed)
832da0c48c4Sopenharmony_ci        *status = 1;
833da0c48c4Sopenharmony_ci      break;
834da0c48c4Sopenharmony_ci    }
835da0c48c4Sopenharmony_ci}
836da0c48c4Sopenharmony_ci
837da0c48c4Sopenharmony_ci/* Called to process standard input if flag_stdin is not no_stdin.  */
838da0c48c4Sopenharmony_cistatic void
839da0c48c4Sopenharmony_ciprocess_stdin (int *status)
840da0c48c4Sopenharmony_ci{
841da0c48c4Sopenharmony_ci  char delim;
842da0c48c4Sopenharmony_ci  if (flag_stdin == do_stdin0)
843da0c48c4Sopenharmony_ci    delim = '\0';
844da0c48c4Sopenharmony_ci  else
845da0c48c4Sopenharmony_ci    delim = '\n';
846da0c48c4Sopenharmony_ci
847da0c48c4Sopenharmony_ci  char *buffer = NULL;
848da0c48c4Sopenharmony_ci  size_t buffer_size = 0;
849da0c48c4Sopenharmony_ci  while (true)
850da0c48c4Sopenharmony_ci    {
851da0c48c4Sopenharmony_ci      ssize_t ret = getdelim (&buffer, &buffer_size, delim, stdin);
852da0c48c4Sopenharmony_ci      if (ferror (stdin))
853da0c48c4Sopenharmony_ci	{
854da0c48c4Sopenharmony_ci	  current_path = NULL;
855da0c48c4Sopenharmony_ci	  issue (errno, N_("reading from standard input"));
856da0c48c4Sopenharmony_ci	  break;
857da0c48c4Sopenharmony_ci	}
858da0c48c4Sopenharmony_ci      if (feof (stdin))
859da0c48c4Sopenharmony_ci        break;
860da0c48c4Sopenharmony_ci      if (ret < 0)
861da0c48c4Sopenharmony_ci        abort ();           /* Cannot happen due to error checks above.  */
862da0c48c4Sopenharmony_ci      if (delim != '\0' && ret > 0 && buffer[ret - 1] == '\n')
863da0c48c4Sopenharmony_ci        buffer[ret - 1] = '\0';
864da0c48c4Sopenharmony_ci      current_path = buffer;
865da0c48c4Sopenharmony_ci      process_current_path (status);
866da0c48c4Sopenharmony_ci    }
867da0c48c4Sopenharmony_ci
868da0c48c4Sopenharmony_ci  free (buffer);
869da0c48c4Sopenharmony_ci}
870da0c48c4Sopenharmony_ci
871da0c48c4Sopenharmony_ciint
872da0c48c4Sopenharmony_cimain (int argc, char **argv)
873da0c48c4Sopenharmony_ci{
874da0c48c4Sopenharmony_ci  const struct argp_option options[] =
875da0c48c4Sopenharmony_ci    {
876da0c48c4Sopenharmony_ci      { NULL, 0, NULL, OPTION_DOC, N_("Classification options"), 1 },
877da0c48c4Sopenharmony_ci      { "elf", classify_check_offset + classify_elf, NULL, 0,
878da0c48c4Sopenharmony_ci        N_("File looks like an ELF object or archive/static library (default)")
879da0c48c4Sopenharmony_ci	, 1 },
880da0c48c4Sopenharmony_ci      { "elf-file", classify_check_offset + classify_elf_file, NULL, 0,
881da0c48c4Sopenharmony_ci        N_("File is an regular ELF object (not an archive/static library)")
882da0c48c4Sopenharmony_ci	, 1 },
883da0c48c4Sopenharmony_ci      { "elf-archive", classify_check_offset + classify_elf_archive, NULL, 0,
884da0c48c4Sopenharmony_ci        N_("File is an ELF archive or static library")
885da0c48c4Sopenharmony_ci	, 1 },
886da0c48c4Sopenharmony_ci      { "core", classify_check_offset + classify_core, NULL, 0,
887da0c48c4Sopenharmony_ci        N_("File is an ELF core dump file")
888da0c48c4Sopenharmony_ci	, 1 },
889da0c48c4Sopenharmony_ci      { "unstripped", classify_check_offset + classify_unstripped, NULL, 0,
890da0c48c4Sopenharmony_ci        N_("File is an ELF file with symbol table or .debug_* sections \
891da0c48c4Sopenharmony_ciand can be stripped further"), 1 },
892da0c48c4Sopenharmony_ci      { "executable", classify_check_offset + classify_executable, NULL, 0,
893da0c48c4Sopenharmony_ci        N_("File is (primarily) an ELF program executable \
894da0c48c4Sopenharmony_ci(not primarily a DSO)"), 1 },
895da0c48c4Sopenharmony_ci      { "program", classify_check_offset + classify_program, NULL, 0,
896da0c48c4Sopenharmony_ci        N_("File is an ELF program executable \
897da0c48c4Sopenharmony_ci(might also be a DSO)"), 1 },
898da0c48c4Sopenharmony_ci      { "shared", classify_check_offset + classify_shared, NULL, 0,
899da0c48c4Sopenharmony_ci        N_("File is (primarily) an ELF shared object (DSO) \
900da0c48c4Sopenharmony_ci(not primarily an executable)"), 1 },
901da0c48c4Sopenharmony_ci      { "library", classify_check_offset + classify_library, NULL, 0,
902da0c48c4Sopenharmony_ci        N_("File is an ELF shared object (DSO) \
903da0c48c4Sopenharmony_ci(might also be an executable)"), 1 },
904da0c48c4Sopenharmony_ci      { "linux-kernel-module", (classify_check_offset
905da0c48c4Sopenharmony_ci				+ classify_linux_kernel_module), NULL, 0,
906da0c48c4Sopenharmony_ci        N_("File is a linux kernel module"), 1 },
907da0c48c4Sopenharmony_ci      { "debug-only", (classify_check_offset + classify_debug_only), NULL, 0,
908da0c48c4Sopenharmony_ci        N_("File is a debug only ELF file \
909da0c48c4Sopenharmony_ci(separate .debug, .dwo or dwz multi-file)"), 1 },
910da0c48c4Sopenharmony_ci      { "loadable", classify_check_offset + classify_loadable, NULL, 0,
911da0c48c4Sopenharmony_ci        N_("File is a loadable ELF object (program or shared object)"), 1 },
912da0c48c4Sopenharmony_ci
913da0c48c4Sopenharmony_ci      /* Negated versions of the above.  */
914da0c48c4Sopenharmony_ci      { "not-elf", classify_check_not_offset + classify_elf,
915da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
916da0c48c4Sopenharmony_ci      { "not-elf-file", classify_check_not_offset + classify_elf_file,
917da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
918da0c48c4Sopenharmony_ci      { "not-elf-archive", classify_check_not_offset + classify_elf_archive,
919da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
920da0c48c4Sopenharmony_ci      { "not-core", classify_check_not_offset + classify_core,
921da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
922da0c48c4Sopenharmony_ci      { "not-unstripped", classify_check_not_offset + classify_unstripped,
923da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
924da0c48c4Sopenharmony_ci      { "not-executable", classify_check_not_offset + classify_executable,
925da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
926da0c48c4Sopenharmony_ci      { "not-program", classify_check_not_offset + classify_program,
927da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
928da0c48c4Sopenharmony_ci      { "not-shared", classify_check_not_offset + classify_shared,
929da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
930da0c48c4Sopenharmony_ci      { "not-library", classify_check_not_offset + classify_library,
931da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
932da0c48c4Sopenharmony_ci      { "not-linux-kernel-module", (classify_check_not_offset
933da0c48c4Sopenharmony_ci				    + classify_linux_kernel_module),
934da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
935da0c48c4Sopenharmony_ci      { "not-debug-only", (classify_check_not_offset + classify_debug_only),
936da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
937da0c48c4Sopenharmony_ci      { "not-loadable", classify_check_not_offset + classify_loadable,
938da0c48c4Sopenharmony_ci        NULL, OPTION_HIDDEN, NULL, 1 },
939da0c48c4Sopenharmony_ci
940da0c48c4Sopenharmony_ci      { NULL, 0, NULL, OPTION_DOC, N_("Input flags"), 2 },
941da0c48c4Sopenharmony_ci      { "file", 'f', NULL, 0,
942da0c48c4Sopenharmony_ci        N_("Only classify regular (not symlink nor special device) files"), 2 },
943da0c48c4Sopenharmony_ci      { "stdin", classify_flag_stdin, NULL, 0,
944da0c48c4Sopenharmony_ci        N_("Also read file names to process from standard input, \
945da0c48c4Sopenharmony_ciseparated by newlines"), 2 },
946da0c48c4Sopenharmony_ci      { "stdin0", classify_flag_stdin0, NULL, 0,
947da0c48c4Sopenharmony_ci        N_("Also read file names to process from standard input, \
948da0c48c4Sopenharmony_ciseparated by ASCII NUL bytes"), 2 },
949da0c48c4Sopenharmony_ci      { "no-stdin", classify_flag_no_stdin, NULL, 0,
950da0c48c4Sopenharmony_ci        N_("Do not read files from standard input (default)"), 2 },
951da0c48c4Sopenharmony_ci      { "compressed", 'z', NULL, 0,
952da0c48c4Sopenharmony_ci	N_("Try to open compressed files or embedded (kernel) ELF images"),
953da0c48c4Sopenharmony_ci	2 },
954da0c48c4Sopenharmony_ci
955da0c48c4Sopenharmony_ci      { NULL, 0, NULL, OPTION_DOC, N_("Output flags"), 3 },
956da0c48c4Sopenharmony_ci      { "print", classify_flag_print, NULL, 0,
957da0c48c4Sopenharmony_ci        N_("Output names of files, separated by newline"), 3 },
958da0c48c4Sopenharmony_ci      { "print0", classify_flag_print0, NULL, 0,
959da0c48c4Sopenharmony_ci        N_("Output names of files, separated by ASCII NUL"), 3 },
960da0c48c4Sopenharmony_ci      { "no-print", classify_flag_no_print, NULL, 0,
961da0c48c4Sopenharmony_ci        N_("Do not output file names"), 3 },
962da0c48c4Sopenharmony_ci      { "matching", classify_flag_matching, NULL, 0,
963da0c48c4Sopenharmony_ci        N_("If printing file names, print matching files (default)"), 3 },
964da0c48c4Sopenharmony_ci      { "not-matching", classify_flag_not_matching, NULL, 0,
965da0c48c4Sopenharmony_ci        N_("If printing file names, print files that do not match"), 3 },
966da0c48c4Sopenharmony_ci
967da0c48c4Sopenharmony_ci      { NULL, 0, NULL, OPTION_DOC, N_("Additional flags"), 4 },
968da0c48c4Sopenharmony_ci      { "verbose", 'v', NULL, 0,
969da0c48c4Sopenharmony_ci        N_("Output additional information (can be specified multiple times)"), 4 },
970da0c48c4Sopenharmony_ci      { "quiet", 'q', NULL, 0,
971da0c48c4Sopenharmony_ci        N_("Suppress some error output (counterpart to --verbose)"), 4 },
972da0c48c4Sopenharmony_ci      { NULL, 0, NULL, 0, NULL, 0 }
973da0c48c4Sopenharmony_ci    };
974da0c48c4Sopenharmony_ci
975da0c48c4Sopenharmony_ci  const struct argp argp =
976da0c48c4Sopenharmony_ci    {
977da0c48c4Sopenharmony_ci      .options = options,
978da0c48c4Sopenharmony_ci      .parser = parse_opt,
979da0c48c4Sopenharmony_ci      .args_doc = N_("FILE..."),
980da0c48c4Sopenharmony_ci      .doc = N_("\
981da0c48c4Sopenharmony_ciDetermine the type of an ELF file.\
982da0c48c4Sopenharmony_ci\n\n\
983da0c48c4Sopenharmony_ciAll of the classification options must apply at the same time to a \
984da0c48c4Sopenharmony_ciparticular file.  Classification options can be negated using a \
985da0c48c4Sopenharmony_ci\"--not-\" prefix.\
986da0c48c4Sopenharmony_ci\n\n\
987da0c48c4Sopenharmony_ciSince modern ELF does not clearly distinguish between programs and \
988da0c48c4Sopenharmony_cidynamic shared objects, you should normally use either --executable or \
989da0c48c4Sopenharmony_ci--shared to identify the primary purpose of a file.  \
990da0c48c4Sopenharmony_ciOnly one of the --shared and --executable checks can pass for a file.\
991da0c48c4Sopenharmony_ci\n\n\
992da0c48c4Sopenharmony_ciIf you want to know whether an ELF object might a program or a \
993da0c48c4Sopenharmony_cishared library (but could be both), then use --program or --library. \
994da0c48c4Sopenharmony_ciSome ELF files will classify as both a program and a library.\
995da0c48c4Sopenharmony_ci\n\n\
996da0c48c4Sopenharmony_ciIf you just want to know whether an ELF file is loadable (as program \
997da0c48c4Sopenharmony_cior library) use --loadable.  Note that files that only contain \
998da0c48c4Sopenharmony_ci(separate) debug information (--debug-only) are never --loadable (even \
999da0c48c4Sopenharmony_cithough they might contain program headers).  Linux kernel modules are \
1000da0c48c4Sopenharmony_cialso not --loadable (in the normal sense).\
1001da0c48c4Sopenharmony_ci\n\n\
1002da0c48c4Sopenharmony_ciWithout any of the --print options, the program exits with status 0 \
1003da0c48c4Sopenharmony_ciif the requested checks pass for all input files, with 1 if a check \
1004da0c48c4Sopenharmony_cifails for any file, and 2 if there is an environmental issue (such \
1005da0c48c4Sopenharmony_cias a file read error or a memory allocation error).\
1006da0c48c4Sopenharmony_ci\n\n\
1007da0c48c4Sopenharmony_ciWhen printing file names, the program exits with status 0 even if \
1008da0c48c4Sopenharmony_cino file names are printed, and exits with status 2 if there is an \
1009da0c48c4Sopenharmony_cienvironmental issue.\
1010da0c48c4Sopenharmony_ci\n\n\
1011da0c48c4Sopenharmony_ciOn usage error (e.g. a bad option was given), the program exits with \
1012da0c48c4Sopenharmony_cia status code larger than 2.\
1013da0c48c4Sopenharmony_ci\n\n\
1014da0c48c4Sopenharmony_ciThe --quiet or -q option suppresses some error warning output, but \
1015da0c48c4Sopenharmony_cidoesn't change the exit status.\
1016da0c48c4Sopenharmony_ci")
1017da0c48c4Sopenharmony_ci    };
1018da0c48c4Sopenharmony_ci
1019da0c48c4Sopenharmony_ci  /* Require that the file is an ELF file by default.  User can
1020da0c48c4Sopenharmony_ci     disable with --not-elf.  */
1021da0c48c4Sopenharmony_ci  requirements[classify_elf] = required;
1022da0c48c4Sopenharmony_ci
1023da0c48c4Sopenharmony_ci  int remaining;
1024da0c48c4Sopenharmony_ci  if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
1025da0c48c4Sopenharmony_ci    return 2;
1026da0c48c4Sopenharmony_ci
1027da0c48c4Sopenharmony_ci  elf_version (EV_CURRENT);
1028da0c48c4Sopenharmony_ci
1029da0c48c4Sopenharmony_ci  int status = 0;
1030da0c48c4Sopenharmony_ci
1031da0c48c4Sopenharmony_ci  for (int i = remaining; i < argc; ++i)
1032da0c48c4Sopenharmony_ci    {
1033da0c48c4Sopenharmony_ci      current_path = argv[i];
1034da0c48c4Sopenharmony_ci      process_current_path (&status);
1035da0c48c4Sopenharmony_ci    }
1036da0c48c4Sopenharmony_ci
1037da0c48c4Sopenharmony_ci  if (flag_stdin != no_stdin)
1038da0c48c4Sopenharmony_ci    process_stdin (&status);
1039da0c48c4Sopenharmony_ci
1040da0c48c4Sopenharmony_ci  if (issue_found)
1041da0c48c4Sopenharmony_ci    return 2;
1042da0c48c4Sopenharmony_ci
1043da0c48c4Sopenharmony_ci  return status;
1044da0c48c4Sopenharmony_ci}
1045