46
46
import java .util .List ;
47
47
48
48
import com .oracle .graal .python .runtime .PythonContext ;
49
+ import com .oracle .truffle .api .TruffleFile ;
50
+ import com .oracle .truffle .api .TruffleLanguage .Env ;
49
51
50
52
final class MachOFile extends SharedObject {
53
+ private final PythonContext context ;
51
54
private final ByteBuffer buffer ;
52
55
private final MachOHeader mh ;
53
56
private final List <MachOLoadCommand > loadCommands ;
54
57
private int emptySpace ;
55
58
56
59
MachOFile (byte [] f , PythonContext context ) throws IOException {
60
+ this .context = context ;
57
61
this .buffer = ByteBuffer .wrap (f );
58
62
this .mh = MachOHeader .read (buffer );
59
63
this .loadCommands = new ArrayList <>();
@@ -68,93 +72,111 @@ final class MachOFile extends SharedObject {
68
72
this .emptySpace = zeroBytes ;
69
73
}
70
74
71
- public void removeCodeSignature () {
75
+ private void removeCommand (MachOLoadCommand cmd ) {
76
+ loadCommands .remove (cmd );
77
+ mh .nCmds -= 1 ;
78
+ mh .sizeOfCmds -= cmd .cmdSize ;
79
+ emptySpace += cmd .cmdSize ;
80
+ }
81
+
82
+ private void addCommand (MachODylibCommand cmd ) throws IOException {
83
+ if (cmd .cmdSize > emptySpace ) {
84
+ throw new IOException (String .format ("Not enough empty space add new cmd with string %s." , cmd .getName ()));
85
+ }
86
+ var newBuffer = ByteBuffer .allocate (cmd .cmdSize );
87
+ newBuffer .order (buffer .order ());
88
+ cmd .put (newBuffer );
89
+ newBuffer .position (0 );
90
+ loadCommands .add (MachOLoadCommand .get (newBuffer ));
91
+ mh .nCmds += 1 ;
92
+ mh .sizeOfCmds += cmd .cmdSize ;
93
+ emptySpace -= cmd .cmdSize ;
94
+ }
95
+
96
+ private void removeCodeSignature () {
72
97
for (int i = 0 ; i < loadCommands .size (); ++i ) {
73
98
var cmd = loadCommands .get (i );
74
99
if (cmd .cmd == MachOLoadCommand .LC_CODE_SIGNATURE ) {
75
- loadCommands .remove (i );
76
- emptySpace += cmd .cmdSize ;
77
- break ;
100
+ removeCommand (cmd );
101
+ LOGGER .fine (() -> String .format ("Removing code LC_CODE_SIGNATURE. New empty space is %d" , emptySpace ));
78
102
}
79
103
}
80
104
}
81
105
82
- @ Override
83
- public void setId (String newId ) throws IOException {
84
- removeCodeSignature ();
85
- MachOLoadCommand oldIdCommand = null ;
106
+ private void removeId () {
86
107
for (int i = 0 ; i < loadCommands .size (); ++i ) {
87
108
var cmd = loadCommands .get (i );
88
109
if (cmd .cmd == MachODylibCommand .LC_ID_DYLIB ) {
89
- oldIdCommand = cmd ;
90
- break ;
110
+ removeCommand (cmd );
91
111
}
92
112
}
93
-
94
- MachODylibCommand newCmd ;
95
- if (oldIdCommand != null ) {
96
- newCmd = MachODylibCommand .get (oldIdCommand .content );
97
- } else {
98
- newCmd = new MachODylibCommand (MachODylibCommand .LC_ID_DYLIB , MachODylibCommand .SIZE , new byte [0 ], MachODylibCommand .SIZE , 0 , 0 , 0 );
99
- }
100
- newCmd .setName (newId );
101
-
102
- if ((oldIdCommand != null && newCmd .cmdSize - oldIdCommand .cmdSize > emptySpace ) || newCmd .cmdSize > emptySpace ) {
103
- throw new IOException ("Not enough empty space to change ID" );
104
- }
105
-
106
- loadCommands .remove (oldIdCommand );
107
-
108
- var newBuffer = ByteBuffer .allocate (newCmd .cmdSize );
109
- newBuffer .order (buffer .order ());
110
- newCmd .put (newBuffer );
111
- loadCommands .add (MachOLoadCommand .get (newBuffer ));
112
-
113
- if (oldIdCommand != null ) {
114
- mh .sizeOfCmds -= oldIdCommand .cmdSize ;
115
- emptySpace += oldIdCommand .cmdSize ;
116
- }
117
- emptySpace -= newCmd .cmdSize ;
118
- mh .sizeOfCmds += newCmd .cmdSize ;
119
113
}
120
114
121
- @ Override
122
- public void changeOrAddDependency (String oldName , String newName ) throws IOException {
123
- removeCodeSignature ();
124
-
115
+ private void removeLoad (String oldName ) {
125
116
for (int i = 0 ; i < loadCommands .size (); ++i ) {
126
117
var cmd = loadCommands .get (i );
127
118
if (cmd .cmd == MachODylibCommand .LC_LOAD_DYLIB ) {
128
119
var loadCmd = MachODylibCommand .get (cmd .content );
129
120
if (loadCmd .getName ().equals (oldName )) {
130
- loadCommands .remove (i );
131
- emptySpace += cmd .cmdSize ;
132
- break ;
121
+ removeCommand (cmd );
122
+ LOGGER .fine (() -> String .format ("Removing LC_LOAD_DYLIB %s. New empty space is %d." , oldName , emptySpace ));
133
123
}
134
124
}
135
125
}
126
+ }
136
127
137
- var newCmd = new MachODylibCommand (MachODylibCommand .LC_LOAD_DYLIB , MachODylibCommand .SIZE , new byte [0 ], MachODylibCommand .SIZE , 0 , 0 , 0 );
138
- newCmd .setName (newName );
128
+ @ Override
129
+ public void setId (String newId ) throws IOException {
130
+ removeCodeSignature ();
131
+ removeId ();
139
132
140
- if ( newCmd . cmdSize > emptySpace ) {
141
- throw new IOException ( "Not enough empty space to add dependency" );
142
- }
133
+ var newCmd = new MachODylibCommand ( MachODylibCommand . LC_ID_DYLIB , MachODylibCommand . SIZE , new byte [ 0 ], MachODylibCommand . SIZE , 0 , 0 , 0 );
134
+ newCmd . setName ( newId );
135
+ addCommand ( newCmd );
143
136
144
- var newBuffer = ByteBuffer .allocate (newCmd .cmdSize );
145
- newBuffer .order (buffer .order ());
146
- newCmd .put (newBuffer );
147
- loadCommands .add (MachOLoadCommand .get (newBuffer ));
137
+ LOGGER .fine (() -> String .format ("Added LC_ID_DYLIB %s. New empty space is %d." , newId , emptySpace ));
138
+ }
148
139
149
- mh .nCmds += 1 ;
150
- mh .sizeOfCmds += newCmd .cmdSize ;
151
- emptySpace -= newCmd .cmdSize ;
140
+ @ Override
141
+ public void changeOrAddDependency (String oldName , String newName ) throws IOException {
142
+ removeCodeSignature ();
143
+ removeLoad (oldName );
144
+
145
+ var newCmd = new MachODylibCommand (MachODylibCommand .LC_LOAD_DYLIB , MachODylibCommand .SIZE , new byte [0 ], MachODylibCommand .SIZE , 0 , 0 , 0 );
146
+ newCmd .setName (newName );
147
+ addCommand (newCmd );
148
+
149
+ LOGGER .fine (() -> String .format ("Added LC_LOAD_DYLIB %s. New empty space is %d." , newName , emptySpace ));
152
150
}
153
151
154
152
@ Override
155
153
public byte [] write () {
156
154
buffer .position (0 );
157
155
mh .put (buffer );
156
+ for (var cmd : loadCommands ) {
157
+ cmd .put (buffer );
158
+ }
158
159
return buffer .array ();
159
160
}
161
+
162
+ private String getCodesign () {
163
+ Env env = context .getEnv ();
164
+ var path = env .getEnvironment ().getOrDefault ("PATH" , "" ).split (env .getPathSeparator ());
165
+ var i = 0 ;
166
+ TruffleFile codesign ;
167
+ do {
168
+ codesign = env .getPublicTruffleFile (path [i ++]).resolve ("codesign" );
169
+ } while (!codesign .isExecutable () && i < path .length );
170
+ return codesign .toString ();
171
+ }
172
+
173
+ @ Override
174
+ protected void fixup (TruffleFile copy ) throws IOException , InterruptedException {
175
+ var pb = newProcessBuilder (context );
176
+ pb .command (getCodesign (), "--force" , "--sign" , "-" , copy .getAbsoluteFile ().getPath ());
177
+ var proc = pb .start ();
178
+ if (proc .waitFor () != 0 ) {
179
+ throw new IOException ("Failed to run `codesign` command. Make sure you have it on your PATH." );
180
+ }
181
+ }
160
182
}
0 commit comments