+/* Process one section of an object file. */
+
+static int
+process_symtab (void *data, const char *name, off_t offset, off_t length)
+{
+ struct plugin_objfile *obj = (struct plugin_objfile *)data;
+ char *s;
+ char *secdata;
+
+ if (strncmp (name, LTO_SECTION_PREFIX, LTO_SECTION_PREFIX_LEN) != 0)
+ return 1;
+
+ s = strrchr (name, '.');
+ if (s)
+ sscanf (s, ".%x", &obj->out->id);
+ secdata = xmalloc (length);
+ offset += obj->file->offset;
+ if (offset != lseek (obj->file->fd, offset, SEEK_SET)
+ || length != read (obj->file->fd, secdata, length))
+ {
+ if (message)
+ message (LDPL_FATAL, "%s: corrupt object file", obj->file->name);
+ /* Force claim_file_handler to abandon this file. */
+ obj->found = 0;
+ free (secdata);
+ return 0;
+ }
+
+ translate (secdata, secdata + length, obj->out);
+ obj->found++;
+ free (secdata);
+ return 1;
+}
+
+/* Callback used by gold to check if the plugin will claim FILE. Writes
+ the result in CLAIMED. */
+
+static enum ld_plugin_status
+claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
+{
+ enum ld_plugin_status status;
+ struct plugin_objfile obj;
+ struct plugin_file_info lto_file;
+ int err;
+ const char *errmsg;
+
+ memset (<o_file, 0, sizeof (struct plugin_file_info));
+
+ if (file->offset != 0)
+ {
+ char *objname;
+ /* We pass the offset of the actual file, not the archive header.
+ Can't use PRIx64, because that's C99, so we have to print the
+ 64-bit hex int as two 32-bit ones. */
+ int lo, hi;
+ lo = file->offset & 0xffffffff;
+ hi = ((int64_t)file->offset >> 32) & 0xffffffff;
+ int t = hi ? asprintf (&objname, "%s@0x%x%08x", file->name, lo, hi)
+ : asprintf (&objname, "%s@0x%x", file->name, lo);
+ check (t >= 0, LDPL_FATAL, "asprintf failed");
+ lto_file.name = objname;
+ }
+ else
+ {
+ lto_file.name = xstrdup (file->name);
+ }
+ lto_file.handle = file->handle;
+
+ *claimed = 0;
+ obj.file = file;
+ obj.found = 0;
+ obj.out = <o_file.symtab;
+ errmsg = NULL;
+ obj.objfile = simple_object_start_read (file->fd, file->offset, LTO_SEGMENT_NAME,
+ &errmsg, &err);
+ /* No file, but also no error code means unrecognized format; just skip it. */
+ if (!obj.objfile && !err)
+ goto err;
+
+ if (obj.objfile)
+ errmsg = simple_object_find_sections (obj.objfile, process_symtab, &obj, &err);
+
+ if (!obj.objfile || errmsg)
+ {
+ if (err && message)
+ message (LDPL_FATAL, "%s: %s: %s", file->name, errmsg,
+ xstrerror (err));
+ else if (message)
+ message (LDPL_FATAL, "%s: %s", file->name, errmsg);
+ goto err;
+ }
+
+ if (obj.found == 0)
+ goto err;
+
+ if (obj.found > 1)
+ resolve_conflicts (<o_file.symtab, <o_file.conflicts);
+
+ status = add_symbols (file->handle, lto_file.symtab.nsyms,
+ lto_file.symtab.syms);
+ check (status == LDPS_OK, LDPL_FATAL, "could not add symbols");
+
+ *claimed = 1;
+ num_claimed_files++;
+ claimed_files =
+ xrealloc (claimed_files,
+ num_claimed_files * sizeof (struct plugin_file_info));
+ claimed_files[num_claimed_files - 1] = lto_file;
+
+ goto cleanup;
+
+ err:
+ free (lto_file.name);
+
+ cleanup:
+ if (obj.objfile)
+ simple_object_release_read (obj.objfile);
+
+ return LDPS_OK;
+}
+