Coverage Report

Created: 2023-12-08 06:43

/src/libdwarf/src/lib/libdwarf/dwarf_generic_init.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
  Copyright (C) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
3
  Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
4
  Portions Copyright 2008-2010 Arxan Technologies, Inc. All rights reserved.
5
  Portions Copyright 2011-2020 David Anderson. All rights reserved.
6
  Portions Copyright 2012 SN Systems Ltd. All rights reserved.
7
8
  This program is free software; you can redistribute it
9
  and/or modify it under the terms of version 2.1 of the
10
  GNU Lesser General Public License as published by the Free
11
  Software Foundation.
12
13
  This program is distributed in the hope that it would be
14
  useful, but WITHOUT ANY WARRANTY; without even the implied
15
  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16
  PURPOSE.
17
18
  Further, this software is distributed without any warranty
19
  that it is free of the rightful claim of any third person
20
  regarding infringement or the like.  Any license provided
21
  herein, whether implied or otherwise, applies only to this
22
  software file.  Patent licenses, if any, provided herein
23
  do not apply to combinations of this program with other
24
  software, or any other product whatsoever.
25
26
  You should have received a copy of the GNU Lesser General
27
  Public License along with this program; if not, write the
28
  Free Software Foundation, Inc., 51 Franklin Street - Fifth
29
  Floor, Boston MA 02110-1301, USA.
30
31
*/
32
/*
33
Here is the deepest routes through dwarf_init_path_dl(),
34
depending on arguments.
35
It is called by dwarfdump to open an fd and return Dwarf_Debug.
36
Much of this is to handle GNU debuglink.
37
dwarf_init_path_dl(path true_path and globals, dbg1
38
    dwarf_object_detector_path_dSYM (dsym only(
39
        if returns DW_DLV_OK itis dSYM
40
    dwarf_object_detector_path_b( &debuglink with global paths.
41
        dwarf_object_detector_path_b  ftype
42
            check for dSYM if found it is the object to run on.
43
                dwarf_object_detector_fd (gets size ftype)
44
                return
45
            _dwarf_debuglink_finder_internal(TRUE passing
46
                in globals paths listr)
47
                new local dbg
48
                dwarf_init_path(path no dysm or debuglink
49
                    no global paths)
50
                    dwarf_object_detector_path_b( path  no dsym
51
                        or debuglink no global paths
52
                        dwarf_object_detector (path
53
                        dwarf_object_detector_fd (gets size ftype)
54
                    for each global pathin list, add to dbg
55
                    dwarf_gnu_debuglink(dbg
56
                        for each global path in debuglink list
57
                            _dwarf_debuglink_finder_internal(FALSE
58
                                no global paths)
59
                                if crc match return OK with
60
                                    pathname and fd returned
61
                                else return NO_ENTRY
62
*/
63
64
#include <config.h>
65
66
#include <stddef.h> /* size_t */
67
#include <stdlib.h> /* free() */
68
#include <string.h> /* strdup() */
69
#include <stdio.h> /* debugging */
70
71
#ifdef _WIN32
72
#ifdef HAVE_STDAFX_H
73
#include "stdafx.h"
74
#endif /* HAVE_STDAFX_H */
75
#include <io.h> /* close() open() */
76
#elif defined HAVE_UNISTD_H
77
#include <unistd.h> /* close() */
78
#endif /* _WIN32 */
79
80
#ifdef HAVE_FCNTL_H
81
#include <fcntl.h> /* open() O_RDONLY */
82
#endif /* HAVE_FCNTL_H */
83
84
#include "dwarf.h"
85
#include "libdwarf.h"
86
#include "libdwarf_private.h"
87
#include "dwarf_base_types.h"
88
#include "dwarf_util.h"
89
#include "dwarf_opaque.h"
90
#include "dwarf_alloc.h"
91
#include "dwarf_error.h"
92
#include "dwarf_object_detector.h"
93
94
#ifndef O_BINARY
95
42.2k
#define O_BINARY 0
96
#endif /* O_BINARY */
97
#ifndef O_CLOEXEC
98
#define O_CLOEXEC 0
99
#endif /* O_CLOEXEC */
100
101
/*  This is the initialization set intended to
102
    handle multiple object formats.
103
    Created September 2018
104
105
    The init functions here cannot process archives.
106
    Archives cannot be read by libdwarf.
107
*/
108
static int
109
open_a_file(const char * name)
110
42.2k
{
111
    /* Set to a file number that cannot be legal. */
112
42.2k
    int fd = -1;
113
114
42.2k
    fd = open(name, O_RDONLY | O_BINARY|O_CLOEXEC);
115
42.2k
    return fd;
116
42.2k
}
117
118
static int
119
set_global_paths_init(Dwarf_Debug dbg, Dwarf_Error* error)
120
67.0k
{
121
67.0k
    int res = 0;
122
123
67.0k
    res = dwarf_add_debuglink_global_path(dbg,
124
67.0k
        "/usr/lib/debug",error);
125
67.0k
    return res;
126
67.0k
}
127
128
/* New in September 2023. */
129
int dwarf_init_path_a(const char *path,
130
    char            * true_path_out_buffer,
131
    unsigned          true_path_bufferlen,
132
    unsigned          groupnumber,
133
    unsigned          universalnumber,
134
    Dwarf_Handler     errhand,
135
    Dwarf_Ptr         errarg,
136
    Dwarf_Debug     * ret_dbg,
137
    Dwarf_Error     * error)
