| author | |
| committer | |
| log | 421102ba724370d04f14016006141a51c0f3e296 |
| tree | 0db8c0dbf687586c3f8ad725324a04e3b12bcc21 |
| parent | dc7cff8ebc5f00c784647c0bd1b40dec70a5008f |
2 files changed, 205 insertions(+), 166 deletions(-)
src/link/MachO/Object.zig+135| ... | @@ -2,6 +2,7 @@ const Object = @This(); | ... | @@ -2,6 +2,7 @@ const Object = @This(); |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | const dwarf = std.dwarf; | ||
| 5 | const fs = std.fs; | 6 | const fs = std.fs; |
| 6 | const io = std.io; | 7 | const io = std.io; |
| 7 | const log = std.log.scoped(.object); | 8 | const log = std.log.scoped(.object); |
| ... | @@ -43,6 +44,10 @@ dwarf_debug_ranges_index: ?u16 = null, | ... | @@ -43,6 +44,10 @@ dwarf_debug_ranges_index: ?u16 = null, |
| 43 | symtab: std.ArrayListUnmanaged(Symbol) = .{}, | 44 | symtab: std.ArrayListUnmanaged(Symbol) = .{}, |
| 44 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 45 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 45 | 46 | ||
| 47 | stabs: std.ArrayListUnmanaged(Stab) = .{}, | ||
| 48 | tu_path: ?[]const u8 = null, | ||
| 49 | tu_mtime: ?u64 = null, | ||
| 50 | |||
| 46 | data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, | 51 | data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, |
| 47 | 52 | ||
| 48 | pub const Section = struct { | 53 | pub const Section = struct { |
| ... | @@ -62,6 +67,82 @@ pub const Section = struct { | ... | @@ -62,6 +67,82 @@ pub const Section = struct { |
| 62 | } | 67 | } |
| 63 | }; | 68 | }; |
| 64 | 69 | ||
| 70 | const Stab = struct { | ||
| 71 | tag: Tag, | ||
| 72 | symbol: u32, | ||
| 73 | size: ?u64 = null, | ||
| 74 | |||
| 75 | const Tag = enum { | ||
| 76 | function, | ||
| 77 | global, | ||
| 78 | static, | ||
| 79 | }; | ||
| 80 | }; | ||
| 81 | |||
| 82 | const DebugInfo = struct { | ||
| 83 | inner: dwarf.DwarfInfo, | ||
| 84 | debug_info: []u8, | ||
| 85 | debug_abbrev: []u8, | ||
| 86 | debug_str: []u8, | ||
| 87 | debug_line: []u8, | ||
| 88 | debug_ranges: []u8, | ||
| 89 | |||
| 90 | pub fn parseFromObject(allocator: *Allocator, object: *const Object) !?DebugInfo { | ||
| 91 | var debug_info = blk: { | ||
| 92 | const index = object.dwarf_debug_info_index orelse return null; | ||
| 93 | break :blk try object.readSection(allocator, index); | ||
| 94 | }; | ||
| 95 | var debug_abbrev = blk: { | ||
| 96 | const index = object.dwarf_debug_abbrev_index orelse return null; | ||
| 97 | break :blk try object.readSection(allocator, index); | ||
| 98 | }; | ||
| 99 | var debug_str = blk: { | ||
| 100 | const index = object.dwarf_debug_str_index orelse return null; | ||
| 101 | break :blk try object.readSection(allocator, index); | ||
| 102 | }; | ||
| 103 | var debug_line = blk: { | ||
| 104 | const index = object.dwarf_debug_line_index orelse return null; | ||
| 105 | break :blk try object.readSection(allocator, index); | ||
| 106 | }; | ||
| 107 | var debug_ranges = blk: { | ||
| 108 | if (object.dwarf_debug_ranges_index) |ind| { | ||
| 109 | break :blk try object.readSection(allocator, ind); | ||
| 110 | } | ||
| 111 | break :blk try allocator.alloc(u8, 0); | ||
| 112 | }; | ||
| 113 | |||
| 114 | var inner: dwarf.DwarfInfo = .{ | ||
| 115 | .endian = .Little, | ||
| 116 | .debug_info = debug_info, | ||
| 117 | .debug_abbrev = debug_abbrev, | ||
| 118 | .debug_str = debug_str, | ||
| 119 | .debug_line = debug_line, | ||
| 120 | .debug_ranges = debug_ranges, | ||
| 121 | }; | ||
| 122 | try dwarf.openDwarfDebugInfo(&inner, allocator); | ||
| 123 | |||
| 124 | return DebugInfo{ | ||
| 125 | .inner = inner, | ||
| 126 | .debug_info = debug_info, | ||
| 127 | .debug_abbrev = debug_abbrev, | ||
| 128 | .debug_str = debug_str, | ||
| 129 | .debug_line = debug_line, | ||
| 130 | .debug_ranges = debug_ranges, | ||
| 131 | }; | ||
| 132 | } | ||
| 133 | |||
| 134 | pub fn deinit(self: *DebugInfo, allocator: *Allocator) void { | ||
| 135 | allocator.free(self.debug_info); | ||
| 136 | allocator.free(self.debug_abbrev); | ||
| 137 | allocator.free(self.debug_str); | ||
| 138 | allocator.free(self.debug_line); | ||
| 139 | allocator.free(self.debug_ranges); | ||
| 140 | self.inner.abbrev_table_list.deinit(); | ||
| 141 | self.inner.compile_unit_list.deinit(); | ||
| 142 | self.inner.func_list.deinit(); | ||
| 143 | } | ||
| 144 | }; | ||
| 145 | |||
| 65 | pub fn init(allocator: *Allocator) Object { | 146 | pub fn init(allocator: *Allocator) Object { |
| 66 | return .{ | 147 | return .{ |
| 67 | .allocator = allocator, | 148 | .allocator = allocator, |
| ... | @@ -81,11 +162,16 @@ pub fn deinit(self: *Object) void { | ... | @@ -81,11 +162,16 @@ pub fn deinit(self: *Object) void { |
| 81 | 162 | ||
| 82 | self.symtab.deinit(self.allocator); | 163 | self.symtab.deinit(self.allocator); |
| 83 | self.strtab.deinit(self.allocator); | 164 | self.strtab.deinit(self.allocator); |
| 165 | self.stabs.deinit(self.allocator); | ||
| 84 | self.data_in_code_entries.deinit(self.allocator); | 166 | self.data_in_code_entries.deinit(self.allocator); |
| 85 | 167 | ||
| 86 | if (self.name) |n| { | 168 | if (self.name) |n| { |
| 87 | self.allocator.free(n); | 169 | self.allocator.free(n); |
| 88 | } | 170 | } |
| 171 | |||
| 172 | if (self.tu_path) |tu_path| { | ||
| 173 | self.allocator.free(tu_path); | ||
| 174 | } | ||
| 89 | } | 175 | } |
| 90 | 176 | ||
| 91 | pub fn closeFile(self: Object) void { | 177 | pub fn closeFile(self: Object) void { |
| ... | @@ -124,6 +210,7 @@ pub fn parse(self: *Object) !void { | ... | @@ -124,6 +210,7 @@ pub fn parse(self: *Object) !void { |
| 124 | try self.parseSections(); | 210 | try self.parseSections(); |
| 125 | if (self.symtab_cmd_index != null) try self.parseSymtab(); | 211 | if (self.symtab_cmd_index != null) try self.parseSymtab(); |
| 126 | if (self.data_in_code_cmd_index != null) try self.readDataInCode(); | 212 | if (self.data_in_code_cmd_index != null) try self.readDataInCode(); |
| 213 | try self.parseDebugInfo(); | ||
| 127 | } | 214 | } |
| 128 | 215 | ||
| 129 | pub fn readLoadCommands(self: *Object, reader: anytype) !void { | 216 | pub fn readLoadCommands(self: *Object, reader: anytype) !void { |
| ... | @@ -271,6 +358,54 @@ pub fn parseSymtab(self: *Object) !void { | ... | @@ -271,6 +358,54 @@ pub fn parseSymtab(self: *Object) !void { |
| 271 | try self.strtab.appendSlice(self.allocator, strtab); | 358 | try self.strtab.appendSlice(self.allocator, strtab); |
| 272 | } | 359 | } |
| 273 | 360 | ||
| 361 | pub fn parseDebugInfo(self: *Object) !void { | ||
| 362 | var debug_info = blk: { | ||
| 363 | var di = try DebugInfo.parseFromObject(self.allocator, self); | ||
| 364 | break :blk di orelse return; | ||
| 365 | }; | ||
| 366 | defer debug_info.deinit(self.allocator); | ||
| 367 | |||
| 368 | log.warn("parsing debug info in '{s}'", .{self.name.?}); | ||
| 369 | |||
| 370 | // We assume there is only one CU. | ||
| 371 | const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) { | ||
| 372 | error.MissingDebugInfo => { | ||
| 373 | // TODO audit cases with missing debug info and audit our dwarf.zig module. | ||
| 374 | log.warn("invalid or missing debug info in {s}; skipping", .{self.name.?}); | ||
| 375 | return; | ||
| 376 | }, | ||
| 377 | else => |e| return e, | ||
| 378 | }; | ||
| 379 | const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name); | ||
| 380 | const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir); | ||
| 381 | |||
| 382 | self.tu_path = try std.fs.path.join(self.allocator, &[_][]const u8{ comp_dir, name }); | ||
| 383 | self.tu_mtime = mtime: { | ||
| 384 | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; | ||
| 385 | const stat = try self.file.?.stat(); | ||
| 386 | break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); | ||
| 387 | }; | ||
| 388 | |||
| 389 | for (self.symtab.items) |sym, index| { | ||
| 390 | const sym_name = self.getString(sym.inner.n_strx); | ||
| 391 | const size = blk: for (debug_info.inner.func_list.items) |func| { | ||
| 392 | if (func.pc_range) |range| { | ||
| 393 | if (sym.inner.n_value >= range.start and sym.inner.n_value < range.end) { | ||
| 394 | break :blk range.end - range.start; | ||
| 395 | } | ||
| 396 | } | ||
| 397 | } else null; | ||
| 398 | |||
| 399 | // TODO How do we work out static, global, local? | ||
| 400 | const tag: Stab.Tag = if (size == null) .global else .function; | ||
| 401 | try self.stabs.append(self.allocator, .{ | ||
| 402 | .tag = tag, | ||
| 403 | .size = size, | ||
| 404 | .symbol = @intCast(u32, index), | ||
| 405 | }); | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 274 | pub fn getString(self: *const Object, str_off: u32) []const u8 { | 409 | pub fn getString(self: *const Object, str_off: u32) []const u8 { |
| 275 | assert(str_off < self.strtab.items.len); | 410 | assert(str_off < self.strtab.items.len); |
| 276 | return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + str_off)); | 411 | return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + str_off)); |
src/link/MachO/Zld.zig+70-166| ... | @@ -2,7 +2,6 @@ const Zld = @This(); | ... | @@ -2,7 +2,6 @@ const Zld = @This(); |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | const dwarf = std.dwarf; | ||
| 6 | const leb = std.leb; | 5 | const leb = std.leb; |
| 7 | const mem = std.mem; | 6 | const mem = std.mem; |
| 8 | const meta = std.meta; | 7 | const meta = std.meta; |
| ... | @@ -110,70 +109,6 @@ pub const SectionMapping = struct { | ... | @@ -110,70 +109,6 @@ pub const SectionMapping = struct { |
| 110 | offset: u32, | 109 | offset: u32, |
| 111 | }; | 110 | }; |
| 112 | 111 | ||
| 113 | const DebugInfo = struct { | ||
| 114 | inner: dwarf.DwarfInfo, | ||
| 115 | debug_info: []u8, | ||
| 116 | debug_abbrev: []u8, | ||
| 117 | debug_str: []u8, | ||
| 118 | debug_line: []u8, | ||
| 119 | debug_ranges: []u8, | ||
| 120 | |||
| 121 | pub fn parseFromObject(allocator: *Allocator, object: Object) !?DebugInfo { | ||
| 122 | var debug_info = blk: { | ||
| 123 | const index = object.dwarf_debug_info_index orelse return null; | ||
| 124 | break :blk try object.readSection(allocator, index); | ||
| 125 | }; | ||
| 126 | var debug_abbrev = blk: { | ||
| 127 | const index = object.dwarf_debug_abbrev_index orelse return null; | ||
| 128 | break :blk try object.readSection(allocator, index); | ||
| 129 | }; | ||
| 130 | var debug_str = blk: { | ||
| 131 | const index = object.dwarf_debug_str_index orelse return null; | ||
| 132 | break :blk try object.readSection(allocator, index); | ||
| 133 | }; | ||
| 134 | var debug_line = blk: { | ||
| 135 | const index = object.dwarf_debug_line_index orelse return null; | ||
| 136 | break :blk try object.readSection(allocator, index); | ||
| 137 | }; | ||
| 138 | var debug_ranges = blk: { | ||
| 139 | if (object.dwarf_debug_ranges_index) |ind| { | ||
| 140 | break :blk try object.readSection(allocator, ind); | ||
| 141 | } | ||
| 142 | break :blk try allocator.alloc(u8, 0); | ||
| 143 | }; | ||
| 144 | |||
| 145 | var inner: dwarf.DwarfInfo = .{ | ||
| 146 | .endian = .Little, | ||
| 147 | .debug_info = debug_info, | ||
| 148 | .debug_abbrev = debug_abbrev, | ||
| 149 | .debug_str = debug_str, | ||
| 150 | .debug_line = debug_line, | ||
| 151 | .debug_ranges = debug_ranges, | ||
| 152 | }; | ||
| 153 | try dwarf.openDwarfDebugInfo(&inner, allocator); | ||
| 154 | |||
| 155 | return DebugInfo{ | ||
| 156 | .inner = inner, | ||
| 157 | .debug_info = debug_info, | ||
| 158 | .debug_abbrev = debug_abbrev, | ||
| 159 | .debug_str = debug_str, | ||
| 160 | .debug_line = debug_line, | ||
| 161 | .debug_ranges = debug_ranges, | ||
| 162 | }; | ||
| 163 | } | ||
| 164 | |||
| 165 | pub fn deinit(self: *DebugInfo, allocator: *Allocator) void { | ||
| 166 | allocator.free(self.debug_info); | ||
| 167 | allocator.free(self.debug_abbrev); | ||
| 168 | allocator.free(self.debug_str); | ||
| 169 | allocator.free(self.debug_line); | ||
| 170 | allocator.free(self.debug_ranges); | ||
| 171 | self.inner.abbrev_table_list.deinit(); | ||
| 172 | self.inner.compile_unit_list.deinit(); | ||
| 173 | self.inner.func_list.deinit(); | ||
| 174 | } | ||
| 175 | }; | ||
| 176 | |||
| 177 | /// Default path to dyld | 112 | /// Default path to dyld |
| 178 | const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld"; | 113 | const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld"; |
| 179 | 114 | ||
| ... | @@ -2510,108 +2445,77 @@ fn writeDebugInfo(self: *Zld) !void { | ... | @@ -2510,108 +2445,77 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2510 | var stabs = std.ArrayList(macho.nlist_64).init(self.allocator); | 2445 | var stabs = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 2511 | defer stabs.deinit(); | 2446 | defer stabs.deinit(); |
| 2512 | 2447 | ||
| 2513 | for (self.objects.items) |object, object_id| { | 2448 | for (self.objects.items) |object| { |
| 2514 | var debug_info = blk: { | 2449 | const tu_path = object.tu_path orelse continue; |
| 2515 | var di = try DebugInfo.parseFromObject(self.allocator, object); | 2450 | const tu_mtime = object.tu_mtime orelse continue; |
| 2516 | break :blk di orelse continue; | 2451 | const dirname = std.fs.path.dirname(tu_path) orelse "./"; |
| 2517 | }; | 2452 | // Current dir |
| 2518 | defer debug_info.deinit(self.allocator); | 2453 | try stabs.append(.{ |
| 2519 | 2454 | .n_strx = try self.makeString(tu_path[0 .. dirname.len + 1]), | |
| 2520 | // We assume there is only one CU. | 2455 | .n_type = macho.N_SO, |
| 2521 | const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) { | 2456 | .n_sect = 0, |
| 2522 | error.MissingDebugInfo => { | 2457 | .n_desc = 0, |
| 2523 | // TODO audit cases with missing debug info and audit our dwarf.zig module. | 2458 | .n_value = 0, |
| 2524 | log.warn("invalid or missing debug info in {s}; skipping", .{object.name}); | 2459 | }); |
| 2525 | continue; | 2460 | // Artifact name |
| 2526 | }, | 2461 | try stabs.append(.{ |
| 2527 | else => |e| return e, | 2462 | .n_strx = try self.makeString(tu_path[dirname.len + 1 ..]), |
| 2528 | }; | 2463 | .n_type = macho.N_SO, |
| 2529 | const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name); | 2464 | .n_sect = 0, |
| 2530 | const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir); | 2465 | .n_desc = 0, |
| 2531 | 2466 | .n_value = 0, | |
| 2532 | { | 2467 | }); |
| 2533 | const tu_path = try std.fs.path.join(self.allocator, &[_][]const u8{ comp_dir, name }); | 2468 | // Path to object file with debug info |
| 2534 | defer self.allocator.free(tu_path); | 2469 | try stabs.append(.{ |
| 2535 | const dirname = std.fs.path.dirname(tu_path) orelse "./"; | 2470 | .n_strx = try self.makeString(object.name.?), |
| 2536 | // Current dir | 2471 | .n_type = macho.N_OSO, |
| 2537 | try stabs.append(.{ | 2472 | .n_sect = 0, |
| 2538 | .n_strx = try self.makeString(tu_path[0 .. dirname.len + 1]), | 2473 | .n_desc = 1, |
| 2539 | .n_type = macho.N_SO, | 2474 | .n_value = tu_mtime, |
| 2540 | .n_sect = 0, | 2475 | }); |
| 2541 | .n_desc = 0, | ||
| 2542 | .n_value = 0, | ||
| 2543 | }); | ||
| 2544 | // Artifact name | ||
| 2545 | try stabs.append(.{ | ||
| 2546 | .n_strx = try self.makeString(tu_path[dirname.len + 1 ..]), | ||
| 2547 | .n_type = macho.N_SO, | ||
| 2548 | .n_sect = 0, | ||
| 2549 | .n_desc = 0, | ||
| 2550 | .n_value = 0, | ||
| 2551 | }); | ||
| 2552 | // Path to object file with debug info | ||
| 2553 | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; | ||
| 2554 | const stat = try object.file.?.stat(); | ||
| 2555 | const mtime = @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); | ||
| 2556 | try stabs.append(.{ | ||
| 2557 | .n_strx = try self.makeString(object.name.?), | ||
| 2558 | .n_type = macho.N_OSO, | ||
| 2559 | .n_sect = 0, | ||
| 2560 | .n_desc = 1, | ||
| 2561 | .n_value = mtime, | ||
| 2562 | }); | ||
| 2563 | } | ||
| 2564 | log.warn("analyzing debug info in '{s}'", .{object.name}); | ||
| 2565 | 2476 | ||
| 2566 | for (object.symtab.items) |sym| { | 2477 | for (object.stabs.items) |stab| { |
| 2567 | const sym_name = object.getString(sym.inner.n_strx); | 2478 | const sym = object.symtab.items[stab.symbol]; |
| 2568 | const maybe_size = blk: for (debug_info.inner.func_list.items) |func| { | 2479 | switch (stab.tag) { |
| 2569 | if (func.pc_range) |range| { | 2480 | .function => { |
| 2570 | // TODO source address needs to be preserved | 2481 | try stabs.append(.{ |
| 2571 | if (sym.inner.n_value >= range.start and sym.inner.n_value < range.end) { | 2482 | .n_strx = 0, |
| 2572 | break :blk range.end - range.start; | 2483 | .n_type = macho.N_BNSYM, |
| 2573 | } | 2484 | .n_sect = sym.inner.n_sect, |
| 2574 | } | 2485 | .n_desc = 0, |
| 2575 | } else null; | 2486 | .n_value = sym.inner.n_value, |
| 2576 | 2487 | }); | |
| 2577 | if (maybe_size) |size| { | 2488 | try stabs.append(.{ |
| 2578 | try stabs.append(.{ | 2489 | .n_strx = sym.inner.n_strx, |
| 2579 | .n_strx = 0, | 2490 | .n_type = macho.N_FUN, |
| 2580 | .n_type = macho.N_BNSYM, | 2491 | .n_sect = sym.inner.n_sect, |
| 2581 | .n_sect = sym.inner.n_sect, | 2492 | .n_desc = 0, |
| 2582 | .n_desc = 0, | 2493 | .n_value = sym.inner.n_value, |
| 2583 | .n_value = sym.inner.n_value, | 2494 | }); |
| 2584 | }); | 2495 | try stabs.append(.{ |
| 2585 | try stabs.append(.{ | 2496 | .n_strx = 0, |
| 2586 | .n_strx = sym.inner.n_strx, | 2497 | .n_type = macho.N_FUN, |
| 2587 | .n_type = macho.N_FUN, | 2498 | .n_sect = 0, |
| 2588 | .n_sect = sym.inner.n_sect, | 2499 | .n_desc = 0, |
| 2589 | .n_desc = 0, | 2500 | .n_value = stab.size.?, |
| 2590 | .n_value = sym.inner.n_value, | 2501 | }); |
| 2591 | }); | 2502 | try stabs.append(.{ |
| 2592 | try stabs.append(.{ | 2503 | .n_strx = 0, |
| 2593 | .n_strx = 0, | 2504 | .n_type = macho.N_ENSYM, |
| 2594 | .n_type = macho.N_FUN, | 2505 | .n_sect = sym.inner.n_sect, |
| 2595 | .n_sect = 0, | 2506 | .n_desc = 0, |
| 2596 | .n_desc = 0, | 2507 | .n_value = stab.size.?, |
| 2597 | .n_value = size, | 2508 | }); |
| 2598 | }); | 2509 | }, |
| 2599 | try stabs.append(.{ | 2510 | else => { |
| 2600 | .n_strx = 0, | 2511 | try stabs.append(.{ |
| 2601 | .n_type = macho.N_ENSYM, | 2512 | .n_strx = sym.inner.n_strx, |
| 2602 | .n_sect = sym.inner.n_sect, | 2513 | .n_type = macho.N_STSYM, |
| 2603 | .n_desc = 0, | 2514 | .n_sect = sym.inner.n_sect, |
| 2604 | .n_value = size, | 2515 | .n_desc = 0, |
| 2605 | }); | 2516 | .n_value = sym.inner.n_value, |
| 2606 | } else { | 2517 | }); |
| 2607 | // TODO need a way to differentiate symbols: global, static, local, etc. | 2518 | }, |
| 2608 | try stabs.append(.{ | ||
| 2609 | .n_strx = sym.inner.n_strx, | ||
| 2610 | .n_type = macho.N_STSYM, | ||
| 2611 | .n_sect = sym.inner.n_sect, | ||
| 2612 | .n_desc = 0, | ||
| 2613 | .n_value = sym.inner.n_value, | ||
| 2614 | }); | ||
| 2615 | } | 2519 | } |
| 2616 | } | 2520 | } |
| 2617 | 2521 |