+/* Read in DW_TAG_GNU_call_site and insert it to CU->call_site_htab. */
+
+static void
+read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ CORE_ADDR pc, baseaddr;
+ struct attribute *attr;
+ struct call_site *call_site, call_site_local;
+ void **slot;
+ int nparams;
+ struct die_info *child_die;
+
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ attr = dwarf2_attr (die, DW_AT_low_pc, cu);
+ if (!attr)
+ {
+ complaint (&symfile_complaints,
+ _("missing DW_AT_low_pc for DW_TAG_GNU_call_site "
+ "DIE 0x%x [in module %s]"),
+ die->offset, cu->objfile->name);
+ return;
+ }
+ pc = DW_ADDR (attr) + baseaddr;
+
+ if (cu->call_site_htab == NULL)
+ cu->call_site_htab = htab_create_alloc_ex (16, core_addr_hash, core_addr_eq,
+ NULL, &objfile->objfile_obstack,
+ hashtab_obstack_allocate, NULL);
+ call_site_local.pc = pc;
+ slot = htab_find_slot (cu->call_site_htab, &call_site_local, INSERT);
+ if (*slot != NULL)
+ {
+ complaint (&symfile_complaints,
+ _("Duplicate PC %s for DW_TAG_GNU_call_site "
+ "DIE 0x%x [in module %s]"),
+ paddress (gdbarch, pc), die->offset, cu->objfile->name);
+ return;
+ }
+
+ /* Count parameters at the caller. */
+
+ nparams = 0;
+ for (child_die = die->child; child_die && child_die->tag;
+ child_die = sibling_die (child_die))
+ {
+ if (child_die->tag != DW_TAG_GNU_call_site_parameter)
+ {
+ complaint (&symfile_complaints,
+ _("Tag %d is not DW_TAG_GNU_call_site_parameter in "
+ "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
+ child_die->tag, child_die->offset, cu->objfile->name);
+ continue;
+ }
+
+ nparams++;
+ }
+
+ call_site = obstack_alloc (&objfile->objfile_obstack,
+ (sizeof (*call_site)
+ + (sizeof (*call_site->parameter)
+ * (nparams - 1))));
+ *slot = call_site;
+ memset (call_site, 0, sizeof (*call_site) - sizeof (*call_site->parameter));
+ call_site->pc = pc;
+
+ if (dwarf2_flag_true_p (die, DW_AT_GNU_tail_call, cu))
+ {
+ struct die_info *func_die;
+
+ /* Skip also over DW_TAG_inlined_subroutine. */
+ for (func_die = die->parent;
+ func_die && func_die->tag != DW_TAG_subprogram
+ && func_die->tag != DW_TAG_subroutine_type;
+ func_die = func_die->parent);
+
+ /* DW_AT_GNU_all_call_sites is a superset
+ of DW_AT_GNU_all_tail_call_sites. */
+ if (func_die
+ && !dwarf2_flag_true_p (func_die, DW_AT_GNU_all_call_sites, cu)
+ && !dwarf2_flag_true_p (func_die, DW_AT_GNU_all_tail_call_sites, cu))
+ {
+ /* TYPE_TAIL_CALL_LIST is not interesting in functions where it is
+ not complete. But keep CALL_SITE for look ups via call_site_htab,
+ both the initial caller containing the real return address PC and
+ the final callee containing the current PC of a chain of tail
+ calls do not need to have the tail call list complete. But any
+ function candidate for a virtual tail call frame searched via
+ TYPE_TAIL_CALL_LIST must have the tail call list complete to be
+ determined unambiguously. */
+ }
+ else
+ {
+ struct type *func_type = NULL;
+
+ if (func_die)
+ func_type = get_die_type (func_die, cu);
+ if (func_type != NULL)
+ {
+ gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC);
+
+ /* Enlist this call site to the function. */
+ call_site->tail_call_next = TYPE_TAIL_CALL_LIST (func_type);
+ TYPE_TAIL_CALL_LIST (func_type) = call_site;
+ }
+ else
+ complaint (&symfile_complaints,
+ _("Cannot find function owning DW_TAG_GNU_call_site "
+ "DIE 0x%x [in module %s]"),
+ die->offset, cu->objfile->name);
+ }
+ }
+
+ attr = dwarf2_attr (die, DW_AT_GNU_call_site_target, cu);
+ if (attr == NULL)
+ attr = dwarf2_attr (die, DW_AT_abstract_origin, cu);
+ SET_FIELD_DWARF_BLOCK (call_site->target, NULL);
+ if (!attr || (attr_form_is_block (attr) && DW_BLOCK (attr)->size == 0))
+ /* Keep NULL DWARF_BLOCK. */;
+ else if (attr_form_is_block (attr))
+ {
+ struct dwarf2_locexpr_baton *dlbaton;
+
+ dlbaton = obstack_alloc (&objfile->objfile_obstack, sizeof (*dlbaton));
+ dlbaton->data = DW_BLOCK (attr)->data;
+ dlbaton->size = DW_BLOCK (attr)->size;
+ dlbaton->per_cu = cu->per_cu;
+
+ SET_FIELD_DWARF_BLOCK (call_site->target, dlbaton);
+ }
+ else if (is_ref_attr (attr))
+ {
+ struct objfile *objfile = cu->objfile;
+ struct dwarf2_cu *target_cu = cu;
+ struct die_info *target_die;
+
+ target_die = follow_die_ref_or_sig (die, attr, &target_cu);
+ gdb_assert (target_cu->objfile == objfile);
+ if (die_is_declaration (target_die, target_cu))
+ {
+ const char *target_physname;
+
+ target_physname = dwarf2_physname (NULL, target_die, target_cu);
+ if (target_physname == NULL)
+ complaint (&symfile_complaints,
+ _("DW_AT_GNU_call_site_target target DIE has invalid "
+ "physname, for referencing DIE 0x%x [in module %s]"),
+ die->offset, cu->objfile->name);
+ else
+ SET_FIELD_PHYSNAME (call_site->target, (char *) target_physname);
+ }
+ else
+ {
+ CORE_ADDR lowpc;
+
+ /* DW_AT_entry_pc should be preferred. */
+ if (!dwarf2_get_pc_bounds (target_die, &lowpc, NULL, target_cu, NULL))
+ complaint (&symfile_complaints,
+ _("DW_AT_GNU_call_site_target target DIE has invalid "
+ "low pc, for referencing DIE 0x%x [in module %s]"),
+ die->offset, cu->objfile->name);
+ else
+ SET_FIELD_PHYSADDR (call_site->target, lowpc + baseaddr);
+ }
+ }
+ else
+ complaint (&symfile_complaints,
+ _("DW_TAG_GNU_call_site DW_AT_GNU_call_site_target is neither "
+ "block nor reference, for DIE 0x%x [in module %s]"),
+ die->offset, cu->objfile->name);
+
+ call_site->per_cu = cu->per_cu;
+
+ for (child_die = die->child;
+ child_die && child_die->tag;
+ child_die = sibling_die (child_die))
+ {
+ struct dwarf2_locexpr_baton *dlbaton;
+ struct call_site_parameter *parameter;
+
+ if (child_die->tag != DW_TAG_GNU_call_site_parameter)
+ {
+ /* Already printed the complaint above. */
+ continue;
+ }
+
+ gdb_assert (call_site->parameter_count < nparams);
+ parameter = &call_site->parameter[call_site->parameter_count];
+
+ /* DW_AT_location specifies the register number. Value of the data
+ assumed for the register is contained in DW_AT_GNU_call_site_value. */
+
+ attr = dwarf2_attr (child_die, DW_AT_location, cu);
+ if (!attr || !attr_form_is_block (attr))
+ {
+ complaint (&symfile_complaints,
+ _("No DW_FORM_block* DW_AT_location for "
+ "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
+ child_die->offset, cu->objfile->name);
+ continue;
+ }
+ parameter->dwarf_reg = dwarf_block_to_dwarf_reg (DW_BLOCK (attr)->data,
+ &DW_BLOCK (attr)->data[DW_BLOCK (attr)->size]);
+ if (parameter->dwarf_reg == -1
+ && !dwarf_block_to_sp_offset (gdbarch, DW_BLOCK (attr)->data,
+ &DW_BLOCK (attr)->data[DW_BLOCK (attr)->size],
+ ¶meter->fb_offset))
+ {
+ complaint (&symfile_complaints,
+ _("Only single DW_OP_reg or DW_OP_fbreg is supported "
+ "for DW_FORM_block* DW_AT_location for "
+ "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
+ child_die->offset, cu->objfile->name);
+ continue;
+ }
+
+ attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_value, cu);
+ if (!attr_form_is_block (attr))
+ {
+ complaint (&symfile_complaints,
+ _("No DW_FORM_block* DW_AT_GNU_call_site_value for "
+ "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
+ child_die->offset, cu->objfile->name);
+ continue;
+ }
+ parameter->value = DW_BLOCK (attr)->data;
+ parameter->value_size = DW_BLOCK (attr)->size;
+
+ /* Parameters are not pre-cleared by memset above. */
+ parameter->data_value = NULL;
+ parameter->data_value_size = 0;
+ call_site->parameter_count++;
+
+ attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_data_value, cu);
+ if (attr)
+ {
+ if (!attr_form_is_block (attr))
+ complaint (&symfile_complaints,
+ _("No DW_FORM_block* DW_AT_GNU_call_site_data_value for "
+ "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
+ child_die->offset, cu->objfile->name);
+ else
+ {
+ parameter->data_value = DW_BLOCK (attr)->data;
+ parameter->data_value_size = DW_BLOCK (attr)->size;
+ }
+ }
+ }
+}
+