138
0
{
139
0
    return dwarf_init_path_dl_a(path,
140
0
        true_path_out_buffer,true_path_bufferlen,
141
0
        groupnumber,universalnumber,
142
0
        errhand,errarg,ret_dbg,
143
0
        0,0,0,
144
0
        error);
145
0
}
146
147
int dwarf_init_path(const char *path,
148
    char            * true_path_out_buffer,
149
    unsigned          true_path_bufferlen,
150
    unsigned          groupnumber,
151
    Dwarf_Handler     errhand,
152
    Dwarf_Ptr         errarg,
153
    Dwarf_Debug     * ret_dbg,
154
    Dwarf_Error     * error)
155
36.5k
{
156
36.5k
    unsigned int universalnumber = 0;
157
36.5k
    return dwarf_init_path_dl_a(path,
158
36.5k
        true_path_out_buffer,true_path_bufferlen,
159
36.5k
        groupnumber,universalnumber,
160
36.5k
        errhand,errarg,ret_dbg,
161
36.5k
        0,0,0,
162
36.5k
        error);
163
36.5k
}
164
165
static void
166
final_common_settings(Dwarf_Debug dbg,
167
    const char *file_path,
168
    int fd,
169
    unsigned char lpath_source,
170
    unsigned char *path_source,
171
    Dwarf_Error *error)
172
8.56k
{
173
8.56k
    int res = 0;
174
175
8.56k
    dbg->de_path = strdup(file_path);
176
8.56k
    dbg->de_fd = fd;
177
8.56k
    dbg->de_owns_fd = TRUE;
178
8.56k
    dbg->de_path_source = lpath_source;
179
8.56k
    if (path_source) {
180
728
        *path_source = lpath_source;
181
728
    }
182
8.56k
    dbg->de_owns_fd = TRUE;
183
8.56k
    res = set_global_paths_init(dbg,error);
184
8.56k
    if (res == DW_DLV_ERROR && error) {
185
0
        dwarf_dealloc_error(dbg,*error);
186
0
        *error = 0;
187
0
    }
188
8.56k
    return;
189
8.56k
}
190
/*  New October 2020
191
    Given true_path_out_buffer (and true_path_bufferlen)
192
    non-zero this finds a dSYM (if such exists) with the
193
    file name in true_path_out_buffer
194
195
    If not a dSYM it follows debuglink rules to try to find a file
196
    that matches requirements. If found returns DW_DLV_OK and
197
    copies the name to true_path_out_buffer;
198
    If none of the above found, it copies path into true_path
199
    and returns DW_DLV_OK, we know the name is good;
200
201
    The pathn_fd is owned by libdwarf and is in the created dbg->de_fd
202
    field.
203
*/
204
int
205
dwarf_init_path_dl(const char *path,
206
    char            * true_path_out_buffer,
207
    unsigned        true_path_bufferlen,
208
    unsigned        groupnumber,
209
    Dwarf_Handler   errhand,
210
    Dwarf_Ptr       errarg,
211
    Dwarf_Debug     * ret_dbg,
212
    char            ** dl_path_array,
213
    unsigned int    dl_path_count,
214
    unsigned char   * path_source,
215
    Dwarf_Error     * error)
