Home | History | Annotate | Download | only in dwarf
      1 // Copyright (c) 2012, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // Original author: Jim Blandy <jimb (at) mozilla.com> <jimb (at) red-bean.com>
     31 
     32 // dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit
     33 
     34 #include <stdlib.h>
     35 
     36 #include <iostream>
     37 #include <string>
     38 #include <vector>
     39 
     40 #include "breakpad_googletest_includes.h"
     41 #include "common/dwarf/bytereader-inl.h"
     42 #include "common/dwarf/dwarf2reader_test_common.h"
     43 #include "common/dwarf/dwarf2reader.h"
     44 #include "common/using_std_string.h"
     45 #include "google_breakpad/common/breakpad_types.h"
     46 
     47 using google_breakpad::test_assembler::Endianness;
     48 using google_breakpad::test_assembler::Label;
     49 using google_breakpad::test_assembler::Section;
     50 using google_breakpad::test_assembler::kBigEndian;
     51 using google_breakpad::test_assembler::kLittleEndian;
     52 
     53 using dwarf2reader::ByteReader;
     54 using dwarf2reader::CompilationUnit;
     55 using dwarf2reader::Dwarf2Handler;
     56 using dwarf2reader::DwarfAttribute;
     57 using dwarf2reader::DwarfForm;
     58 using dwarf2reader::DwarfHasChild;
     59 using dwarf2reader::DwarfTag;
     60 using dwarf2reader::ENDIANNESS_BIG;
     61 using dwarf2reader::ENDIANNESS_LITTLE;
     62 using dwarf2reader::SectionMap;
     63 
     64 using std::vector;
     65 using testing::InSequence;
     66 using testing::Pointee;
     67 using testing::Return;
     68 using testing::Sequence;
     69 using testing::Test;
     70 using testing::TestWithParam;
     71 using testing::_;
     72 
     73 class MockDwarf2Handler: public Dwarf2Handler {
     74  public:
     75   MOCK_METHOD5(StartCompilationUnit, bool(uint64 offset, uint8 address_size,
     76                                           uint8 offset_size, uint64 cu_length,
     77                                           uint8 dwarf_version));
     78   MOCK_METHOD2(StartDIE, bool(uint64 offset, enum DwarfTag tag));
     79   MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64 offset,
     80                                               DwarfAttribute attr,
     81                                               enum DwarfForm form,
     82                                               uint64 data));
     83   MOCK_METHOD4(ProcessAttributeSigned, void(uint64 offset,
     84                                             enum DwarfAttribute attr,
     85                                             enum DwarfForm form,
     86                                             int64 data));
     87   MOCK_METHOD4(ProcessAttributeReference, void(uint64 offset,
     88                                                enum DwarfAttribute attr,
     89                                                enum DwarfForm form,
     90                                                uint64 data));
     91   MOCK_METHOD5(ProcessAttributeBuffer, void(uint64 offset,
     92                                             enum DwarfAttribute attr,
     93                                             enum DwarfForm form,
     94                                             const char* data,
     95                                             uint64 len));
     96   MOCK_METHOD4(ProcessAttributeString, void(uint64 offset,
     97                                             enum DwarfAttribute attr,
     98                                             enum DwarfForm form,
     99                                             const string& data));
    100   MOCK_METHOD4(ProcessAttributeSignature, void(uint64 offset,
    101                                                DwarfAttribute attr,
    102                                                enum DwarfForm form,
    103                                                uint64 signature));
    104   MOCK_METHOD1(EndDIE, void(uint64 offset));
    105 };
    106 
    107 struct DIEFixture {
    108 
    109   DIEFixture() {
    110     // Fix the initial offset of the .debug_info and .debug_abbrev sections.
    111     info.start() = 0;
    112     abbrevs.start() = 0;
    113 
    114     // Default expectations for the data handler.
    115     EXPECT_CALL(handler, StartCompilationUnit(_, _, _, _, _)).Times(0);
    116     EXPECT_CALL(handler, StartDIE(_, _)).Times(0);
    117     EXPECT_CALL(handler, ProcessAttributeUnsigned(_, _, _, _)).Times(0);
    118     EXPECT_CALL(handler, ProcessAttributeSigned(_, _, _, _)).Times(0);
    119     EXPECT_CALL(handler, ProcessAttributeReference(_, _, _, _)).Times(0);
    120     EXPECT_CALL(handler, ProcessAttributeBuffer(_, _, _, _, _)).Times(0);
    121     EXPECT_CALL(handler, ProcessAttributeString(_, _, _, _)).Times(0);
    122     EXPECT_CALL(handler, EndDIE(_)).Times(0);
    123   }
    124 
    125   // Return a reference to a section map whose .debug_info section refers
    126   // to |info|, and whose .debug_abbrev section refers to |abbrevs|. This
    127   // function returns a reference to the same SectionMap each time; new
    128   // calls wipe out maps established by earlier calls.
    129   const SectionMap &MakeSectionMap() {
    130     // Copy the sections' contents into strings that will live as long as
    131     // the map itself.
    132     assert(info.GetContents(&info_contents));
    133     assert(abbrevs.GetContents(&abbrevs_contents));
    134     section_map.clear();
    135     section_map[".debug_info"].first  = info_contents.data();
    136     section_map[".debug_info"].second = info_contents.size();
    137     section_map[".debug_abbrev"].first  = abbrevs_contents.data();
    138     section_map[".debug_abbrev"].second = abbrevs_contents.size();
    139     return section_map;
    140   }
    141 
    142   TestCompilationUnit info;
    143   TestAbbrevTable abbrevs;
    144   MockDwarf2Handler handler;
    145   string abbrevs_contents, info_contents;
    146   SectionMap section_map;
    147 };
    148 
    149 struct DwarfHeaderParams {
    150   DwarfHeaderParams(Endianness endianness, size_t format_size,
    151                    int version, size_t address_size)
    152       : endianness(endianness), format_size(format_size),
    153         version(version), address_size(address_size) { }
    154   Endianness endianness;
    155   size_t format_size;                   // 4-byte or 8-byte DWARF offsets
    156   int version;
    157   size_t address_size;
    158 };
    159 
    160 class DwarfHeader: public DIEFixture,
    161                    public TestWithParam<DwarfHeaderParams> { };
    162 
    163 TEST_P(DwarfHeader, Header) {
    164   Label abbrev_table = abbrevs.Here();
    165   abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit,
    166                  dwarf2reader::DW_children_yes)
    167       .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string)
    168       .EndAbbrev()
    169       .EndTable();
    170 
    171   info.set_format_size(GetParam().format_size);
    172   info.set_endianness(GetParam().endianness);
    173 
    174   info.Header(GetParam().version, abbrev_table, GetParam().address_size)
    175       .ULEB128(1)                     // DW_TAG_compile_unit, with children
    176       .AppendCString("sam")           // DW_AT_name, DW_FORM_string
    177       .D8(0);                         // end of children
    178   info.Finish();
    179 
    180   {
    181     InSequence s;
    182     EXPECT_CALL(handler,
    183                 StartCompilationUnit(0, GetParam().address_size,
    184                                      GetParam().format_size, _,
    185                                      GetParam().version))
    186         .WillOnce(Return(true));
    187     EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit))
    188         .WillOnce(Return(true));
    189     EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name,
    190                                                 dwarf2reader::DW_FORM_string,
    191                                                 "sam"))
    192         .WillOnce(Return());
    193     EXPECT_CALL(handler, EndDIE(_))
    194         .WillOnce(Return());
    195   }
    196 
    197   ByteReader byte_reader(GetParam().endianness == kLittleEndian ?
    198                          ENDIANNESS_LITTLE : ENDIANNESS_BIG);
    199   CompilationUnit parser(MakeSectionMap(), 0, &byte_reader, &handler);
    200   EXPECT_EQ(parser.Start(), info_contents.size());
    201 }
    202 
    203 INSTANTIATE_TEST_CASE_P(
    204     HeaderVariants, DwarfHeader,
    205     ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
    206                       DwarfHeaderParams(kLittleEndian, 4, 2, 8),
    207                       DwarfHeaderParams(kLittleEndian, 4, 3, 4),
    208                       DwarfHeaderParams(kLittleEndian, 4, 3, 8),
    209                       DwarfHeaderParams(kLittleEndian, 4, 4, 4),
    210                       DwarfHeaderParams(kLittleEndian, 4, 4, 8),
    211                       DwarfHeaderParams(kLittleEndian, 8, 2, 4),
    212                       DwarfHeaderParams(kLittleEndian, 8, 2, 8),
    213                       DwarfHeaderParams(kLittleEndian, 8, 3, 4),
    214                       DwarfHeaderParams(kLittleEndian, 8, 3, 8),
    215                       DwarfHeaderParams(kLittleEndian, 8, 4, 4),
    216                       DwarfHeaderParams(kLittleEndian, 8, 4, 8),
    217                       DwarfHeaderParams(kBigEndian,    4, 2, 4),
    218                       DwarfHeaderParams(kBigEndian,    4, 2, 8),
    219                       DwarfHeaderParams(kBigEndian,    4, 3, 4),
    220                       DwarfHeaderParams(kBigEndian,    4, 3, 8),
    221                       DwarfHeaderParams(kBigEndian,    4, 4, 4),
    222                       DwarfHeaderParams(kBigEndian,    4, 4, 8),
    223                       DwarfHeaderParams(kBigEndian,    8, 2, 4),
    224                       DwarfHeaderParams(kBigEndian,    8, 2, 8),
    225                       DwarfHeaderParams(kBigEndian,    8, 3, 4),
    226                       DwarfHeaderParams(kBigEndian,    8, 3, 8),
    227                       DwarfHeaderParams(kBigEndian,    8, 4, 4),
    228                       DwarfHeaderParams(kBigEndian,    8, 4, 8)));
    229 
    230 struct DwarfFormsFixture: public DIEFixture {
    231   // Start a compilation unit, as directed by |params|, containing one
    232   // childless DIE of the given tag, with one attribute of the given name
    233   // and form. The 'info' fixture member is left just after the abbrev
    234   // code, waiting for the attribute value to be appended.
    235   void StartSingleAttributeDIE(const DwarfHeaderParams &params,
    236                                DwarfTag tag, DwarfAttribute name,
    237                                DwarfForm form) {
    238     // Create the abbreviation table.
    239     Label abbrev_table = abbrevs.Here();
    240     abbrevs.Abbrev(1, tag, dwarf2reader::DW_children_no)
    241         .Attribute(name, form)
    242         .EndAbbrev()
    243         .EndTable();
    244 
    245     // Create the compilation unit, up to the attribute value.
    246     info.set_format_size(params.format_size);
    247     info.set_endianness(params.endianness);
    248     info.Header(params.version, abbrev_table, params.address_size)
    249         .ULEB128(1);                    // abbrev code
    250   }
    251 
    252   // Set up handler to expect a compilation unit matching |params|,
    253   // containing one childless DIE of the given tag, in the sequence s. Stop
    254   // just before the expectations.
    255   void ExpectBeginCompilationUnit(const DwarfHeaderParams &params,
    256                                   DwarfTag tag, uint64 offset=0) {
    257     EXPECT_CALL(handler,
    258                 StartCompilationUnit(offset, params.address_size,
    259                                      params.format_size, _,
    260                                      params.version))
    261         .InSequence(s)
    262         .WillOnce(Return(true));
    263     EXPECT_CALL(handler, StartDIE(_, tag))
    264         .InSequence(s)
    265         .WillOnce(Return(true));
    266   }
    267 
    268   void ExpectEndCompilationUnit() {
    269     EXPECT_CALL(handler, EndDIE(_))
    270         .InSequence(s)
    271         .WillOnce(Return());
    272   }
    273 
    274   void ParseCompilationUnit(const DwarfHeaderParams &params, uint64 offset=0) {
    275     ByteReader byte_reader(params.endianness == kLittleEndian ?
    276                            ENDIANNESS_LITTLE : ENDIANNESS_BIG);
    277     CompilationUnit parser(MakeSectionMap(), offset, &byte_reader, &handler);
    278     EXPECT_EQ(offset + parser.Start(), info_contents.size());
    279   }
    280 
    281   // The sequence to which the fixture's methods append expectations.
    282   Sequence s;
    283 };
    284 
    285 struct DwarfForms: public DwarfFormsFixture,
    286                    public TestWithParam<DwarfHeaderParams> { };
    287 
    288 TEST_P(DwarfForms, addr) {
    289   StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit,
    290                           dwarf2reader::DW_AT_low_pc,
    291                           dwarf2reader::DW_FORM_addr);
    292   uint64_t value;
    293   if (GetParam().address_size == 4) {
    294     value = 0xc8e9ffcc;
    295     info.D32(value);
    296   } else {
    297     value = 0xe942517fc2768564ULL;
    298     info.D64(value);
    299   }
    300   info.Finish();
    301 
    302   ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit);
    303   EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc,
    304                                                 dwarf2reader::DW_FORM_addr,
    305                                                 value))
    306       .InSequence(s)
    307       .WillOnce(Return());
    308   ExpectEndCompilationUnit();
    309 
    310   ParseCompilationUnit(GetParam());
    311 }
    312 
    313 TEST_P(DwarfForms, block2_empty) {
    314   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
    315                           (DwarfAttribute) 0xe52c4463,
    316                           dwarf2reader::DW_FORM_block2);
    317   info.D16(0);
    318   info.Finish();
    319 
    320   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
    321   EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
    322                                               dwarf2reader::DW_FORM_block2,
    323                                               _, 0))
    324       .InSequence(s)
    325       .WillOnce(Return());
    326   ExpectEndCompilationUnit();
    327 
    328   ParseCompilationUnit(GetParam());
    329 }
    330 
    331 TEST_P(DwarfForms, block2) {
    332   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
    333                           (DwarfAttribute) 0xe52c4463,
    334                           dwarf2reader::DW_FORM_block2);
    335   unsigned char data[258];
    336   memset(data, '*', sizeof(data));
    337   info.D16(sizeof(data))
    338       .Append(data, sizeof(data));
    339   info.Finish();
    340 
    341   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
    342   EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
    343                                               dwarf2reader::DW_FORM_block2,
    344                                               Pointee('*'), 258))
    345       .InSequence(s)
    346       .WillOnce(Return());
    347   ExpectEndCompilationUnit();
    348 
    349   ParseCompilationUnit(GetParam());
    350 }
    351 
    352 TEST_P(DwarfForms, flag_present) {
    353   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2,
    354                           (DwarfAttribute) 0x359d1972,
    355                           dwarf2reader::DW_FORM_flag_present);
    356   // DW_FORM_flag_present occupies no space in the DIE.
    357   info.Finish();
    358 
    359   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2);
    360   EXPECT_CALL(handler,
    361               ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972,
    362                                        dwarf2reader::DW_FORM_flag_present,
    363                                        1))
    364       .InSequence(s)
    365       .WillOnce(Return());
    366   ExpectEndCompilationUnit();
    367 
    368   ParseCompilationUnit(GetParam());
    369 }
    370 
    371 TEST_P(DwarfForms, sec_offset) {
    372   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689,
    373                           (DwarfAttribute) 0xa060bfd1,
    374                           dwarf2reader::DW_FORM_sec_offset);
    375   uint64_t value;
    376   if (GetParam().format_size == 4) {
    377     value = 0xacc9c388;
    378     info.D32(value);
    379   } else {
    380     value = 0xcffe5696ffe3ed0aULL;
    381     info.D64(value);
    382   }
    383   info.Finish();
    384 
    385   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689);
    386   EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1,
    387                                                 dwarf2reader::DW_FORM_sec_offset,
    388                                                 value))
    389       .InSequence(s)
    390       .WillOnce(Return());
    391   ExpectEndCompilationUnit();
    392 
    393   ParseCompilationUnit(GetParam());
    394 }
    395 
    396 TEST_P(DwarfForms, exprloc) {
    397   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb,
    398                           (DwarfAttribute) 0xba3ae5cb,
    399                           dwarf2reader::DW_FORM_exprloc);
    400   info.ULEB128(29)
    401       .Append(29, 173);
    402   info.Finish();
    403 
    404   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb);
    405   EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb,
    406                                               dwarf2reader::DW_FORM_exprloc,
    407                                               Pointee(173), 29))
    408       .InSequence(s)
    409       .WillOnce(Return());
    410   ExpectEndCompilationUnit();
    411 
    412   ParseCompilationUnit(GetParam());
    413 }
    414 
    415 TEST_P(DwarfForms, ref_sig8) {
    416   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
    417                           (DwarfAttribute) 0xd708d908,
    418                           dwarf2reader::DW_FORM_ref_sig8);
    419   info.D64(0xf72fa0cb6ddcf9d6ULL);
    420   info.Finish();
    421 
    422   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
    423   EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
    424                                                  dwarf2reader::DW_FORM_ref_sig8,
    425                                                  0xf72fa0cb6ddcf9d6ULL))
    426       .InSequence(s)
    427       .WillOnce(Return());
    428   ExpectEndCompilationUnit();
    429 
    430   ParseCompilationUnit(GetParam());
    431 }
    432 
    433 // A value passed to ProcessAttributeSignature is just an absolute number,
    434 // not an offset within the compilation unit as most of the other
    435 // DW_FORM_ref forms are. Check that the reader doesn't try to apply any
    436 // offset to the signature, by reading it from a compilation unit that does
    437 // not start at the beginning of the section.
    438 TEST_P(DwarfForms, ref_sig8_not_first) {
    439   info.Append(98, '*');
    440   StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
    441                           (DwarfAttribute) 0xd708d908,
    442                           dwarf2reader::DW_FORM_ref_sig8);
    443   info.D64(0xf72fa0cb6ddcf9d6ULL);
    444   info.Finish();
    445 
    446   ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98);
    447   EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
    448                                                  dwarf2reader::DW_FORM_ref_sig8,
    449                                                  0xf72fa0cb6ddcf9d6ULL))
    450       .InSequence(s)
    451       .WillOnce(Return());
    452   ExpectEndCompilationUnit();
    453 
    454   ParseCompilationUnit(GetParam(), 98);
    455 }
    456 
    457 // Tests for the other attribute forms could go here.
    458 
    459 INSTANTIATE_TEST_CASE_P(
    460     HeaderVariants, DwarfForms,
    461     ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
    462                       DwarfHeaderParams(kLittleEndian, 4, 2, 8),
    463                       DwarfHeaderParams(kLittleEndian, 4, 3, 4),
    464                       DwarfHeaderParams(kLittleEndian, 4, 3, 8),
    465                       DwarfHeaderParams(kLittleEndian, 4, 4, 4),
    466                       DwarfHeaderParams(kLittleEndian, 4, 4, 8),
    467                       DwarfHeaderParams(kLittleEndian, 8, 2, 4),
    468                       DwarfHeaderParams(kLittleEndian, 8, 2, 8),
    469                       DwarfHeaderParams(kLittleEndian, 8, 3, 4),
    470                       DwarfHeaderParams(kLittleEndian, 8, 3, 8),
    471                       DwarfHeaderParams(kLittleEndian, 8, 4, 4),
    472                       DwarfHeaderParams(kLittleEndian, 8, 4, 8),
    473                       DwarfHeaderParams(kBigEndian,    4, 2, 4),
    474                       DwarfHeaderParams(kBigEndian,    4, 2, 8),
    475                       DwarfHeaderParams(kBigEndian,    4, 3, 4),
    476                       DwarfHeaderParams(kBigEndian,    4, 3, 8),
    477                       DwarfHeaderParams(kBigEndian,    4, 4, 4),
    478                       DwarfHeaderParams(kBigEndian,    4, 4, 8),
    479                       DwarfHeaderParams(kBigEndian,    8, 2, 4),
    480                       DwarfHeaderParams(kBigEndian,    8, 2, 8),
    481                       DwarfHeaderParams(kBigEndian,    8, 3, 4),
    482                       DwarfHeaderParams(kBigEndian,    8, 3, 8),
    483                       DwarfHeaderParams(kBigEndian,    8, 4, 4),
    484                       DwarfHeaderParams(kBigEndian,    8, 4, 8)));
    485