1 /* Textual dumping of CTF data. 2 Copyright (C) 2019-2020 Free Software Foundation, Inc. 3 4 This file is part of libctf. 5 6 libctf is free software; you can redistribute it and/or modify it under 7 the terms of the GNU General Public License as published by the Free 8 Software Foundation; either version 3, or (at your option) any later 9 version. 10 11 This program is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 See the GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; see the file COPYING. If not see 18 <http://www.gnu.org/licenses/>. */ 19 20 #include <ctf-impl.h> 21 #include <string.h> 22 23 #define str_append(s, a) ctf_str_append_noerr (s, a) 24 25 /* One item to be dumped, in string form. */ 26 27 typedef struct ctf_dump_item 28 { 29 ctf_list_t cdi_list; 30 char *cdi_item; 31 } ctf_dump_item_t; 32 33 /* Cross-call state for dumping. Basically just enough to track the section in 34 use and a list of return strings. */ 35 36 struct ctf_dump_state 37 { 38 ctf_sect_names_t cds_sect; 39 ctf_file_t *cds_fp; 40 ctf_dump_item_t *cds_current; 41 ctf_list_t cds_items; 42 }; 43 44 /* Cross-call state for ctf_dump_member. */ 45 46 typedef struct ctf_dump_membstate 47 { 48 char **cdm_str; 49 ctf_file_t *cdm_fp; 50 } ctf_dump_membstate_t; 51 52 static int 53 ctf_dump_append (ctf_dump_state_t *state, char *str) 54 { 55 ctf_dump_item_t *cdi; 56 57 if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL) 58 return (ctf_set_errno (state->cds_fp, ENOMEM)); 59 60 cdi->cdi_item = str; 61 ctf_list_append (&state->cds_items, cdi); 62 return 0; 63 } 64 65 static void 66 ctf_dump_free (ctf_dump_state_t *state) 67 { 68 ctf_dump_item_t *cdi, *next_cdi; 69 70 if (state == NULL) 71 return; 72 73 for (cdi = ctf_list_next (&state->cds_items); cdi != NULL; 74 cdi = next_cdi) 75 { 76 free (cdi->cdi_item); 77 next_cdi = ctf_list_next (cdi); 78 free (cdi); 79 } 80 } 81 82 /* Slices need special handling to distinguish them from their referenced 83 type. */ 84 85 static int 86 ctf_is_slice (ctf_file_t *fp, ctf_id_t id, ctf_encoding_t *enc) 87 { 88 int kind = ctf_type_kind (fp, id); 89 90 return (((kind == CTF_K_INTEGER) || (kind == CTF_K_ENUM) 91 || (kind == CTF_K_FLOAT)) 92 && ctf_type_reference (fp, id) != CTF_ERR 93 && ctf_type_encoding (fp, id, enc) == 0); 94 } 95 96 /* Return a dump for a single type, without member info: but do show the 97 type's references. */ 98 99 static char * 100 ctf_dump_format_type (ctf_file_t *fp, ctf_id_t id, int flag) 101 { 102 ctf_id_t new_id; 103 char *str = NULL, *bit = NULL, *buf = NULL; 104 105 new_id = id; 106 do 107 { 108 ctf_encoding_t enc; 109 const char *nonroot_leader = ""; 110 const char *nonroot_trailer = ""; 111 112 id = new_id; 113 if (flag == CTF_ADD_NONROOT) 114 { 115 nonroot_leader = "{"; 116 nonroot_trailer = "}"; 117 } 118 119 buf = ctf_type_aname (fp, id); 120 if (!buf) 121 { 122 if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE) 123 { 124 str = str_append (str, " (type not represented in CTF)"); 125 ctf_set_errno (fp, ECTF_NOTREF); 126 break; 127 } 128 129 goto err; 130 } 131 132 /* Slices get a different print representation. */ 133 134 if (ctf_is_slice (fp, id, &enc)) 135 { 136 ctf_type_encoding (fp, id, &enc); 137 if (asprintf (&bit, " %s%lx: [slice 0x%x:0x%x]%s", 138 nonroot_leader, id, enc.cte_offset, enc.cte_bits, 139 nonroot_trailer) < 0) 140 goto oom; 141 } 142 else 143 { 144 if (asprintf (&bit, " %s%lx: %s (size 0x%lx)%s", nonroot_leader, 145 id, buf[0] == '\0' ? "(nameless)" : buf, 146 (unsigned long) ctf_type_size (fp, id), 147 nonroot_trailer) < 0) 148 goto oom; 149 } 150 free (buf); 151 buf = NULL; 152 str = str_append (str, bit); 153 free (bit); 154 bit = NULL; 155 156 new_id = ctf_type_reference (fp, id); 157 if (new_id != CTF_ERR) 158 str = str_append (str, " ->"); 159 } while (new_id != CTF_ERR); 160 161 if (ctf_errno (fp) != ECTF_NOTREF) 162 { 163 free (str); 164 return NULL; 165 } 166 167 return str; 168 169 oom: 170 ctf_set_errno (fp, errno); 171 err: 172 free (buf); 173 free (str); 174 free (bit); 175 return NULL; 176 } 177 178 /* Dump one string field from the file header into the cds_items. */ 179 static int 180 ctf_dump_header_strfield (ctf_file_t *fp, ctf_dump_state_t *state, 181 const char *name, uint32_t value) 182 { 183 char *str; 184 if (value) 185 { 186 if (asprintf (&str, "%s: %s\n", name, ctf_strptr (fp, value)) < 0) 187 goto err; 188 ctf_dump_append (state, str); 189 } 190 return 0; 191 192 err: 193 return (ctf_set_errno (fp, errno)); 194 } 195 196 /* Dump one section-offset field from the file header into the cds_items. */ 197 static int 198 ctf_dump_header_sectfield (ctf_file_t *fp, ctf_dump_state_t *state, 199 const char *sect, uint32_t off, uint32_t nextoff) 200 { 201 char *str; 202 if (nextoff - off) 203 { 204 if (asprintf (&str, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect, 205 (unsigned long) off, (unsigned long) (nextoff - 1), 206 (unsigned long) (nextoff - off)) < 0) 207 goto err; 208 ctf_dump_append (state, str); 209 } 210 return 0; 211 212 err: 213 return (ctf_set_errno (fp, errno)); 214 } 215 216 /* Dump the file header into the cds_items. */ 217 static int 218 ctf_dump_header (ctf_file_t *fp, ctf_dump_state_t *state) 219 { 220 char *str; 221 const ctf_header_t *hp = fp->ctf_header; 222 const char *vertab[] = 223 { 224 NULL, "CTF_VERSION_1", 225 "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type " 226 "boundaries)", 227 "CTF_VERSION_2", 228 "CTF_VERSION_3", NULL 229 }; 230 const char *verstr = NULL; 231 232 if (asprintf (&str, "Magic number: %x\n", hp->cth_magic) < 0) 233 goto err; 234 ctf_dump_append (state, str); 235 236 if (hp->cth_version <= CTF_VERSION) 237 verstr = vertab[hp->cth_version]; 238 239 if (verstr == NULL) 240 verstr = "(not a valid version)"; 241 242 if (asprintf (&str, "Version: %i (%s)\n", hp->cth_version, 243 verstr) < 0) 244 goto err; 245 ctf_dump_append (state, str); 246 247 /* Everything else is only printed if present. */ 248 249 /* The flags are unusual in that they represent the ctf_file_t *in memory*: 250 flags representing compression, etc, are turned off as the file is 251 decompressed. So we store a copy of the flags before they are changed, for 252 the dumper. */ 253 254 if (fp->ctf_openflags > 0) 255 { 256 if (fp->ctf_openflags) 257 if (asprintf (&str, "Flags: 0x%x (%s)", fp->ctf_openflags, 258 fp->ctf_openflags & CTF_F_COMPRESS ? "CTF_F_COMPRESS" 259 : "") < 0) 260 goto err; 261 ctf_dump_append (state, str); 262 } 263 264 if (ctf_dump_header_strfield (fp, state, "Parent label", 265 hp->cth_parlabel) < 0) 266 goto err; 267 268 if (ctf_dump_header_strfield (fp, state, "Parent name", hp->cth_parname) < 0) 269 goto err; 270 271 if (ctf_dump_header_strfield (fp, state, "Compilation unit name", 272 hp->cth_cuname) < 0) 273 goto err; 274 275 if (ctf_dump_header_sectfield (fp, state, "Label section", hp->cth_lbloff, 276 hp->cth_objtoff) < 0) 277 goto err; 278 279 if (ctf_dump_header_sectfield (fp, state, "Data object section", 280 hp->cth_objtoff, hp->cth_funcoff) < 0) 281 goto err; 282 283 if (ctf_dump_header_sectfield (fp, state, "Function info section", 284 hp->cth_funcoff, hp->cth_varoff) < 0) 285 goto err; 286 287 if (ctf_dump_header_sectfield (fp, state, "Variable section", 288 hp->cth_varoff, hp->cth_typeoff) < 0) 289 goto err; 290 291 if (ctf_dump_header_sectfield (fp, state, "Type section", 292 hp->cth_typeoff, hp->cth_stroff) < 0) 293 goto err; 294 295 if (ctf_dump_header_sectfield (fp, state, "String section", hp->cth_stroff, 296 hp->cth_stroff + hp->cth_strlen + 1) < 0) 297 goto err; 298 299 return 0; 300 err: 301 return (ctf_set_errno (fp, errno)); 302 } 303 304 /* Dump a single label into the cds_items. */ 305 306 static int 307 ctf_dump_label (const char *name, const ctf_lblinfo_t *info, 308 void *arg) 309 { 310 char *str; 311 char *typestr; 312 ctf_dump_state_t *state = arg; 313 314 if (asprintf (&str, "%s -> ", name) < 0) 315 return (ctf_set_errno (state->cds_fp, errno)); 316 317 if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type, 318 CTF_ADD_ROOT)) == NULL) 319 { 320 free (str); 321 return -1; /* errno is set for us. */ 322 } 323 324 str = str_append (str, typestr); 325 free (typestr); 326 327 ctf_dump_append (state, str); 328 return 0; 329 } 330 331 /* Dump all the object entries into the cds_items. (There is no iterator for 332 this section, so we just do it in a loop, and this function handles all of 333 them, rather than only one. */ 334 335 static int 336 ctf_dump_objts (ctf_file_t *fp, ctf_dump_state_t *state) 337 { 338 size_t i; 339 340 for (i = 0; i < fp->ctf_nsyms; i++) 341 { 342 char *str; 343 char *typestr; 344 const char *sym_name; 345 ctf_id_t type; 346 347 if ((type = ctf_lookup_by_symbol (state->cds_fp, i)) == CTF_ERR) 348 switch (ctf_errno (state->cds_fp)) 349 { 350 /* Most errors are just an indication that this symbol is not a data 351 symbol, but this one indicates that we were called wrong, on a 352 CTF file with no associated symbol table. */ 353 case ECTF_NOSYMTAB: 354 return -1; 355 case ECTF_NOTDATA: 356 case ECTF_NOTYPEDAT: 357 continue; 358 } 359 360 /* Variable name. */ 361 sym_name = ctf_lookup_symbol_name (fp, i); 362 if (sym_name[0] == '\0') 363 { 364 if (asprintf (&str, "%lx -> ", (unsigned long) i) < 0) 365 return (ctf_set_errno (fp, errno)); 366 } 367 else 368 { 369 if (asprintf (&str, "%s (%lx) -> ", sym_name, (unsigned long) i) < 0) 370 return (ctf_set_errno (fp, errno)); 371 } 372 373 /* Variable type. */ 374 if ((typestr = ctf_dump_format_type (state->cds_fp, type, 375 CTF_ADD_ROOT)) == NULL) 376 { 377 free (str); 378 return -1; /* errno is set for us. */ 379 } 380 381 str = str_append (str, typestr); 382 free (typestr); 383 384 ctf_dump_append (state, str); 385 } 386 return 0; 387 } 388 389 /* Dump all the function entries into the cds_items. (As above, there is no 390 iterator for this section.) */ 391 392 static int 393 ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state) 394 { 395 size_t i; 396 397 for (i = 0; i < fp->ctf_nsyms; i++) 398 { 399 char *str; 400 char *bit; 401 const char *err; 402 const char *sym_name; 403 ctf_funcinfo_t fi; 404 ctf_id_t type; 405 size_t j; 406 ctf_id_t *args; 407 408 if ((type = ctf_func_info (state->cds_fp, i, &fi)) == CTF_ERR) 409 switch (ctf_errno (state->cds_fp)) 410 { 411 /* Most errors are just an indication that this symbol is not a data 412 symbol, but this one indicates that we were called wrong, on a 413 CTF file with no associated symbol table. */ 414 case ECTF_NOSYMTAB: 415 return -1; 416 case ECTF_NOTDATA: 417 case ECTF_NOTFUNC: 418 case ECTF_NOFUNCDAT: 419 continue; 420 } 421 if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL) 422 return (ctf_set_errno (fp, ENOMEM)); 423 424 /* Return type. */ 425 if ((str = ctf_type_aname (state->cds_fp, type)) == NULL) 426 { 427 err = "look up return type"; 428 goto err; 429 } 430 431 str = str_append (str, " "); 432 433 /* Function name. */ 434 435 sym_name = ctf_lookup_symbol_name (fp, i); 436 if (sym_name[0] == '\0') 437 { 438 if (asprintf (&bit, "0x%lx ", (unsigned long) i) < 0) 439 goto oom; 440 } 441 else 442 { 443 if (asprintf (&bit, "%s (0x%lx) ", sym_name, (unsigned long) i) < 0) 444 goto oom; 445 } 446 str = str_append (str, bit); 447 str = str_append (str, " ("); 448 free (bit); 449 450 /* Function arguments. */ 451 452 if (ctf_func_args (state->cds_fp, i, fi.ctc_argc, args) < 0) 453 { 454 err = "look up argument type"; 455 goto err; 456 } 457 458 for (j = 0; j < fi.ctc_argc; j++) 459 { 460 if ((bit = ctf_type_aname (state->cds_fp, args[j])) == NULL) 461 { 462 err = "look up argument type name"; 463 goto err; 464 } 465 str = str_append (str, bit); 466 if ((j < fi.ctc_argc - 1) || (fi.ctc_flags & CTF_FUNC_VARARG)) 467 str = str_append (str, ", "); 468 free (bit); 469 } 470 471 if (fi.ctc_flags & CTF_FUNC_VARARG) 472 str = str_append (str, "..."); 473 str = str_append (str, ")"); 474 475 free (args); 476 ctf_dump_append (state, str); 477 continue; 478 479 oom: 480 free (args); 481 free (str); 482 return (ctf_set_errno (fp, errno)); 483 err: 484 ctf_dprintf ("Cannot %s dumping function type for symbol 0x%li: %s\n", 485 err, (unsigned long) i, 486 ctf_errmsg (ctf_errno (state->cds_fp))); 487 free (args); 488 free (str); 489 return -1; /* errno is set for us. */ 490 } 491 return 0; 492 } 493 494 /* Dump a single variable into the cds_items. */ 495 static int 496 ctf_dump_var (const char *name, ctf_id_t type, void *arg) 497 { 498 char *str; 499 char *typestr; 500 ctf_dump_state_t *state = arg; 501 502 if (asprintf (&str, "%s -> ", name) < 0) 503 return (ctf_set_errno (state->cds_fp, errno)); 504 505 if ((typestr = ctf_dump_format_type (state->cds_fp, type, 506 CTF_ADD_ROOT)) == NULL) 507 { 508 free (str); 509 return -1; /* errno is set for us. */ 510 } 511 512 str = str_append (str, typestr); 513 free (typestr); 514 515 ctf_dump_append (state, str); 516 return 0; 517 } 518 519 /* Dump a single member into the string in the membstate. */ 520 static int 521 ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset, 522 int depth, void *arg) 523 { 524 ctf_dump_membstate_t *state = arg; 525 char *typestr = NULL; 526 char *bit = NULL; 527 ctf_encoding_t ep; 528 ssize_t i; 529 530 for (i = 0; i < depth; i++) 531 *state->cdm_str = str_append (*state->cdm_str, " "); 532 533 if ((typestr = ctf_type_aname (state->cdm_fp, id)) == NULL) 534 { 535 if (id == 0 || ctf_errno (state->cdm_fp) == ECTF_NONREPRESENTABLE) 536 { 537 if (asprintf (&bit, " [0x%lx] (type not represented in CTF)", 538 offset) < 0) 539 goto oom; 540 541 *state->cdm_str = str_append (*state->cdm_str, bit); 542 free (typestr); 543 free (bit); 544 return 0; 545 } 546 547 goto oom; 548 } 549 550 if (asprintf (&bit, " [0x%lx] (ID 0x%lx) (kind %i) %s %s (aligned at 0x%lx", 551 offset, id, ctf_type_kind (state->cdm_fp, id), typestr, name, 552 (unsigned long) ctf_type_align (state->cdm_fp, id)) < 0) 553 goto oom; 554 *state->cdm_str = str_append (*state->cdm_str, bit); 555 free (typestr); 556 free (bit); 557 typestr = NULL; 558 bit = NULL; 559 560 if ((ctf_type_kind (state->cdm_fp, id) == CTF_K_INTEGER) 561 || (ctf_type_kind (state->cdm_fp, id) == CTF_K_FLOAT) 562 || (ctf_is_slice (state->cdm_fp, id, &ep) == CTF_K_ENUM)) 563 { 564 ctf_type_encoding (state->cdm_fp, id, &ep); 565 if (asprintf (&bit, ", format 0x%x, offset:bits 0x%x:0x%x", ep.cte_format, 566 ep.cte_offset, ep.cte_bits) < 0) 567 goto oom; 568 *state->cdm_str = str_append (*state->cdm_str, bit); 569 free (bit); 570 bit = NULL; 571 } 572 573 *state->cdm_str = str_append (*state->cdm_str, ")\n"); 574 return 0; 575 576 oom: 577 free (typestr); 578 free (bit); 579 return (ctf_set_errno (state->cdm_fp, errno)); 580 } 581 582 /* Dump a single type into the cds_items. */ 583 static int 584 ctf_dump_type (ctf_id_t id, int flag, void *arg) 585 { 586 char *str; 587 const char *err; 588 ctf_dump_state_t *state = arg; 589 ctf_dump_membstate_t membstate = { &str, state->cds_fp }; 590 size_t len; 591 592 if ((str = ctf_dump_format_type (state->cds_fp, id, flag)) == NULL) 593 { 594 err = "format type"; 595 goto err; 596 } 597 598 str = str_append (str, "\n"); 599 if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0) 600 { 601 if (id == 0 || ctf_errno (state->cds_fp) == ECTF_NONREPRESENTABLE) 602 { 603 ctf_dump_append (state, str); 604 return 0; 605 } 606 err = "visit members"; 607 goto err; 608 } 609 610 /* Trim off the last linefeed added by ctf_dump_member(). */ 611 len = strlen (str); 612 if (str[len-1] == '\n') 613 str[len-1] = '\0'; 614 615 ctf_dump_append (state, str); 616 return 0; 617 618 err: 619 ctf_dprintf ("Cannot %s dumping type 0x%lx: %s\n", err, id, 620 ctf_errmsg (ctf_errno (state->cds_fp))); 621 free (str); 622 return -1; /* errno is set for us. */ 623 } 624 625 /* Dump the string table into the cds_items. */ 626 627 static int 628 ctf_dump_str (ctf_file_t *fp, ctf_dump_state_t *state) 629 { 630 const char *s = fp->ctf_str[CTF_STRTAB_0].cts_strs; 631 632 for (; s < fp->ctf_str[CTF_STRTAB_0].cts_strs + 633 fp->ctf_str[CTF_STRTAB_0].cts_len;) 634 { 635 char *str; 636 if (asprintf (&str, "%lx: %s", 637 (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs), 638 s) < 0) 639 return (ctf_set_errno (fp, errno)); 640 ctf_dump_append (state, str); 641 s += strlen (s) + 1; 642 } 643 644 return 0; 645 } 646 647 /* Dump a particular section of a CTF file, in textual form. Call with a 648 pointer to a NULL STATE: each call emits a dynamically allocated string 649 containing a description of one entity in the specified section, in order. 650 Only the first call (with a NULL state) may vary SECT. Once the CTF section 651 has been entirely dumped, the call returns NULL and frees and annuls the 652 STATE, ready for another section to be dumped. The returned textual content 653 may span multiple lines: between each call the FUNC is called with one 654 textual line at a time, and should return a suitably decorated line (it can 655 allocate a new one and return it if it likes). */ 656 657 char * 658 ctf_dump (ctf_file_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect, 659 ctf_dump_decorate_f *func, void *arg) 660 { 661 char *str; 662 char *line; 663 ctf_dump_state_t *state = NULL; 664 665 if (*statep == NULL) 666 { 667 /* Data collection. Transforming a call-at-a-time iterator into a 668 return-at-a-time iterator in a language without call/cc is annoying. It 669 is easiest to simply collect everything at once and then return it bit 670 by bit. The first call will take (much) longer than otherwise, but the 671 amortized time needed is the same. */ 672 673 if ((*statep = malloc (sizeof (struct ctf_dump_state))) == NULL) 674 { 675 ctf_set_errno (fp, ENOMEM); 676 goto end; 677 } 678 state = *statep; 679 680 memset (state, 0, sizeof (struct ctf_dump_state)); 681 state->cds_fp = fp; 682 state->cds_sect = sect; 683 684 switch (sect) 685 { 686 case CTF_SECT_HEADER: 687 ctf_dump_header (fp, state); 688 break; 689 case CTF_SECT_LABEL: 690 if (ctf_label_iter (fp, ctf_dump_label, state) < 0) 691 { 692 if (ctf_errno (fp) != ECTF_NOLABELDATA) 693 goto end; /* errno is set for us. */ 694 ctf_set_errno (fp, 0); 695 } 696 break; 697 case CTF_SECT_OBJT: 698 if (ctf_dump_objts (fp, state) < 0) 699 goto end; /* errno is set for us. */ 700 break; 701 case CTF_SECT_FUNC: 702 if (ctf_dump_funcs (fp, state) < 0) 703 goto end; /* errno is set for us. */ 704 break; 705 case CTF_SECT_VAR: 706 if (ctf_variable_iter (fp, ctf_dump_var, state) < 0) 707 goto end; /* errno is set for us. */ 708 break; 709 case CTF_SECT_TYPE: 710 if (ctf_type_iter_all (fp, ctf_dump_type, state) < 0) 711 goto end; /* errno is set for us. */ 712 break; 713 case CTF_SECT_STR: 714 ctf_dump_str (fp, state); 715 break; 716 default: 717 ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN); 718 goto end; 719 } 720 } 721 else 722 { 723 state = *statep; 724 725 if (state->cds_sect != sect) 726 { 727 ctf_set_errno (fp, ECTF_DUMPSECTCHANGED); 728 goto end; 729 } 730 } 731 732 if (state->cds_current == NULL) 733 state->cds_current = ctf_list_next (&state->cds_items); 734 else 735 state->cds_current = ctf_list_next (state->cds_current); 736 737 if (state->cds_current == NULL) 738 goto end; 739 740 /* Hookery. There is some extra complexity to preserve linefeeds within each 741 item while removing linefeeds at the end. */ 742 if (func) 743 { 744 size_t len; 745 746 str = NULL; 747 for (line = state->cds_current->cdi_item; line && *line; ) 748 { 749 char *nline = line; 750 char *ret; 751 752 nline = strchr (line, '\n'); 753 if (nline) 754 nline[0] = '\0'; 755 756 ret = func (sect, line, arg); 757 str = str_append (str, ret); 758 str = str_append (str, "\n"); 759 if (ret != line) 760 free (ret); 761 762 if (nline) 763 { 764 nline[0] = '\n'; 765 nline++; 766 } 767 768 line = nline; 769 } 770 771 len = strlen (str); 772 773 if (str[len-1] == '\n') 774 str[len-1] = '\0'; 775 } 776 else 777 { 778 str = strdup (state->cds_current->cdi_item); 779 if (!str) 780 { 781 ctf_set_errno (fp, ENOMEM); 782 return str; 783 } 784 } 785 786 ctf_set_errno (fp, 0); 787 return str; 788 789 end: 790 ctf_dump_free (state); 791 free (state); 792 ctf_set_errno (fp, 0); 793 *statep = NULL; 794 return NULL; 795 } 796