216
7.96k
{
217
7.96k
    unsigned int universalnumber = 0;
218
7.96k
    int res = 0;
219
220
7.96k
    res = dwarf_init_path_dl_a(path,
221
7.96k
        true_path_out_buffer, true_path_bufferlen,
222
7.96k
        groupnumber,universalnumber,
223
7.96k
        errhand,errarg,ret_dbg, dl_path_array,
224
7.96k
        dl_path_count,path_source,error);
225
7.96k
    return res;
226
7.96k
}
227
228
#if 0
229
/*  for debugging */
230
static void
231
dump_header_fields(const char *w,Dwarf_Debug dbg)
232
{
233
    printf("dadebug dumping certain fields of %s\n",w);
234
    printf("ftype         : %d\n",dbg->de_ftype);
235
    printf("machine       : %llu\n",dbg->de_obj_machine);
236
    printf("flags         : 0x%llx\n",dbg->de_obj_flags);
237
    printf("pointer size  : %u\n",dbg->de_pointer_size);
238
    printf("big_endian?   : %u\n",dbg->de_big_endian_object);
239
    printf("ubcount       : %u\n",dbg->de_universalbinary_count);
240
    printf("ubindex       : %u\n",dbg->de_universalbinary_index);
241
    printf("ub offset     : %llu\n",dbg->de_obj_ub_offset);
242
    printf("path source   : %u\n",dbg->de_path_source);
243
    printf("comdat group# : %u\n",dbg->de_groupnumber);
244
    exit(0);
245
}
246
#endif
247
248
int
249
dwarf_init_path_dl_a(const char *path,
250
    char            * true_path_out_buffer,
251
    unsigned        true_path_bufferlen,
252
    unsigned        groupnumber,
253
    unsigned        universalnumber,
254
    Dwarf_Handler   errhand,
255
    Dwarf_Ptr       errarg,
256
    Dwarf_Debug     * ret_dbg,
257
    char            ** dl_path_array,
258
    unsigned int    dl_path_count,
259
    unsigned char   * path_source,
260
    Dwarf_Error     * error)
