Identify entries in a global offset table - elf

I'm attempting to write some ELF parsing logic (in C). Specifically, I'm trying to identify which entries in the GOT correspond to which functions.
I've crafted a simple program which contains references to malloc and free. Some relevant excerpts from readelf -a a.out:
Relocation section '.rela.plt' at offset 0x630 contains 2 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
0000000000003fc8 0000000100000007 R_X86_64_JUMP_SLOT 0000000000000000 free#GLIBC_2.2.5 + 0
0000000000003fd0 0000000500000007 R_X86_64_JUMP_SLOT 0000000000000000 malloc#GLIBC_2.2.5 + 0
No processor specific unwind information to decode
Symbol table '.dynsym' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND free#GLIBC_2.2.5 (2)
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main#GLIBC_2.34 (3)
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND malloc#GLIBC_2.2.5 (2)
6: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
7: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize#GLIBC_2.2.5 (2)
I know how to use .dynstr to get the names of the symbols in .dynsym. However, how is readelf populating the symbol names in .rela.plt? I'm not seeing anything in the definitions of either Elf64_Sym or Elf64_Rel which would help. At first, I thought the st_shndx field in Elf64_Sym would be relevant but readelf is showing that value as SHN_UNDEF.

The information is contained in the Elf64_Rel structure. Specifically, the r_info field:
This member gives both the symbol table index with respect to which the relocation must be made and the type of relocation to apply.
The ELF64_R_SYM macro can be used to extract the offset from this field. As seen in the .rela.plt description in the OP, free, for example, has an index of 1 which corresponds to entry 1 in .dynsym.

Related

Location of DW_FORM_strp values

