103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Function return value location for Linux/TILE-Gx ABI.
203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Copyright (C) 2012 Tilera Corporation
303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Copyright (C) 2014 Red Hat, Inc.
403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is part of elfutils.
503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is free software; you can redistribute it and/or modify
703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   it under the terms of either
803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU Lesser General Public License as published by the Free
1003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 3 of the License, or (at
1103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or
1403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU General Public License as published by the Free
1603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 2 of the License, or (at
1703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or both in parallel, as here.
2003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
2103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   elfutils is distributed in the hope that it will be useful, but
2203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   WITHOUT ANY WARRANTY; without even the implied warranty of
2303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   General Public License for more details.
2503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
2603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   You should have received copies of the GNU General Public License and
2703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   the GNU Lesser General Public License along with this program.  If
2803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   not, see <http://www.gnu.org/licenses/>.  */
2903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#ifdef HAVE_CONFIG_H
3203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes# include <config.h>
3303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#endif
3403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <assert.h>
3603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <dwarf.h>
3703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define BACKEND tilegx_
3903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include "libebl_CPU.h"
4003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
4103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
4203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* r0.  */
4303333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic const Dwarf_Op loc_intreg[] =
4403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  {
4503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    { .atom = DW_OP_reg0 }
4603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  };
4703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define nloc_intreg	1
4803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
4903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* The return value is a structure and is actually stored in stack space
5003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   passed in a hidden argument by the caller.  But, the compiler
5103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   helpfully returns the address of that space in r0.  */
5203333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic const Dwarf_Op loc_aggregate[] =
5303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  {
5403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    { .atom = DW_OP_breg0, .number = 0 }
5503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  };
5603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define nloc_aggregate 1
5703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
5803333823c75a1c1887e923828113a1b0fd12020cElliott Hughesint
5903333823c75a1c1887e923828113a1b0fd12020cElliott Hughestilegx_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
6003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
6103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* Start with the function's type, and get the DW_AT_type attribute,
6203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     which is the type of the return value.  */
6303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Die die_mem, *typedie = &die_mem;
6403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int tag = dwarf_peeled_die_type (functypedie, typedie);
6503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (tag <= 0)
6603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return tag;
6703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
6803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Word size;
6903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  switch (tag)
7003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
7103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case -1:
7203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return -1;
7303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
7403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_subrange_type:
7503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
7603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
7703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  Dwarf_Attribute attr_mem, *attr;
7803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
7903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  typedie = dwarf_formref_die (attr, &die_mem);
8003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  tag = DWARF_TAG_OR_RETURN (typedie);
8103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
8203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* Fall through.  */
8303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
8403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_base_type:
8503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_enumeration_type:
8603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_pointer_type:
8703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_ptr_to_member_type:
8803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      {
8903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	Dwarf_Attribute attr_mem;
9003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
9103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						   &attr_mem), &size) != 0)
9203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  {
9303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
9403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      size = 8;
9503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    else
9603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      return -1;
9703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  }
9803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	if (tag == DW_TAG_base_type)
9903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  {
10003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    Dwarf_Word encoding;
10103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
10203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						       &attr_mem),
10303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes				 &encoding) != 0)
10403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      return -1;
10503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  }
10603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      }
10703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
10803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* Small enough structs are passed directly in registers R0 ... R7.  */
10903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (size <= 8)
11003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
11103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	intreg:
11203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  *locp = loc_intreg;
11303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  return nloc_intreg;
11403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
11503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
11603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* Else fall through.  */
11703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_structure_type:
11803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_class_type:
11903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_union_type:
12003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    aggregate:
12103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      *locp = loc_aggregate;
12203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return nloc_aggregate;
12303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
12403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_array_type:
12503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DW_TAG_string_type:
12603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (dwarf_aggregate_size (typedie, &size) == 0 && size <= 8)
12703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
12803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (tag == DW_TAG_array_type)
12903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
13003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      Dwarf_Attribute attr_mem, *attr;
13103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      /* Check if it's a character array.  */
13203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
13303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      typedie = dwarf_formref_die (attr, &die_mem);
13403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      tag = DWARF_TAG_OR_RETURN (typedie);
13503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (tag != DW_TAG_base_type)
13603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		goto aggregate;
13703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (dwarf_formudata (dwarf_attr_integrate (typedie,
13803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes							 DW_AT_byte_size,
13903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes							 &attr_mem),
14003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes				   &size) != 0)
14103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		return -1;
14203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (size != 1)
14303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		goto aggregate;
14403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
14503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  goto intreg;
14603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
14703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      goto aggregate;
14803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
14903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
15003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* XXX We don't have a good way to return specific errors from ebl calls.
15103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     This value means we do not understand the type, but it is well-formed
15203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     DWARF and might be valid.  */
15303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return -2;
15403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
155