261
44.5k
{
262
44.5k
    unsigned       ftype = 0;
263
44.5k
    unsigned       endian = 0;
264
44.5k
    unsigned       offsetsize = 0;
265
44.5k
    Dwarf_Unsigned filesize = 0;
266
44.5k
    int res =  DW_DLV_ERROR;
267
44.5k
    int errcode = 0;
268
44.5k
    int fd = -1;
269
44.5k
    Dwarf_Debug dbg = 0;
270
44.5k
    char *file_path = 0;
271
44.5k
    unsigned char  lpath_source = DW_PATHSOURCE_basic;
272
273
44.5k
    if (!ret_dbg) {
274
0
        DWARF_DBG_ERROR(NULL,DW_DLE_DWARF_INIT_DBG_NULL,
275
0
            DW_DLV_ERROR);
276
0
    }
277
    /*  Non-null *ret_dbg will cause problems dealing with
278
        DW_DLV_ERROR */
279
44.5k
    *ret_dbg = 0;
280
44.5k
    if (!path) {
281
        /* Oops. Null path */
282
0
        _dwarf_error_string(NULL,
283
0
            error,DW_DLE_STRING_PTR_NULL,
284
0
            "DW_DLE_STRING_PTR_NULL: Passing a"
285
0
            " null path argument to "
286
0
            "dwarf_init_path or dwarf_init_path_dl"
287
0
            " cannot work. Error.");
288
0
        return DW_DLV_ERROR;
289
0
    }
290
    /* a special dsym call so we only check once. */
291
44.5k
    if (true_path_out_buffer) {
292
7.96k
        res = dwarf_object_detector_path_dSYM(path,
293
7.96k
            true_path_out_buffer,
294
7.96k
            true_path_bufferlen,
295
7.96k
            dl_path_array,dl_path_count,
296
7.96k
            &ftype,&endian,&offsetsize,&filesize,
297
7.96k
            &lpath_source,
298
7.96k
            &errcode);
299
7.96k
        if (res != DW_DLV_OK) {
300
7.96k
            if (res == DW_DLV_ERROR) {
301
                /* ignore error. Look further. */
302
0
                errcode = 0;
303
0
            }
304
7.96k
        }
305
7.96k
    }
306
44.5k
    if (res != DW_DLV_OK) {
307
44.5k
        res = dwarf_object_detector_path_b(path,
308
44.5k
            true_path_out_buffer,
309
44.5k
            true_path_bufferlen,
310
44.5k
            dl_path_array,dl_path_count,
311
44.5k
            &ftype,&endian,&offsetsize,&filesize,
312
44.5k
            &lpath_source,
313
44.5k
            &errcode);
314
44.5k
        if (res != DW_DLV_OK ) {
315
7.46k
            if (res == DW_DLV_ERROR) {
316
5.32k
                errcode = 0;
317
5.32k
            }
318
7.46k
        }
319
44.5k
    }
320
44.5k
    if (res != DW_DLV_OK) {
321
        /*  So as a last resort in case
322
            of data corruption in the object.
323
            Lets try without
324
            investigating debuglink  or dSYM. */
325
7.46k
        res = dwarf_object_detector_path_b(path,
326
7.46k
            0,
327
7.46k
            0,
328
7.46k
            dl_path_array,dl_path_count,
329
7.46k
            &ftype,&endian,&offsetsize,&filesize,
330
7.46k
            &lpath_source,
331
7.46k
            &errcode);
332
7.46k
    }
333
44.5k
    if (res != DW_DLV_OK) {
334
        /* impossible. The last above *had* to work */
335
2.25k
        if (res == DW_DLV_ERROR) {
336
110
            _dwarf_error(NULL, error, errcode);
337
110
        }
338
2.25k
        return res;
339
2.25k
    }
340
    /*  ASSERT: lpath_source != DW_PATHSOURCE_unspecified  */
341
42.2k
    if (lpath_source != DW_PATHSOURCE_basic &&
342
42.2k
        true_path_out_buffer && *true_path_out_buffer) {
343
        /* MacOS dSYM or GNU debuglink */
344
0
        file_path = true_path_out_buffer;
345
0
        fd = open_a_file(true_path_out_buffer);
346
42.2k
    } else {
347
        /*  ASSERT: lpath_source = DW_PATHSOURCE_basic */
348
42.2k
        file_path = (char *)path;
349
42.2k
        fd = open_a_file(path);
350
42.2k
    }
351
352
42.2k
    if (fd == -1) {
353
0
        DWARF_DBG_ERROR(NULL, DW_DLE_FILE_UNAVAILABLE,
354
0
            DW_DLV_ERROR);
355
0
    }
356
42.2k
    switch(ftype) {
357
27.8k
    case DW_FTYPE_ELF: {
358
27.8k
        res = _dwarf_elf_nlsetup(fd,
359
27.8k
            file_path,
360
27.8k
            ftype,endian,offsetsize,filesize,
361
27.8k
            groupnumber,errhand,errarg,&dbg,error);
362
27.8k
        if (res != DW_DLV_OK) {
363
19.8k
            close(fd);
364
19.8k
            return res;
365
19.8k
        }
366
8.03k
        final_common_settings(dbg,file_path,fd,
367
8.03k
            lpath_source,path_source,error);
368
8.03k
        dbg->de_ftype =  ftype;
369
8.03k
        *ret_dbg = dbg;
370
8.03k
        return res;
371
27.8k
    }
372
2.92k
    case DW_FTYPE_APPLEUNIVERSAL:
373
11.0k
    case DW_FTYPE_MACH_O: {
374
11.0k
        res = _dwarf_macho_setup(fd,
375
11.0k
            file_path,
376
11.0k
            universalnumber,
377
11.0k
            ftype,endian,offsetsize,filesize,
378
11.0k
            groupnumber,errhand,errarg,&dbg,error);
379
11.0k
        if (res != DW_DLV_OK) {
380
10.8k
            close(fd);
381
10.8k
            return res;
382
10.8k
        }
383
197
        final_common_settings(dbg,file_path,fd,
384
197
            lpath_source,path_source,error);
385
197
        dbg->de_ftype =  ftype;
386
197
        *ret_dbg = dbg;
387
197
        return res;
388
11.0k
    }
389
3.40k
    case DW_FTYPE_PE: {
390
3.40k
        res = _dwarf_pe_setup(fd,
391
3.40k
            file_path,
392
3.40k
            ftype,endian,offsetsize,filesize,
393
3.40k
            groupnumber,errhand,errarg,&dbg,error);
394
3.40k
        if (res != DW_DLV_OK) {
395
3.06k
            close(fd);
396
3.06k
            return res;
397
3.06k
        }
398
333
        final_common_settings(dbg,file_path,fd,
399
333
            lpath_source,path_source,error);
400
333
        dbg->de_ftype =  ftype;
401
333
        *ret_dbg = dbg;
402
333
        return res;
403
3.40k
    }
404
5
    default:
405
5
        close(fd);
406
5
        DWARF_DBG_ERROR(NULL, DW_DLE_FILE_WRONG_TYPE,
407
3.40k
            DW_DLV_ERROR);
408
        /* Macro returns, cannot reach this line. */
409
42.2k
    }
410
    /* Cannot reach this line */
411
42.2k
}
412
413
/*  New March 2017, this provides for reading
414
    object files with multiple elf section groups.
415
    If you are unsure about group_number, use
416
    DW_GROUPNUMBER_ANY  as groupnumber.
417
*/
418
int
419
dwarf_init_b(int fd,
420
    unsigned        group_number,
421
    Dwarf_Handler   errhand,
422
    Dwarf_Ptr       errarg,
423
    Dwarf_Debug *   ret_dbg,
424
    Dwarf_Error *   error)
