* ecoff.c (ecoff_set_symbol_info): Mark local stProc or stLabel

symbols as BSF_DEBUGGING.
PR 5769.
This commit is contained in:
Ian Lance Taylor
1994-10-12 21:51:04 +00:00
parent ef4b8f6687
commit 7b18561f3b
2 changed files with 307 additions and 118 deletions

View File

@ -7,6 +7,9 @@ Wed Oct 12 16:46:43 1994 Ken Raeburn <raeburn@cujo.cygnus.com>
Wed Oct 12 11:54:37 1994 Ian Lance Taylor <ian@sanguine.cygnus.com> Wed Oct 12 11:54:37 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
* ecoff.c (ecoff_set_symbol_info): Mark local stProc or stLabel
symbols as BSF_DEBUGGING.
* rs6000-core.c (rs6000coff_core_file_matches_executable_p): Make * rs6000-core.c (rs6000coff_core_file_matches_executable_p): Make
str1 and str2 const pointers. str1 and str2 const pointers.

View File

@ -25,6 +25,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "libbfd.h" #include "libbfd.h"
#include "aout/ar.h" #include "aout/ar.h"
#include "aout/ranlib.h" #include "aout/ranlib.h"
#include "aout/stab_gnu.h"
/* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines /* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines
some other stuff which we don't want and which conflicts with stuff some other stuff which we don't want and which conflicts with stuff
@ -152,14 +153,17 @@ _bfd_ecoff_new_section_hook (abfd, section)
asection *section; asection *section;
{ {
/* For the .pdata section, which has a special meaning on the Alpha, /* For the .pdata section, which has a special meaning on the Alpha,
we set the alignment to 8. We correct this later in we set the alignment power to 3. We correct this later in
ecoff_compute_section_file_positions. We do this hackery because ecoff_compute_section_file_positions. We do this hackery because
we need to know the exact unaligned size of the .pdata section in we need to know the exact unaligned size of the .pdata section in
order to set the lnnoptr field correctly. */ order to set the lnnoptr field correctly. For every other
section we use an alignment power of 4; this could be made target
dependent by adding a field to ecoff_backend_data, but 4 appears
to be correct for both the MIPS and the Alpha. */
if (strcmp (section->name, _PDATA) == 0) if (strcmp (section->name, _PDATA) == 0)
section->alignment_power = 3; section->alignment_power = 3;
else else
section->alignment_power = abfd->xvec->align_power_min; section->alignment_power = 4;
if (strcmp (section->name, _TEXT) == 0) if (strcmp (section->name, _TEXT) == 0)
section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
@ -340,9 +344,10 @@ ecoff_sec_to_styp_flags (name, flags)
/*ARGSUSED*/ /*ARGSUSED*/
flagword flagword
_bfd_ecoff_styp_to_sec_flags (abfd, hdr) _bfd_ecoff_styp_to_sec_flags (abfd, hdr, name)
bfd *abfd; bfd *abfd;
PTR hdr; PTR hdr;
const char *name;
{ {
struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
long styp_flags = internal_s->s_flags; long styp_flags = internal_s->s_flags;
@ -871,7 +876,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
(*indirect_ptr_ptr)->value = (bfd_vma) asym; (*indirect_ptr_ptr)->value = (bfd_vma) asym;
asym->flags = BSF_DEBUGGING; asym->flags = BSF_DEBUGGING;
asym->section = &bfd_und_section; asym->section = bfd_und_section_ptr;
*indirect_ptr_ptr = NULL; *indirect_ptr_ptr = NULL;
return true; return true;
} }
@ -880,7 +885,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
&& (ECOFF_UNMARK_STAB (ecoff_sym->index) | N_EXT) == (N_INDR | N_EXT)) && (ECOFF_UNMARK_STAB (ecoff_sym->index) | N_EXT) == (N_INDR | N_EXT))
{ {
asym->flags = BSF_DEBUGGING | BSF_INDIRECT; asym->flags = BSF_DEBUGGING | BSF_INDIRECT;
asym->section = &bfd_ind_section; asym->section = bfd_ind_section_ptr;
/* Pass this symbol on to the next call to this function. */ /* Pass this symbol on to the next call to this function. */
*indirect_ptr_ptr = asym; *indirect_ptr_ptr = asym;
return true; return true;
@ -910,7 +915,18 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
if (ext) if (ext)
asym->flags = BSF_EXPORT | BSF_GLOBAL; asym->flags = BSF_EXPORT | BSF_GLOBAL;
else else
asym->flags = BSF_LOCAL; {
asym->flags = BSF_LOCAL;
/* Normally, a local stProc symbol will have a corresponding
external symbol. We mark the local symbol as a debugging
symbol, in order to prevent nm from printing both out.
Similarly, we mark stLabel fields as debugging symbols. In
both cases, we do want to set the value correctly based on
the symbol class. */
if (ecoff_sym->st == stProc
|| ecoff_sym->st == stLabel)
asym->flags |= BSF_DEBUGGING;
}
switch (ecoff_sym->sc) switch (ecoff_sym->sc)
{ {
case scNil: case scNil:
@ -936,10 +952,10 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
asym->flags = BSF_DEBUGGING; asym->flags = BSF_DEBUGGING;
break; break;
case scAbs: case scAbs:
asym->section = &bfd_abs_section; asym->section = bfd_abs_section_ptr;
break; break;
case scUndefined: case scUndefined:
asym->section = &bfd_und_section; asym->section = bfd_und_section_ptr;
asym->flags = 0; asym->flags = 0;
asym->value = 0; asym->value = 0;
break; break;
@ -969,7 +985,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
case scCommon: case scCommon:
if (asym->value > ecoff_data (abfd)->gp_size) if (asym->value > ecoff_data (abfd)->gp_size)
{ {
asym->section = &bfd_com_section; asym->section = bfd_com_section_ptr;
asym->flags = 0; asym->flags = 0;
break; break;
} }
@ -996,7 +1012,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
asym->flags = BSF_DEBUGGING; asym->flags = BSF_DEBUGGING;
break; break;
case scSUndefined: case scSUndefined:
asym->section = &bfd_und_section; asym->section = bfd_und_section_ptr;
asym->flags = 0; asym->flags = 0;
asym->value = 0; asym->value = 0;
break; break;
@ -1895,7 +1911,7 @@ ecoff_slurp_reloc_table (abfd, section, symbols)
else if (intern.r_symndx == RELOC_SECTION_NONE else if (intern.r_symndx == RELOC_SECTION_NONE
|| intern.r_symndx == RELOC_SECTION_ABS) || intern.r_symndx == RELOC_SECTION_ABS)
{ {
rptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr; rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
rptr->addend = 0; rptr->addend = 0;
} }
else else
@ -2003,18 +2019,12 @@ _bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
{ {
const struct ecoff_debug_swap * const debug_swap const struct ecoff_debug_swap * const debug_swap
= &ecoff_backend (abfd)->debug_swap; = &ecoff_backend (abfd)->debug_swap;
struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info;
FDR *fdr_ptr; FDR *fdr_ptr;
FDR *fdr_start; FDR *fdr_start;
FDR *fdr_end; FDR *fdr_end;
FDR *fdr_hold; FDR *fdr_hold;
bfd_size_type external_pdr_size; boolean stabs;
char *pdr_ptr;
char *pdr_end;
PDR pdr;
bfd_vma first_off;
unsigned char *line_ptr;
unsigned char *line_end;
int lineno;
/* If we're not in the .text section, we don't have any line /* If we're not in the .text section, we don't have any line
numbers. */ numbers. */
@ -2024,8 +2034,7 @@ _bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
return false; return false;
/* Make sure we have the FDR's. */ /* Make sure we have the FDR's. */
if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL, if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL, debug_info)
&ecoff_data (abfd)->debug_info)
|| bfd_get_symcount (abfd) == 0) || bfd_get_symcount (abfd) == 0)
return false; return false;
@ -2034,8 +2043,8 @@ _bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
memory order. If speed is ever important, this can become a memory order. If speed is ever important, this can become a
binary search. We must ignore FDR's with no PDR entries; they binary search. We must ignore FDR's with no PDR entries; they
will have the adr of the FDR before or after them. */ will have the adr of the FDR before or after them. */
fdr_start = ecoff_data (abfd)->debug_info.fdr; fdr_start = debug_info->fdr;
fdr_end = fdr_start + ecoff_data (abfd)->debug_info.symbolic_header.ifdMax; fdr_end = fdr_start + debug_info->symbolic_header.ifdMax;
fdr_hold = (FDR *) NULL; fdr_hold = (FDR *) NULL;
for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
{ {
@ -2049,112 +2058,289 @@ _bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
return false; return false;
fdr_ptr = fdr_hold; fdr_ptr = fdr_hold;
/* Each FDR has a list of procedure descriptors (PDR). PDR's also /* Check whether this file has stabs debugging information. In a
have an address, which is relative to the FDR address, and are file with stabs debugging information, the second local symbol is
also stored in increasing memory order. */ named @stabs. */
offset -= fdr_ptr->adr; stabs = false;
external_pdr_size = debug_swap->external_pdr_size; if (fdr_ptr->csym >= 2)
pdr_ptr = ((char *) ecoff_data (abfd)->debug_info.external_pdr
+ fdr_ptr->ipdFirst * external_pdr_size);
pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
(*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
if (offset < pdr.adr)
return false;
/* The address of the first PDR is an offset which applies to the
addresses of all the PDR's. */
first_off = pdr.adr;
for (pdr_ptr += external_pdr_size;
pdr_ptr < pdr_end;
pdr_ptr += external_pdr_size)
{ {
char *sym_ptr;
SYMR sym;
sym_ptr = ((char *) debug_info->external_sym
+ (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size);
(*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss,
STABS_SYMBOL) == 0)
stabs = true;
}
if (! stabs)
{
bfd_size_type external_pdr_size;
char *pdr_ptr;
char *pdr_end;
PDR pdr;
bfd_vma first_off;
unsigned char *line_ptr;
unsigned char *line_end;
int lineno;
/* This file uses ECOFF debugging information. Each FDR has a
list of procedure descriptors (PDR). PDR's also have an
address, which is relative to the FDR address, and are also
stored in increasing memory order. */
offset -= fdr_ptr->adr;
external_pdr_size = debug_swap->external_pdr_size;
pdr_ptr = ((char *) debug_info->external_pdr
+ fdr_ptr->ipdFirst * external_pdr_size);
pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
(*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
if (offset < pdr.adr) if (offset < pdr.adr)
break; return false;
}
/* Now we can look for the actual line number. The line numbers are /* The address of the first PDR is an offset which applies to
stored in a very funky format, which I won't try to describe. the addresses of all the PDR's. */
Note that right here pdr_ptr and pdr hold the PDR *after* the one first_off = pdr.adr;
we want; we need this to compute line_end. */
line_end = ecoff_data (abfd)->debug_info.line;
if (pdr_ptr == pdr_end)
line_end += fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
else
line_end += fdr_ptr->cbLineOffset + pdr.cbLineOffset;
/* Now change pdr and pdr_ptr to the one we want. */ for (pdr_ptr += external_pdr_size;
pdr_ptr -= external_pdr_size; pdr_ptr < pdr_end;
(*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); pdr_ptr += external_pdr_size)
offset -= pdr.adr - first_off;
lineno = pdr.lnLow;
line_ptr = (ecoff_data (abfd)->debug_info.line
+ fdr_ptr->cbLineOffset
+ pdr.cbLineOffset);
while (line_ptr < line_end)
{
int delta;
int count;
delta = *line_ptr >> 4;
if (delta >= 0x8)
delta -= 0x10;
count = (*line_ptr & 0xf) + 1;
++line_ptr;
if (delta == -8)
{ {
delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff); (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
if (delta >= 0x8000) if (offset < pdr.adr)
delta -= 0x10000; break;
line_ptr += 2;
} }
lineno += delta;
if (offset < count * 4)
break;
offset -= count * 4;
}
/* If fdr_ptr->rss is -1, then this file does not have full symbols, /* Now we can look for the actual line number. The line numbers
at least according to gdb/mipsread.c. */ are stored in a very funky format, which I won't try to
if (fdr_ptr->rss == -1) describe. Note that right here pdr_ptr and pdr hold the PDR
{ *after* the one we want; we need this to compute line_end. */
*filename_ptr = NULL; line_end = debug_info->line;
if (pdr.isym == -1) if (pdr_ptr == pdr_end)
*functionname_ptr = NULL; line_end += fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
else
line_end += fdr_ptr->cbLineOffset + pdr.cbLineOffset;
/* Now change pdr and pdr_ptr to the one we want. */
pdr_ptr -= external_pdr_size;
(*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
offset -= pdr.adr - first_off;
lineno = pdr.lnLow;
line_ptr = debug_info->line + fdr_ptr->cbLineOffset + pdr.cbLineOffset;
while (line_ptr < line_end)
{
int delta;
int count;
delta = *line_ptr >> 4;
if (delta >= 0x8)
delta -= 0x10;
count = (*line_ptr & 0xf) + 1;
++line_ptr;
if (delta == -8)
{
delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff);
if (delta >= 0x8000)
delta -= 0x10000;
line_ptr += 2;
}
lineno += delta;
if (offset < count * 4)
break;
offset -= count * 4;
}
/* If fdr_ptr->rss is -1, then this file does not have full
symbols, at least according to gdb/mipsread.c. */
if (fdr_ptr->rss == -1)
{
*filename_ptr = NULL;
if (pdr.isym == -1)
*functionname_ptr = NULL;
else
{
EXTR proc_ext;
(*debug_swap->swap_ext_in)
(abfd,
((char *) debug_info->external_ext
+ pdr.isym * debug_swap->external_ext_size),
&proc_ext);
*functionname_ptr = debug_info->ssext + proc_ext.asym.iss;
}
}
else else
{ {
EXTR proc_ext; SYMR proc_sym;
(*debug_swap->swap_ext_in) *filename_ptr = debug_info->ss + fdr_ptr->issBase + fdr_ptr->rss;
(*debug_swap->swap_sym_in)
(abfd, (abfd,
((char *) ecoff_data (abfd)->debug_info.external_ext ((char *) debug_info->external_sym
+ pdr.isym * debug_swap->external_ext_size), + (fdr_ptr->isymBase + pdr.isym) * debug_swap->external_sym_size),
&proc_ext); &proc_sym);
*functionname_ptr = (ecoff_data (abfd)->debug_info.ssext *functionname_ptr = debug_info->ss + fdr_ptr->issBase + proc_sym.iss;
+ proc_ext.asym.iss);
} }
if (lineno == ilineNil)
lineno = 0;
*retline_ptr = lineno;
} }
else else
{ {
SYMR proc_sym; bfd_size_type external_sym_size;
const char *directory_name;
const char *main_file_name;
const char *current_file_name;
const char *function_name;
const char *line_file_name;
bfd_vma low_func_vma;
bfd_vma low_line_vma;
char *sym_ptr, *sym_ptr_end;
size_t len, funclen;
char *buffer = NULL;
*filename_ptr = (ecoff_data (abfd)->debug_info.ss /* This file uses stabs debugging information. */
+ fdr_ptr->issBase
+ fdr_ptr->rss); *filename_ptr = NULL;
(*debug_swap->swap_sym_in) *functionname_ptr = NULL;
(abfd, *retline_ptr = 0;
((char *) ecoff_data (abfd)->debug_info.external_sym
+ (fdr_ptr->isymBase + pdr.isym) * debug_swap->external_sym_size), directory_name = NULL;
&proc_sym); main_file_name = NULL;
*functionname_ptr = (ecoff_data (abfd)->debug_info.ss current_file_name = NULL;
+ fdr_ptr->issBase function_name = NULL;
+ proc_sym.iss); line_file_name = NULL;
low_func_vma = 0;
low_line_vma = 0;
external_sym_size = debug_swap->external_sym_size;
sym_ptr = ((char *) debug_info->external_sym
+ (fdr_ptr->isymBase + 2) * external_sym_size);
sym_ptr_end = sym_ptr + fdr_ptr->csym * external_sym_size;
for (; sym_ptr < sym_ptr_end; sym_ptr += external_sym_size)
{
SYMR sym;
(*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
if (ECOFF_IS_STAB (&sym))
{
switch (ECOFF_UNMARK_STAB (sym.index))
{
case N_SO:
main_file_name = current_file_name =
debug_info->ss + fdr_ptr->issBase + sym.iss;
/* Check the next symbol to see if it is also an
N_SO symbol. */
if (sym_ptr + external_sym_size < sym_ptr_end)
{
SYMR nextsym;
(*debug_swap->swap_sym_in) (abfd,
sym_ptr + external_sym_size,
&nextsym);
if (ECOFF_IS_STAB (&nextsym)
&& ECOFF_UNMARK_STAB (nextsym.index) == N_SO)
{
directory_name = current_file_name;
main_file_name = current_file_name =
debug_info->ss + fdr_ptr->issBase + sym.iss;
sym_ptr += external_sym_size;
}
}
break;
case N_SOL:
current_file_name =
debug_info->ss + fdr_ptr->issBase + sym.iss;
break;
case N_FUN:
if (sym.value >= low_func_vma
&& sym.value <= offset + section->vma)
{
low_func_vma = sym.value;
function_name =
debug_info->ss + fdr_ptr->issBase + sym.iss;
}
break;
}
}
else if (sym.st == stLabel && sym.index != indexNil)
{
if (sym.value > offset + section->vma)
{
/* We have passed the location in the file we are
looking for, so we can get out of the loop. */
break;
}
if (sym.value >= low_line_vma)
{
low_line_vma = sym.value;
line_file_name = current_file_name;
*retline_ptr = sym.index;
}
}
}
if (*retline_ptr != 0)
main_file_name = line_file_name;
/* We need to remove the stuff after the colon in the function
name. We also need to put the directory name and the file
name together. */
if (function_name == NULL)
len = funclen = 0;
else
len = funclen = strlen (function_name) + 1;
if (main_file_name != NULL
&& directory_name != NULL
&& main_file_name[0] != '/')
len += strlen (directory_name) + strlen (main_file_name) + 1;
if (len != 0)
{
if (ecoff_data (abfd)->find_buffer != NULL)
free (ecoff_data (abfd)->find_buffer);
buffer = (char *) malloc (len);
if (buffer == NULL)
{
bfd_set_error (bfd_error_no_memory);
return false;
}
ecoff_data (abfd)->find_buffer = buffer;
}
if (function_name != NULL)
{
char *colon;
strcpy (buffer, function_name);
colon = strchr (buffer, ':');
if (colon != NULL)
*colon = '\0';
*functionname_ptr = buffer;
}
if (main_file_name != NULL)
{
if (directory_name == NULL || main_file_name[0] == '/')
*filename_ptr = main_file_name;
else
{
sprintf (buffer + funclen, "%s%s", directory_name,
main_file_name);
*filename_ptr = buffer + funclen;
}
}
} }
if (lineno == ilineNil)
lineno = 0;
*retline_ptr = lineno;
return true; return true;
} }
@ -2617,7 +2803,7 @@ ecoff_get_extr (sym, esym)
symbol. */ symbol. */
if ((esym->asym.sc == scUndefined if ((esym->asym.sc == scUndefined
|| esym->asym.sc == scSUndefined) || esym->asym.sc == scSUndefined)
&& bfd_get_section (sym) != &bfd_und_section) && ! bfd_is_und_section (bfd_get_section (sym)))
esym->asym.sc = scAbs; esym->asym.sc = scAbs;
/* Adjust the FDR index for the symbol by that used for the input /* Adjust the FDR index for the symbol by that used for the input
@ -4099,10 +4285,10 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext)
value -= section->vma; value -= section->vma;
break; break;
case scAbs: case scAbs:
section = &bfd_abs_section; section = bfd_abs_section_ptr;
break; break;
case scUndefined: case scUndefined:
section = &bfd_und_section; section = bfd_und_section_ptr;
break; break;
case scSData: case scSData:
section = bfd_make_section_old_way (abfd, ".sdata"); section = bfd_make_section_old_way (abfd, ".sdata");
@ -4119,7 +4305,7 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext)
case scCommon: case scCommon:
if (value > ecoff_data (abfd)->gp_size) if (value > ecoff_data (abfd)->gp_size)
{ {
section = &bfd_com_section; section = bfd_com_section_ptr;
break; break;
} }
/* Fall through. */ /* Fall through. */
@ -4140,7 +4326,7 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext)
section = &ecoff_scom_section; section = &ecoff_scom_section;
break; break;
case scSUndefined: case scSUndefined:
section = &bfd_und_section; section = bfd_und_section_ptr;
break; break;
case scInit: case scInit:
section = bfd_make_section_old_way (abfd, ".init"); section = bfd_make_section_old_way (abfd, ".init");
@ -4171,7 +4357,7 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext)
if (info->hash->creator->flavour == bfd_get_flavour (abfd)) if (info->hash->creator->flavour == bfd_get_flavour (abfd))
{ {
if (h->abfd == (bfd *) NULL if (h->abfd == (bfd *) NULL
|| (section != &bfd_und_section || (! bfd_is_und_section (section)
&& (! bfd_is_com_section (section) && (! bfd_is_com_section (section)
|| h->root.type != bfd_link_hash_defined))) || h->root.type != bfd_link_hash_defined)))
{ {