···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2013 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#include "CFIWalker.h"
2121+#include <sstream>
2222+#include <stdexcept>
2323+#include "log.h"
2424+2525+CFIWalker::CFIWalker(uint8_t* instructions, uintptr_t length, uint8_t dwarfPtrEncoding)
2626+: m_buffer(instructions, length), m_dwarfPtrEncoding(dwarfPtrEncoding)
2727+{
2828+}
2929+3030+void CFIWalker::processNextReg(void* opaque, int (*mapRegisterNumber)(void*, int))
3131+{
3232+ uint64_t reg, newReg;
3333+3434+ reg = m_buffer.readULEB128();
3535+ newReg = mapRegisterNumber(opaque, reg);
3636+3737+ if (newReg != reg)
3838+ {
3939+ LOG << "Updating register number: " << reg << " -> " << newReg << std::endl;
4040+ m_buffer.updateLastULEB128(newReg);
4141+ }
4242+}
4343+4444+uint8_t CFIWalker::processMixedInstr(void* opaque, int (*mapRegisterNumber)(void*, int), uint8_t instr)
4545+{
4646+ int origRegNo = int(instr) & 0x3f;
4747+ int newRegNo = mapRegisterNumber(opaque, origRegNo);
4848+4949+ if (origRegNo != newRegNo)
5050+ return (uint8_t) (instr & 0xC0) | newRegNo;
5151+ else
5252+ return instr;
5353+}
5454+5555+void CFIWalker::walk(void* opaque, int (*mapRegisterNumber)(void*,int))
5656+{
5757+ while (!m_buffer.atEnd())
5858+ {
5959+ const uint8_t instr = m_buffer.read();
6060+ uint64_t len;
6161+6262+ switch (instr)
6363+ {
6464+ case DW_CFA_nop:
6565+ break;
6666+ case DW_CFA_advance_loc1:
6767+ m_buffer.read();
6868+ break;
6969+ case DW_CFA_advance_loc2:
7070+ m_buffer.read16();
7171+ break;
7272+ case DW_CFA_advance_loc4:
7373+ m_buffer.read32();
7474+ break;
7575+ case DW_CFA_set_loc:
7676+ // read a DWARF pointer with ptrEncoding
7777+ m_buffer.readDwarfPointer(m_dwarfPtrEncoding);
7878+ break;
7979+ case DW_CFA_offset_extended:
8080+ // uleb128 reg
8181+ processNextReg(opaque, mapRegisterNumber);
8282+ // uleb128 offset (*data align factor)
8383+ m_buffer.readULEB128();
8484+ break;
8585+ case DW_CFA_restore_extended:
8686+ // uleb128 reg
8787+ processNextReg(opaque, mapRegisterNumber);
8888+ // loads up initial value
8989+ break;
9090+ case DW_CFA_undefined:
9191+ // uleb128 reg
9292+ processNextReg(opaque, mapRegisterNumber);
9393+ // marks register as unused
9494+ break;
9595+ case DW_CFA_same_value:
9696+ // uleb128 reg
9797+ processNextReg(opaque, mapRegisterNumber);
9898+ break;
9999+ case DW_CFA_register:
100100+ // uleb128 reg
101101+ processNextReg(opaque, mapRegisterNumber);
102102+ // uleb128 reg2
103103+ processNextReg(opaque, mapRegisterNumber);
104104+ break;
105105+ case DW_CFA_remember_state:
106106+ break;
107107+ case DW_CFA_restore_state:
108108+ break;
109109+ case DW_CFA_def_cfa:
110110+ // uleb128 reg
111111+ processNextReg(opaque, mapRegisterNumber);
112112+ // uleb128 offset
113113+ m_buffer.readULEB128();
114114+ break;
115115+ case DW_CFA_def_cfa_register:
116116+ // uleb128 reg
117117+ processNextReg(opaque, mapRegisterNumber);
118118+ break;
119119+ case DW_CFA_def_cfa_offset:
120120+ // uleb128 - drop
121121+ m_buffer.readULEB128();
122122+ break;
123123+ case DW_CFA_def_cfa_expression:
124124+ // uleb128 length
125125+ len = m_buffer.readULEB128();
126126+ // add read value to m_pPos
127127+ m_buffer.readBlock(size_t(len));
128128+ break;
129129+ case DW_CFA_expression:
130130+ // uleb128 reg
131131+ processNextReg(opaque, mapRegisterNumber);
132132+ // uleb128 length
133133+ len = m_buffer.readULEB128();
134134+ // add read value to m_pPos
135135+ m_buffer.readBlock(size_t(len));
136136+ break;
137137+ case DW_CFA_offset_extended_sf:
138138+ // uleb128 reg
139139+ processNextReg(opaque, mapRegisterNumber);
140140+ // uleb128 offset
141141+ m_buffer.readULEB128();
142142+ break;
143143+ case DW_CFA_def_cfa_sf:
144144+ // uleb128 reg
145145+ processNextReg(opaque, mapRegisterNumber);
146146+ // uleb128 offset
147147+ m_buffer.readULEB128();
148148+ break;
149149+ case DW_CFA_def_cfa_offset_sf:
150150+ // uleb128 offset
151151+ m_buffer.readULEB128();
152152+ break;
153153+ case DW_CFA_val_offset:
154154+ // uleb128 reg
155155+ processNextReg(opaque, mapRegisterNumber);
156156+ // uleb128 offset
157157+ m_buffer.readULEB128();
158158+ break;
159159+ case DW_CFA_val_offset_sf:
160160+ // uleb128 reg
161161+ processNextReg(opaque, mapRegisterNumber);
162162+ // uleb128 offset
163163+ m_buffer.readULEB128();
164164+ break;
165165+ case DW_CFA_val_expression:
166166+ // uleb128 reg
167167+ processNextReg(opaque, mapRegisterNumber);
168168+ // uleb128 length
169169+ len = m_buffer.readULEB128();
170170+ // add read value to m_pPos
171171+ m_buffer.readBlock(size_t(len));
172172+ break;
173173+ //case DW_CFA_low_user: // not in Apple's libunwind
174174+ //case DW_CFA_GNU_window_save: // not in Apple's libunwind
175175+ case DW_CFA_GNU_args_size:
176176+ // uleb128 offset
177177+ m_buffer.readULEB128();
178178+ break;
179179+ case DW_CFA_GNU_negative_offset_extended:
180180+ // uleb128 reg
181181+ processNextReg(opaque, mapRegisterNumber);
182182+ // uleb128 offset
183183+ m_buffer.readULEB128();
184184+ break;
185185+ //case DW_CFA_high_user: // not in Apple's libunwind
186186+ default:
187187+ {
188188+ uint8_t op = instr & 0x3f;
189189+ switch (instr & 0xC0)
190190+ {
191191+ case DW_CFA_offset:
192192+ {
193193+ // op is reg!
194194+ uint8_t newInstr = processMixedInstr(opaque, mapRegisterNumber, instr);
195195+ m_buffer.updateLast(newInstr);
196196+ // uleb128 offset
197197+ m_buffer.readULEB128();
198198+ break;
199199+ }
200200+ case DW_CFA_advance_loc:
201201+ break;
202202+ case DW_CFA_restore:
203203+ {
204204+ // op is reg!
205205+ uint8_t newInstr = processMixedInstr(opaque, mapRegisterNumber, instr);
206206+ m_buffer.updateLast(newInstr);
207207+ break;
208208+ }
209209+ default:
210210+ {
211211+ std::stringstream ss;
212212+ ss << "Unhandled DWARF instruction " << std::hex << instr << std::dec;
213213+ throw std::runtime_error(ss.str());
214214+ }
215215+ }
216216+ }
217217+ }
218218+ }
219219+}
+79
src/dyld/eh/CFIWalker.h
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2013 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#ifndef CFIWALKER_H
2121+#define CFIWALKER_H
2222+#include <stdint.h>
2323+#include "BufReWriter.h"
2424+2525+class CFIWalker
2626+{
2727+public:
2828+ CFIWalker(uint8_t* instructions, uintptr_t length, uint8_t dwarfPtrEncoding);
2929+3030+ void walk(void* opaque, int (*mapRegisterNumber)(void*, int));
3131+private:
3232+ void processNextReg(void* opaque, int (*mapRegisterNumber)(void*, int));
3333+ uint8_t processMixedInstr(void* opaque, int (*mapRegisterNumber)(void*, int), uint8_t instr);
3434+private:
3535+ BufReWriter m_buffer;
3636+ uint8_t m_dwarfPtrEncoding;
3737+};
3838+3939+enum : uint8_t
4040+{
4141+ DW_CFA_advance_loc = 0x40,
4242+ DW_CFA_offset = 0x80,
4343+ DW_CFA_restore = 0xc0,
4444+ DW_CFA_extended = 0,
4545+4646+ DW_CFA_nop = 0x00,
4747+ DW_CFA_set_loc = 0x01,
4848+ DW_CFA_advance_loc1 = 0x02,
4949+ DW_CFA_advance_loc2 = 0x03,
5050+ DW_CFA_advance_loc4 = 0x04,
5151+ DW_CFA_offset_extended = 0x05,
5252+ DW_CFA_restore_extended = 0x06,
5353+ DW_CFA_undefined = 0x07,
5454+ DW_CFA_same_value = 0x08,
5555+ DW_CFA_register = 0x09,
5656+ DW_CFA_remember_state = 0x0a,
5757+ DW_CFA_restore_state = 0x0b,
5858+ DW_CFA_def_cfa = 0x0c,
5959+ DW_CFA_def_cfa_register = 0x0d,
6060+ DW_CFA_def_cfa_offset = 0x0e,
6161+ DW_CFA_def_cfa_expression = 0x0f,
6262+ DW_CFA_expression = 0x10,
6363+ DW_CFA_offset_extended_sf = 0x11,
6464+ DW_CFA_def_cfa_sf = 0x12,
6565+ DW_CFA_def_cfa_offset_sf = 0x13,
6666+ DW_CFA_val_offset = 0x14,
6767+ DW_CFA_val_offset_sf = 0x15,
6868+ DW_CFA_val_expression = 0x16,
6969+7070+ DW_CFA_low_user = 0x1c,
7171+ DW_CFA_MIPS_advance_loc8 = 0x1d,
7272+ DW_CFA_GNU_window_save = 0x2d,
7373+ DW_CFA_GNU_args_size = 0x2e,
7474+ DW_CFA_GNU_negative_offset_extended = 0x2f,
7575+ DW_CFA_high_user = 0x3f
7676+};
7777+7878+7979+#endif