Skip to content

Commit 3185cb6

Browse files
committed
Merge remote-tracking branch 'origin/GT-3261_emteere_DYLDStringIssues' into patch
2 parents ec079f7 + 97dc133 commit 3185cb6

File tree

5 files changed

+192
-134
lines changed

5 files changed

+192
-134
lines changed

Ghidra/Features/Base/data/MachOFunctionsThatDoNotReturn

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Unwind_SjLj_Resume
1616
assert_rtn
1717
pthread_exit
1818
errx
19+
abort_message
20+
clang_call_terminate
1921
ZL11unreachablePKc
2022
ZN5swift10fatalErrorEjPKcz
2123
ZN5swift24swift_abortRetainUnownedEPKv
@@ -31,3 +33,5 @@ ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv
3133
ZNKSt3__121__basic_string_commonILb1EE20__throw_length_errorEv
3234
T0s9_abstracts5NeverOs12StaticStringV4file_Su4linetF
3335
ZN5swift24swift_dynamicCastFailureEPKvPKcS1_S3_S3_
36+
ZSt11__terminatePFvvE
37+
ZSt12__unexpectedPFvvE

Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/NList.java

Lines changed: 71 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
2222
import ghidra.app.util.bin.format.macho.MachConstants;
2323
import ghidra.program.model.data.*;
24+
import ghidra.util.exception.AssertException;
2425
import ghidra.util.exception.DuplicateNameException;
2526