I'm trying to understand where DW_FORM_strp attribute values are actually stored in an ELF file (can be found here: https://filebin.net/77bb8359o0ibqu67).
I've found sections .debug_info, .debug_abbrev and .debug_str. I've then parsed the compilation unit header in .debug_info, and found the abbreviation table entry for the compile unit and iterated over its abbreviations. The first abbreviation is DW_AT_producer with form DW_FORM_strp. What I'm wondering is how to find where this offset is located?
From the DWARF4 spec I read: Each debugging information entry begins with a code that represents an entry in a separate abbreviations table. This code is followed directly by a series of attribute values. My understanding of this is that if I go back to the compilation unit header, skip over its content, I should end up at the compilation unit. It starts with a ULEB128 (which I parse), after which the attribute values should come. However, in my ELF file those bytes are all 0. I've run readelf -w on the file, and I see the following:
Contents of the .debug_info section:
Compilation Unit # offset 0x0:
Length: 0xf6 (32-bit)
Version: 4
Abbrev Offset: 0x0
Pointer Size: 8
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<c> DW_AT_producer : (indirect string, offset: 0x62): GNU C11 7.5.0 -mtune=generic -march=x86-64 -g -O0 -fstack-protector-strong
<10> DW_AT_language : 12 (ANSI C99)
<11> DW_AT_name : (indirect string, offset: 0xd9): elf.c
<15> DW_AT_comp_dir : (indirect string, offset: 0xad): /home//struct_analyzer
<19> DW_AT_low_pc : 0x0
<21> DW_AT_high_pc : 0x39
<29> DW_AT_stmt_list : 0x0
This tells me that the offset into the string table is 0x62, and the name is at an offset 0xd9. However, after parsing the ULEB128 which is the first part of any DIE, the next 4 bytes (the first attribute's value) are 0x00 00 00 00. This I don't understand?
Edit to Employed Russian:
Yes, I understand that the offset 0x62 points into the .debug_str section. However, what I'm wondering is where I find this 0x62 value?
Each DIE starts with a ULEB128 value (the abbreviation table entry code), and is followed by the attributes. The first attribute in the corresponding abbreviation table entry is a DW_AT_producer of form DW_FORM_strp. This means that the next 4 bytes in the DIE are supposed to be the offset into .debug_str. However, the next 4 bytes are 0x00 00 00 00, and not 0x62 00 00 00 which is the value I'm looking. 0x62 is residing at offset 0x5c8 into the ELF file, whereas the DIE's attributes start at offset 0x85 as far as I can tell (see attached image for a hexdump (little endian) - highlighted byte is the ULEB128, and the following bytes are what I expect to be the offset into .debug_str).
Edit 2
I've been able to determine that the actual attribute values of form DW_FORM_strp are located in the .rela.debug_info section in the ELF file, so I'll have to read more about that.
The specific ELF file posted for this question also has a rela.debug_info section, which contains relocation entries for the .debug_info section. From the ELF spec:
.relaNAME
This section holds relocation information as described below.
If the file has a loadable segment that includes relocation,
the section's attributes will include the SHF_ALLOC bit. Oth‐
erwise, the bit will be off. By convention, "NAME" is sup‐
plied by the section to which the relocations apply. Thus a
relocation section for .text normally would have the name
.rela.text. This section is of type SHT_RELA.
Each relocation entry in this section (of type Elf64_Rela in this particular case) should be iterated over, and the value of each entry should be addended with the corresponding value in the .debug_info section.
This tells me that the offset into the string table is 0x62, and the name is at an offset 0xd9.
Correct. These offsets are into the .debug_str section, which starts at offset 0x289 in the file.
readelf -WS elf.o | grep debug_str
[12] .debug_str PROGBITS 0000000000000000 000289 0000e4 01 MS 0 0 1
dd if=elf.o bs=1 skip=$((0x289+0x62)) count=75 2>/dev/null
GNU C11 7.5.0 -mtune=generic -march=x86-64 -g -O0 -fstack-protector-strong
dd if=elf.o bs=1 skip=$((0x289+0xd9)) count=5 2>/dev/null
elf.c
P.S.
I've found sections .dwarf_info, .dward_abbrev and .dwarf_str.
None of above sections exit in your file. It helps to be precise when asking questions.

Getting difference between virtual address and Offset in an ELF file

readelf -S of a particular binary gives the following output
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000400238 00000238
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.ABI-tag NOTE 0000000000400254 00000254
0000000000000020 0000000000000000 A 0 0 4
[ 3] .hash HASH 0000000000400278 00000278
0000000000000a7c 0000000000000004 A 4 0 8
[ 4] .dynsym DYNSYM 0000000000400cf8 00000cf8
.
.
.
Difference between virtual address and offset of first section .interp is 0x400000. I am curious as to:
how is this calculated?
Is there a programmatic way of determining this?
how is this calculated?
You just calculated it yourself: 0x400238 - 0x238 == 0x400000. Your question is probably "why is this particular address selected?".
This is the default link-at address for Linux x86_64 position dependent binaries. You can change that address with -Ttext=... linker flag. The default is different for ix86 (32-bit) binaries: it's 0x8048000.
I am not sure why these particular defaults were chosen.
Is there a programmatic way of determining this?
Sure: read the Elf64_Ehdr from the start of the file. It will tell you offset to the start of program headers (.e_phoff). Seek to that offset, and read Elf64_Phdrs. Now iterate over them, and their .p_vaddr and .p_offset will have the same values.
P.S. You are looking at program sections which are not used and are not guaranteed to be present in a fully-linked binary. You should be looking at program segments instead. Use readelf -Wl a.out to examine them.

modified elf symbol but not reflecting in disassembly

I have used a symbol "__copy_start" inside my assembly code which is coming from linker script. symbol is defined as ABS in symbol table.
This symbol is used inside a macro to copy data from one memory location to another.
After looking at varenter code hereious ways to modify this symbol directly in elf i decided to write C code of my own to modify the symbol value.
To do that i traversed entire symbol table and did string match for the symbol i am interested in. When there is a symbol name match i just assigned symbol_table.st_value = new value.
To make sure the new value is taken i did readelf -s and checked that it does show the new value assigned by me.
Now, when i disassemble the modified elf i find that the new value has not taken effect and i still see the assembly code doing copy from old symbol value.
My question is:
Am i doing something wrong here? is it possible to change the symbol values in elf? If yes, please let me know the correct way to do it. How do i achieve what i intend to do here.
Note: I don't have the source code so taking this approach.
Thanks in advance,
Gaurav
wanted to add more information so that people can understand better.
copying the elf header below:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
**Type: EXEC (Executable file)**
Machine: Ubicom32 32-bit microcontrollers
Version: 0x1
Entry point address: 0xb0000000
Start of program headers: 52 (bytes into file)
Start of section headers: 33548 (bytes into file)
Flags: 0x6
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 2
Size of section headers: 40 (bytes)
Number of section headers: 6
Section header string table index: 3
Here as you can see that file is of type executable.
output of readelf -S copied below:
There are 6 section headers, starting at offset 0x830c:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 3ffc0000 004000 000ebc 00 AX 0 0 1
[ 2] .sdram PROGBITS 50000000 008000 0002e4 00 WA 0 0 1
[ 3] .shstrtab STRTAB 00000000 0082e4 000028 00 0 0 1
[ 4] .symtab SYMTAB 00000000 0083fc 0001c0 10 5 20 4
[ 5] .strtab STRTAB 00000000 0085bc 00019a 00 0 0 1
I am using one of the symbol named "__copy_start" in an instruction to copy the data from .sdram section to .text section. I was under an impression that i could go and change the symbol_table.st_value and then get the desired work done. But unfortunately that is not the case. Seems like it is already compiled and cannot be changed like this.
Any idea how this could be done would be really helpful.
Regards,
Gaurav
Are you sure that the object code actually uses a relocation to reference the data at the __copy_start symbol? Even for position-independent code, it is usually possible to turn section start addresses into relative addresses, which do not need a relocation. (That the symbol itself remains present with an absolute address does not change this.)
You can check this by using readelf -r or eu-readelf -r and examining the output. It is also visible in the objdump --dissassemble --reloc output.

relocation section header information in .elf file

My apology for my poor English, really having a hard time understanding what is the sh_info field contains for relocation section, following is what I get from the ELF document:
It says
sh_info : contains the section header index of the section to which the relocation applies
sh_link: contains the section header index of the associated symbol table.
Clearly: sh_info is not about the symbol table section that the relocation section relates to, whose information is stored in sh_link.
Based on my understanding: when relocating a symbol, three sections are related: the relocation section, the symbol table section, and the section which contains symbols' definition for symbols in the symbol table.
Assumption 1: So I assume sh_info is about the third section mentioned ahead
-----However, when I go through the sample code for relocation, my assumption seems not match
static int elf_do_reloc(Elf32_Ehdr *hdr, Elf32_Rel *rel, Elf32_Shdr *reltab) {
Elf32_Shdr *target = elf_section(hdr, reltab->sh_info);
int addr = (int)hdr + target->sh_offset;
int *ref = (int *)(addr + rel->r_offset);
// Symbol value
int symval = 0;
if(ELF32_R_SYM(rel->r_info) != SHN_UNDEF) {
symval = elf_get_symval(hdr, reltab->sh_link, ELF32_R_SYM(rel->r_info));
if(symval == ELF_RELOC_ERR) return ELF_RELOC_ERR;
}
-----Sicce r_info is a field only entry in relocation section contains
which means sh_info is the index of the relocation section itself. < Assumption 2
What confuses me more is the an example someone else posts, reading elf file example
it seems the sh_info field information is nothing related to my previous 2 assumptions
Could anyone please help explain what does sh_info really contains?
About the "confusing example", maybe relocation part got deleted but only mention of sh_info is related to parsing of (dynamic) symbols name and (as show in image in your question) that field has different meaning for SHT_SYMTAB and SHT_DYNSYM (number of items in section + 1).
Section #0A OFF: 0x000015F8
Name: .rela.plt (0x00000084)
Type: SHT_RELA (0x00000004)
Flags: -a-
Addr: 0x004003E8
Offset: 0x000003E8
Size: 0x00000090
Link: 0x00000005
Info 0x0000000C
Section #05 OFF: 0x000014B8
Name: .dynsym (0x0000004E)
Type: SHT_DYNSYM (0x0000000B)
Flags: -a-
Addr: 0x00400280
Offset: 0x00000280
Size: 0x000000A8
Link: 0x00000006
Info 0x00000001
Section #0C OFF: 0x00001678
Name: .plt (0x00000089)
Type: SHT_PROGBITS (0x00000001)
Flags: -ax
Addr: 0x004004A0
Offset: 0x000004A0
Size: 0x00000070
Link: 0x00000000
Info 0x00000000
You can see that sh_link points to .dynsym section and sh_info points to .plt section (which contains executable memory).
So sh_link is symbol table and sh_info is executable section that gets modified.
Basically your document says it all already, but here are some more references.
Chapter on Sections [Figure 4-12: sh_link and sh_info Interpretation]:
sh_link - The section header index of the associated symbol table.
sh_info - The section header index of the section to which the relocation applies.
Also there's a chapter on relocation:
A relocation section references two other sections: a symbol table and a section to modify. The section header's sh_info and sh_link members, described in ``Sections'' above, specify these relationships. Relocation entries for different object files have slightly different interpretations for the r_offset member.
In relocatable files, r_offset holds a section offset. The relocation section itself describes how to modify another section in the file; relocation offsets designate a storage unit within the second section.
In executable and shared object files, r_offset holds a virtual address. To make these files' relocation entries more useful for the dynamic linker, the section offset (file interpretation) gives way to a virtual address (memory interpretation).
And just for fun... Here are (search page) relocation types for x86 on Linux:
#define R_X86_64_NONE 0 /* No reloc */
#define R_X86_64_64 1 /* Direct 64 bit */
#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
#define R_X86_64_PLT32 4 /* 32 bit PLT address */
#define R_X86_64_COPY 5 /* Copy symbol at runtime */
#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
#define R_X86_64_RELATIVE 8 /* Adjust by program base */
#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative
offset to GOT */
#define R_X86_64_32 10 /* Direct 32 bit zero extended */
#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
#define R_X86_64_16 12 /* Direct 16 bit zero extended */
#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
#define R_X86_64_8 14 /* Direct 8 bit sign extended */
#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */

ORA 7445: Query causing Oracle 12c to crash

I'm currently testing my application on Oracle 12 after all tests passed OK on Oracle 11. During testing the application kept losing the connection to Oracle when running a certain query. Here is a simplified example which replicates the problem exactly:
--create an example table
CREATE TABLE ERROR_TABLE(
PKID INT,
STRING_COLUMN VARCHAR2(255 CHAR)
);
--and run the offending query
SELECT
T.*,
ROW_NUMBER() OVER(
ORDER BY TO_NUMBER(REGEXP_SUBSTR(STRING_COLUMN,'^[0-9]*[.]*[0-9]*')) ASC,
STRING_COLUMN ASC,
PKID ASC
)
FROM
(
SELECT
PKID,
(SELECT MIN(STRING_COLUMN) FROM ERROR_TABLE T1 WHERE T1.PKID = T2.PKID) AS STRING_COLUMN
FROM ERROR_TABLE T2
)T;
When I run this query the connection to Oracle is dropped. There is an 'incident' recorded in the Oracle alert log, but it doesn't say why it happened. It seems to be the combination of the TO_NUMBER(... and the SELECT(MIN... part. If I replace either of those the problem goes away. However, I'm reluctant to do this as it's been tested and validated, and this technique appears in multiple places throughout the program.
Has anyone else encountered anything like this? What is causing it?
I'm running Oracle 12.1.0.1.0. The server is 64-bit and the client is 32-bit.
UPDATE
Here is the relevant excerpt from the alert log:
<msg time='2014-09-29T14:57:30.310+01:00' org_id='oracle' comp_id='rdbms'
type='UNKNOWN' level='16' host_id='ADMIN-PC'
host_addr='fe80::5183:eb5:fdd6:8fce%10' module='SQL Developer' pid='2084'>
<txt>Exception [type: ACCESS_VIOLATION, UNABLE_TO_READ] [ADDR:0x0] [PC:0x7FEF691FB5A, qcsogolz()+208]
</txt>
</msg>
<msg time='2014-09-29T14:57:30.435+01:00' org_id='oracle' comp_id='rdbms'
msg_id='1305664044' type='INCIDENT_ERROR' group='Access Violation'
level='1' host_id='ADMIN-PC' host_addr='fe80::5183:eb5:fdd6:8fce%10'
prob_key='ORA 7445 [qcsogolz]' errid='40818' detail_path='C:\APP\ORACLEUSER\diag\rdbms\orcl\orcl\trace\orcl_ora_2084.trc'>
<txt>Errors in file C:\APP\ORACLEUSER\diag\rdbms\orcl\orcl\trace\orcl_ora_2084.trc (incident=40818):
ORA-07445: exception encountered: core dump [qcsogolz()+208] [ACCESS_VIOLATION] [ADDR:0x0] [PC:0x7FEF691FB5A] [UNABLE_TO_READ] []
</txt>
</msg>
<msg time='2014-09-29T14:57:30.451+01:00' org_id='oracle' comp_id='rdbms'
type='UNKNOWN' level='16' host_id='ADMIN-PC'
host_addr='fe80::5183:eb5:fdd6:8fce%10' module='SQL Developer' pid='2084'>
<txt>Use ADRCI or Support Workbench to package the incident.
See Note 411.1 at My Oracle Support for error and packaging details.
</txt>
</msg>
<msg time='2014-09-29T14:57:32.760+01:00' org_id='oracle' comp_id='rdbms'
msg_id='dbgripsto_sweep_staged_obj:15783:70631439' type='ERROR' group='ami_comp'
level='8' host_id='ADMIN-PC' host_addr='fe80::5183:eb5:fdd6:8fce%10'>
<txt>Sweep [inc][40818]: completed
</txt>
</msg>
And here is a copy of the resulting trace file:
Trace file C:\APP\ORACLEUSER\diag\rdbms\orcl\orcl\trace\orcl_ora_2084.trc
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
Windows NT Version V6.1 Service Pack 1
CPU : 2 - type 8664, 2 Physical Cores
Process Affinity : 0x0x0000000000000000
Memory (Avail/Total): Ph:882M/2038M, Ph+PgF:1864M/4076M
Instance name: orcl
Redo thread mounted by this instance: 1
Oracle process number: 50
Windows thread id: 2084, image: ORACLE.EXE (SHAD)
*** 2014-09-29 14:57:30.310
*** SESSION ID:(18.63977) 2014-09-29 14:57:30.310
*** CLIENT ID:() 2014-09-29 14:57:30.310
*** SERVICE NAME:(pdborcl) 2014-09-29 14:57:30.310
*** MODULE NAME:(SQL Developer) 2014-09-29 14:57:30.310
*** ACTION NAME:() 2014-09-29 14:57:30.310
*** CONTAINER ID:(3) 2014-09-29 14:57:30.310
Exception [type: ACCESS_VIOLATION, UNABLE_TO_READ] [ADDR:0x0] [PC:0x7FEF691FB5A, qcsogolz()+208]
DDE: Problem Key 'ORA 7445 [qcsogolz]' was flood controlled (0x4) (incident: 40818)
ORA-07445: exception encountered: core dump [qcsogolz()+208] [ACCESS_VIOLATION] [ADDR:0x0] [PC:0x7FEF691FB5A] [UNABLE_TO_READ] []
Dump file c:\app\oracleuser\diag\rdbms\orcl\orcl\trace\orcl_ora_2084.trc
Mon Sep 29 14:57:30 2014
ORACLE V12.1.0.1.0 - 64bit Production vsnsta=0
vsnsql=16 vsnxtr=3
Dumping diagnostics for abrupt exit from ksedmp
ksedmp exception at address PC:0x0
ksedmp exception at 0000000000000000
Dumping initial exception call-stack
------------------- Call Stack Trace ---------------------
Frameptr RetAddr Param#1 Param#2 Param#3 Param#4 Function Name
000007FEF691FB5A 0000000000000000 0000000000630072 0000000000000000 0000000000000000 0000000000000000 qcsogolz()+208
000007FEF692BD90 000007FEF691FA8A 000000001969AE00 000007FE00000000 0000000000035490 000007FE00000000 qctcopn()+1904
000007FEF692B7B8 000007FEF692B620 0000000019696BC0 0000000022C90F80 000000014A2062A0 000000014657990E qctcopn()+408
000007FEF692B7B8 000007FEF692B620 000000014A2062A0 00000000196954C0 00000000196954C0 000007FF1A0EC938 qctcopn()+408
000007FEF692B7B8 000007FEF692B620 00000000196964E0 000007FEF65DBEE3 000000001522B400 0000000022C90F80 qctcopn()+408
000007FEF692B7B8 000007FEF692B620 0000000000000000 000000001522A7A8 000000001522A2E8 0000000000000000 qctcopn()+408
000007FEF6928BA3 000007FEF692B620 0000000022C91540 000007FEF65DBC6D 0000000000000000 000000001522A9B8 qctcpqb()+291
000007FEF6928A53 000007FEF6928A80 0000000019695C20 0000000022C90F80 0000000000035490 00000001433D61D6 qctcpqbl()+51
000000014561599A 000007FEF6928A20 00000001460088E0 000000002DDB5570 0000000000000001 000000001522A9B8 xtydrv()+138
0000000145FE901F 0000000145615910 0000000015227AC8 0000000000000000 0000000022C91540 000007FEF65DBFCC kkqcttcalo()+383
0000000145FF4C5D 0000000145FE8EA0 0000000000000000 0000000000000000 0000000000008000 0000000002000000 kkqctdrvCVM()+1501
00000001462F36EF 0000000145FF4A37 0000000000000000 0000000000000433 0000000022C91540 000007FEF61F6186 kkqvmTrMrg()+3087
00000001462F2148 00000001462F2AE0 0000000000000000 00000001422DEED1 0000000000000001 0000000000037038 kkqvmdrv2()+872
00000001460059B9 00000001462F1DE0 0000000000000000 000007FEF65E1153 0000000000000000 00000001460D7EAE kkqctdrvTD()+809
0000000145F213E1 0000000146005690 0000000000000000 000000002DDB5ED0 0000000000000002 00000000000000A1 kkqdrv()+6977
000000014600504C 0000000145F1F8A0 0000000015222578 000007FF00000000 000000000003AF58 000007FF1A0ECB80 kkqctdrvIT()+828
0000000145EE8B5A 0000000146004D10 0000000000000000 000000001522FF48 0000000000000038 000000001522FF48 apadrv()+4010
0000000143250A15 0000000145EE7BB0 0000000000000000 0000000000000433 0000000000000000 0000000000000000 opitca()+2565
000000014025C3A6 0000000143250010 00000000196EEB60 000007FF1A0ECB80 000000002DDB8CE8 0000000100000002 kksLoadChild()+8886
0000000140DA2D9E 000000014025A0F0 0000000022C91540 000007FF1839B920 000007FF1CE6F730 000007FF1839B920 kxsGetRuntimeLock()+2414
0000000140BE5A2A 0000000140DA2430 0000000022C91540 00000000196EEB60 000000002DDB8110 000000000000012C kksfbc()+15626
0000000140BDCB6E 0000000140BE1FD0 00000000196EEB60 0000000000000003 000007FF00000108 000000002DDBB020 kkspsc0()+2526
0000000140BDE812 0000000140BDC43E 0000000015242330 000000002DDBB020 0000000000000137 0000000000000003 kksParseCursor()+130
000000014630AC0C 0000000140BDE790 00000000151C6AF8 00000000151C9B98 0000000000000000 000007FEF7C21726 opiosq0()+3004
00000001442E760A 000000014630A050 000007FF00000003 000000014915B0C0 0000000000000000 00000000000000A4 kpooprx()+410
00000001442E3A52 00000001442E7470 0000000022C962AC 0000000000000001 0000000022C962D0 0000000000000001 kpoal8()+994
0000000140E685C1 00000001442E3670 0000000000000001 000000002DDBB2BC 00000000169711A0 000000002DDBB295 opiodr()+1601
000007FEF75CD7A7 0000000140E67F80 000007FF0000005E 000007FF0000001F 000000002DDBD8A0 000007FE00000000 ttcpip()+1223
0000000140E64E10 000007FEF75CD2E0 0000000022CB1140 0000000000000000 0000000000000000 0000000000000000 opitsk()+2160
0000000144768CD7 0000000140E645A0 0000000000000000 0000000000000000 000000002DDBF080 000000002DDBE7F0 opiino()+1079
0000000140E685C1 00000001447688A0 000000000000003C 0000000000000000 000000002DDBF2F0 0000000000000000 opiodr()+1601
000000013FE2F68A 0000000140E67F80 000000000000003C 0000000000000004 000000002DDBF2F0 0000000000000000 opidrv()+842
000000013FE3074E 000000013FE2F3DC 000000010000003C 000007FE00000004 000000002DDBF2F0 0000000015106A28 sou2o()+94
000000013FD612E4 000000013FE306F0 01CFDBED484830FD 0000000014A364D0 000E001D000907DE 0001015900120039 opimai_real()+276
000000013FD610BA 000000013FD611D0 0000000000000000 0000D6736DC2EA78 0000000014A364D0 000000002DDBF4A8 opimai()+170
000000013FD62239 000000013FD61010 0000000000000000 0000000149041F90 0000000000000050 000000000000196C OracleThreadStart()+713
0000000076CC59ED 000000013FD61F70 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000076CC59ED
0000000076EFC541 0000000076CC59E0 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000076EFC541
---------------- End of Call Stack Trace -----------------
This is a bug in 12.1.0.1 (Bug 17633803). It will be fixed in 12.2 and patched in 12.1.0.2.
There is a workaround which is to run
ALTER SESSION SET "_optimizer_unnest_scalar_sq"=false;
I've tried running your sample code above and the workaround does fix the issue in 12.1.0.1
UPDATE
Tested as fixed and working (without the workaround) in 12.1.0.2