425
260k
{
426
260k
    unsigned ftype = 0;
427
260k
    unsigned endian = 0;
428
260k
    unsigned offsetsize = 0;
429
260k
    unsigned universalnumber = 0;
430
260k
    Dwarf_Unsigned   filesize = 0;
431
260k
    int res = 0;
432
260k
    int errcode = 0;
433
434
260k
    if (!ret_dbg) {
435
0
        DWARF_DBG_ERROR(NULL,DW_DLE_DWARF_INIT_DBG_NULL,DW_DLV_ERROR);
436
0
    }
437
    /*  Non-null *ret_dbg will cause problems dealing with
438
        DW_DLV_ERROR */
439
260k
    *ret_dbg = 0;
440
260k
    res = dwarf_object_detector_fd(fd, &ftype,
441
260k
        &endian,&offsetsize,&filesize,&errcode);
442
260k
    if (res == DW_DLV_NO_ENTRY) {
443
12.0k
        return res;
444
12.0k
    }
445
248k
    if (res == DW_DLV_ERROR) {
446
        /* This macro does a return. */
447
600
        DWARF_DBG_ERROR(NULL, DW_DLE_FILE_WRONG_TYPE, DW_DLV_ERROR);
448
0
    }
449
247k
    switch(ftype) {
450
153k
    case DW_FTYPE_ELF: {
451
153k
        int res2 = 0;
452
453
153k
        res2 = _dwarf_elf_nlsetup(fd,"",
454
153k
            ftype,endian,offsetsize,filesize,
455
153k
            group_number,errhand,errarg,ret_dbg,error);
456
153k
        if (res2 != DW_DLV_OK) {
457
108k
            return res2;
458
108k
        }
459
44.8k
        set_global_paths_init(*ret_dbg,error);
460
44.8k
        return res2;
461
153k
        }
462
16.2k
    case DW_FTYPE_APPLEUNIVERSAL:
463
72.2k
    case DW_FTYPE_MACH_O: {
464
72.2k
        int resm = 0;
465
466
72.2k
        resm = _dwarf_macho_setup(fd,"",
467
72.2k
            universalnumber,
468
72.2k
            ftype,endian,offsetsize,filesize,
469
72.2k
            group_number,errhand,errarg,ret_dbg,error);
470
72.2k
        if (resm != DW_DLV_OK) {
471
62.5k
            return resm;
472
62.5k
        }
473
9.75k
        set_global_paths_init(*ret_dbg,error);
474
9.75k
        return resm;
475
72.2k
        }
476
477
21.3k
    case DW_FTYPE_PE: {
478
21.3k
        int resp = 0;
479
480
21.3k
        resp = _dwarf_pe_setup(fd,
481
21.3k
            "",
482
21.3k
            ftype,endian,offsetsize,filesize,
483
21.3k
            group_number,errhand,errarg,ret_dbg,error);
484
21.3k
        if (resp != DW_DLV_OK) {
485
17.5k
            return resp;
486
17.5k
        }
487
3.82k
        set_global_paths_init(*ret_dbg,error);
488
3.82k
        return resp;
489
21.3k
        }
490
28
    default: break;
491
247k
    }
492
247k
    DWARF_DBG_ERROR(NULL, DW_DLE_FILE_WRONG_TYPE, DW_DLV_ERROR);
493
    /* Macro above returns. cannot reach here. */
494
0
}
495
496
/*
497
    Frees all memory that was not previously freed
498
    by dwarf_dealloc.
499
    Aside from certain categories.
500
501
    Applicable when dwarf_init() or dwarf_elf_init()
502
    or the -b() form was used to init 'dbg'.
503
*/
504
int
505
dwarf_finish(Dwarf_Debug dbg)
506
297k
{
507
297k
    if (IS_INVALID_DBG(dbg)) {
508
230k
        _dwarf_free_static_errlist();
509
230k
        return DW_DLV_OK;
510
230k
    }
511
67.0k
    if (dbg->de_obj_file) {
512
        /*  The initial character of a valid
513
            dbg->de_obj_file->object struct is a letter:
514
            E, F, M, or P */
515
67.0k
        char otype  = *(char *)(dbg->de_obj_file->ai_object);
516
517
67.0k
        switch(otype) {
518
0
        case 'E':
519
0
            break;
520
52.9k
        case 'F':
521
            /* Non-libelf elf access */
522
52.9k
            _dwarf_destruct_elf_nlaccess(dbg->de_obj_file);
523
52.9k
            break;
524
9.95k
        case 'M':
525
9.95k
            _dwarf_destruct_macho_access(dbg->de_obj_file);
526
9.95k
            break;
527
4.16k
        case 'P':
528
4.16k
            _dwarf_destruct_pe_access(dbg->de_obj_file);
529
4.16k
            break;
530
0
        default:
531
            /*  Do nothing. A serious internal error */
532
0
            break;
533
67.0k
        }
534
67.0k
    }
535
67.0k
    if (dbg->de_owns_fd) {
536
8.56k
        close(dbg->de_fd);
537
8.56k
        dbg->de_owns_fd = FALSE;
538
8.56k
    }
539
67.0k
    free((void *)dbg->de_path);
540
67.0k
    dbg->de_path = 0;
541
    /*  dwarf_object_finish() also frees de_path,
542
        but that is safe because we set it to zero
543
        here so no duplicate free will occur.
544
        It never returns DW_DLV_ERROR.
545
        Not all code uses libdwarf exactly as we do
546
        hence the free() there. */
547
67.0k
    return dwarf_object_finish(dbg);
548
67.0k
}
549
550
/*
551
    tieddbg should be the executable or .o
552
    that has the .debug_addr section that
553
    the base dbg refers to. See Split Objects in DWARF5.
554
555
    Allows setting to NULL (NULL is the default
556
    of  de_tied_data.td_tied_object).
557
    New September 2015.
558
*/
559
int
560
dwarf_set_tied_dbg(Dwarf_Debug dbg,
561
    Dwarf_Debug tieddbg,
562
    Dwarf_Error*error)
563
3.87k
{
564
3.87k
    CHECK_DBG(dbg,error,"dwarf_set_tied_dbg()");
565
566
3.87k
    dbg->de_tied_data.td_tied_object = tieddbg;
567
3.87k
    if (tieddbg) {
568
0
        tieddbg->de_tied_data.td_is_tied_object = TRUE;
569
0
    }
570
3.87k
    return DW_DLV_OK;
571
3.87k
}
572
573
/*  New September 2015. */
574
int
575
dwarf_get_tied_dbg(Dwarf_Debug dbg, Dwarf_Debug *tieddbg_out,
576
    Dwarf_Error*error)
577
0
{
578
0
    CHECK_DBG(dbg,error,"dwarf_get_tied_dbg()");
579
0
    *tieddbg_out = dbg->de_tied_data.td_tied_object;
580
0
    return DW_DLV_OK;
581
0
}