2627
/**
@@ -29,41 +30,58 @@
2930
* @see <a href="https://opensource.apple.com/source/xnu/xnu-4570.71.2/EXTERNAL_HEADERS/mach-o/nlist.h.auto.html">mach-o/nlist.h</a>
3031
*/
3132
public class NList implements StructConverter {
32-
private int n_strx;
33-
private byte n_type;
34-
private byte n_sect;
35-
private short n_desc;
36-
private long n_value;
33+
private int n_strx;
34+
private byte n_type;
35+
private byte n_sect;
36+
private short n_desc;
37+
private long n_value;
3738

3839
private String string;
3940
private boolean is32bit;
4041

41-
public static NList createNList(FactoryBundledWithBinaryReader reader,
42-
boolean is32bit, long stringTableOffset) throws IOException {
43-
NList nList = (NList) reader.getFactory().create(NList.class);
44-
nList.initNList(reader, is32bit, stringTableOffset);
45-
return nList;
46-
}
42+
public static NList createNList(FactoryBundledWithBinaryReader reader, boolean is32bit)
43+
throws IOException {
44+
NList nList = (NList) reader.getFactory().create(NList.class);
45+
nList.initNList(reader, is32bit);
46+
return nList;
47+
}
4748

48-
/**
49-
* DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD.
50-
*/
51-
public NList() {}
49+
/**
50+
* DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD.
51+
*/
52+
public NList() {
53+
}
5254

53-
private void initNList(FactoryBundledWithBinaryReader reader, boolean is32bit,
54-
long stringTableOffset) throws IOException {
55+
private void initNList(FactoryBundledWithBinaryReader reader, boolean is32bit)
56+
throws IOException {
5557
this.is32bit = is32bit;
5658

57-
n_strx = reader.readNextInt();
58-
n_type = reader.readNextByte();
59-
n_sect = reader.readNextByte();
60-
n_desc = reader.readNextShort();
59+
n_strx = reader.readNextInt();
60+
n_type = reader.readNextByte();
61+
n_sect = reader.readNextByte();
62+
n_desc = reader.readNextShort();
6163
if (is32bit) {
6264
n_value = reader.readNextInt() & 0xffffffffL;
6365
}
6466
else {
6567
n_value = reader.readNextLong();
6668
}
69+
}
70+
71+
/**
72+
* Initialize the string from the string table.
73+
* <p>
74+
* You MUST call this method after the NLIST element is created!
75+
* <p>
76+
* Reading a large NList table can cause a large performance issue if the strings
77+
* are initialized as the NList entry is created. The string table indexes are
78+
* scattered. Initializing the strings linearly from the string table is much
79+
* faster.
80+
*
81+
* @param reader
82+
* @param stringTableOffset offset of the string table
83+
*/
84+
public void initString(FactoryBundledWithBinaryReader reader, long stringTableOffset) {
6785
try {
6886
string = reader.readAsciiString(stringTableOffset + n_strx);
6987
}
@@ -74,19 +92,19 @@ private void initNList(FactoryBundledWithBinaryReader reader, boolean is32bit,
7492

7593
@Override
7694
public DataType toDataType() throws DuplicateNameException, IOException {
77-
StructureDataType struct = new StructureDataType("nlist", 0);
78-
struct.add(DWORD, "n_strx", null);
79-
struct.add( BYTE, "n_type", null);
80-
struct.add( BYTE, "n_sect", null);
81-
struct.add( WORD, "n_desc", null);
82-
if (is32bit) {
83-
struct.add(DWORD, "n_value", null);
84-
}
85-
else {
86-
struct.add(QWORD, "n_value", null);
87-
}
88-
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
89-
return struct;
95+
StructureDataType struct = new StructureDataType("nlist", 0);
96+
struct.add(DWORD, "n_strx", null);
97+
struct.add(BYTE, "n_type", null);
98+
struct.add(BYTE, "n_sect", null);
99+
struct.add(WORD, "n_desc", null);
100+
if (is32bit) {
101+
struct.add(DWORD, "n_value", null);
102+
}
103+
else {
104+
struct.add(QWORD, "n_value", null);
105+
}
106+
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
107+
return struct;
90108
}
91109

92110
/**
@@ -95,6 +113,9 @@ public DataType toDataType() throws DuplicateNameException, IOException {
95113
* @return the symbol string
96114
*/
97115
public String getString() {
116+
if (string == null) {
117+
throw new AssertException("initString must be called first");
118+
}
98119
return string;
99120
}
100121

@@ -105,6 +126,7 @@ public String getString() {
105126
public int getStringTableIndex() {
106127
return n_strx;
107128
}
129+
108130
/**
109131
* Returns the symbol type flag.
110132
* @return the symbol type flag
@@ -114,34 +136,40 @@ public byte getType() {
114136
}
115137

116138
public boolean isTypeUndefined() {
117-
return n_sect == NListConstants.NO_SECT &&
118-
(n_type & NListConstants.MASK_N_TYPE) == NListConstants.TYPE_N_UNDF;
139+
return n_sect == NListConstants.NO_SECT &&
140+
(n_type & NListConstants.MASK_N_TYPE) == NListConstants.TYPE_N_UNDF;
119141
}
142+
120143
public boolean isTypeAbsolute() {
121-
return n_sect == NListConstants.NO_SECT &&
122-
(n_type & NListConstants.MASK_N_TYPE) == NListConstants.TYPE_N_ABS;
144+
return n_sect == NListConstants.NO_SECT &&
145+
(n_type & NListConstants.MASK_N_TYPE) == NListConstants.TYPE_N_ABS;
123146
}
147+
124148
public boolean isTypePreboundUndefined() {
125-
return n_sect == NListConstants.NO_SECT &&
126-
(n_type & NListConstants.MASK_N_TYPE) == NListConstants.TYPE_N_PBUD;
149+
return n_sect == NListConstants.NO_SECT &&
150+
(n_type & NListConstants.MASK_N_TYPE) == NListConstants.TYPE_N_PBUD;
127151
}
128152

129153
public boolean isSymbolicDebugging() {
130154
return (n_type & NListConstants.MASK_N_STAB) != 0;
131155
}
156+
132157
public boolean isPrivateExternal() {
133158
return (n_type & NListConstants.MASK_N_PEXT) != 0;
134159
}
160+
135161
public boolean isExternal() {
136162
return (n_type & NListConstants.MASK_N_EXT) != 0;
137163
}
164+
138165
public boolean isLazyBind() {
139-
return ( n_desc & NListConstants.REFERENCE_TYPE ) != 0;
166+
return (n_desc & NListConstants.REFERENCE_TYPE) != 0;
140167
}
141168

142169
public boolean isThumbSymbol() {
143170
return (n_desc & NListConstants.DESC_N_ARM_THUMB_DEF) != 0;
144171
}
172+
145173
/**
146174
* An integer specifying the number of the section that this
147175
* symbol can be found in, or NO_SECT if
@@ -151,13 +179,15 @@ public boolean isThumbSymbol() {
151179
public byte getSection() {
152180
return n_sect;
153181
}
182+
154183
/**
155184
* A 16-bit value providing additional information about this symbol.
156185
* @return a 16-bit value providing additional information about this symbol
157186
*/
158187
public short getDescription() {
159188
return n_desc;
160189
}
190+
161191
/**
162192
* An integer that contains the value of this symbol.
163193
* The format of this value is different for each type of symbol.

Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/SymbolTableCommand.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.IOException;
1919
import java.util.ArrayList;
2020
import java.util.List;
21+
import java.util.stream.Collectors;
2122

2223
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
2324
import ghidra.app.util.bin.format.macho.MachConstants;
@@ -74,9 +75,24 @@ private void initSymbolTableCommand(FactoryBundledWithBinaryReader reader, MachH
7475

7576
reader.setPointerIndex(header.getStartIndexInProvider() + symoff);
7677

78+
List<NList> nlistList = new ArrayList<>(nsyms);
79+
long startIndex = header.getStartIndexInProvider();
80+
boolean is32bit = header.is32bit();
81+
reader.setPointerIndex(startIndex + symoff);
82+
7783
for (int i = 0; i < nsyms; ++i) {
78-
NList symbol = NList.createNList(reader, header.is32bit(), stroff);
79-
symbols.add(symbol);
84+
nlistList.add(NList.createNList(reader, is32bit));
85+
}
86+
// sort the entries by the index in the string table, so don't jump around reading
87+
List<NList> sortedList = nlistList.stream().sorted(
88+
(o1, o2) -> o1.getStringTableIndex() - o2.getStringTableIndex()).collect(
89+
Collectors.toList());
90+
91+
// initialize the NList strings from string table
92+
long stringTableOffset = stroff;
93+
for (NList nList : sortedList) {
94+
nList.initString(reader, stringTableOffset);
95+
symbols.add(nList);
8096
}
8197

8298
reader.setPointerIndex(index);

Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldCacheLocalSymbolsInfo.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.IOException;
1919
import java.util.ArrayList;
2020
import java.util.List;
21+
import java.util.stream.Collectors;
2122

2223
import generic.continues.RethrowContinuesFactory;
2324
import ghidra.app.util.bin.BinaryReader;
@@ -119,7 +120,7 @@ public void markup(Program program, Address localSymbolsInfoAddr, TaskMonitor mo
119120
public List<NList> getNList() {
120121
return nlistList;
121122
}
122-
123+
123124
/**
124125
* Gets the {@link List} of {@link DyldCacheLocalSymbolsEntry}s.
125126
*
@@ -144,19 +145,31 @@ public DataType toDataType() throws DuplicateNameException, IOException {
144145
return struct;
145146
}
146147

147-
private void parseNList(MessageLog log, TaskMonitor monitor)
148-
throws CancelledException {
148+
private void parseNList(MessageLog log, TaskMonitor monitor) throws CancelledException {
149149
FactoryBundledWithBinaryReader nListReader = new FactoryBundledWithBinaryReader(
150150
RethrowContinuesFactory.INSTANCE, reader.getByteProvider(), reader.isLittleEndian());
151151
monitor.setMessage("Parsing DYLD nlist symbol table...");
152-
monitor.initialize(nlistCount);
152+
monitor.initialize(nlistCount * 2);
153153
nListReader.setPointerIndex(startIndex + nlistOffset);
154154
try {
155+
155156
for (int i = 0; i < nlistCount; ++i) {
156-
nlistList.add(NList.createNList(nListReader, is32bit, startIndex + stringsOffset));
157+
nlistList.add(NList.createNList(nListReader, is32bit));
157158
monitor.checkCanceled();
158159
monitor.incrementProgress(1);
159160
}
161+
// sort the entries by the index in the string table, so don't jump around reading
162+
List<NList> sortedList = nlistList.stream().sorted(
163+
(o1, o2) -> o1.getStringTableIndex() - o2.getStringTableIndex()).collect(
164+
Collectors.toList());
165+
166+
// initialize the NList strings from string table
167+
long stringTableOffset = startIndex + stringsOffset;
168+
for (NList nList : sortedList) {
169+
monitor.checkCanceled();
170+
monitor.incrementProgress(1);
171+
nList.initString(nListReader, stringTableOffset);
172+
}
160173
}
161174
catch (IOException e) {
162175
log.appendMsg(DyldCacheAccelerateInfo.class.getSimpleName(), "Failed to parse nlist.");
@@ -187,8 +200,8 @@ private void markupNList(Program program, Address localSymbolsInfoAddr, TaskMoni
187200
try {
188201
Address addr = localSymbolsInfoAddr.add(nlistOffset);
189202
for (NList nlist : nlistList) {
190-
Data d = DataUtilities.createData(program, addr, nlist.toDataType(), -1,
191-
false, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
203+
Data d = DataUtilities.createData(program, addr, nlist.toDataType(), -1, false,
204+
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
192205
addr = addr.add(d.getLength());
193206
monitor.checkCanceled();
194207
monitor.incrementProgress(1);

0 commit comments

Comments
 (0)