-- Simulat whole-address checks for _dl_addr_inside_object. with Ada.Text_IO; procedure Bug20292 is -- Our address space is just 6 bits large (so that we can easily -- print diagrams). All arithmetic wraps around (unless type -- converions are applied). There is no implicit promotion to -- another arithmetic type. type Address is mod 2**6; -- Approximation of struct link_map. type Link_Map is record L_Addr : Address; -- In the oringal, these fields are actually nested in an -- array. P_Vaddr : Address; P_Memsz : Address; end record; -- Return True if the link map described by the argument does not -- exceed beyond the end of the address space. Used to filter out -- invalid test cases. function Valid_Link_Map (L : Link_Map) return Boolean is -- Perform the computations without wraparound. type Large_Address is range 0 .. 3 * Integer (Address'Last); Addr : constant Large_Address := Large_Address (L.L_Addr); Vaddr : constant Large_Address := Large_Address (L.P_Vaddr); Memsz : constant Large_Address := Large_Address (L.P_Memsz); Last : constant Large_Address := Large_Address (Address'Last); begin -- The sum is the logical address of the byte after the memory -- range covering the mapping. return Addr + Vaddr + Memsz <= Last + 1; end Valid_Link_Map; -- Ada translation of _dl_addr_inside_object (without the loop -- over l_phnum). function Address_Inside_Object (L : Link_Map; Addr : Address) return Boolean is Reladdr : constant Address := Addr - L.L_Addr; begin -- reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz return Reladdr - L.P_Vaddr < L.P_Memsz; end Address_Inside_Object; -- A vew of an address space where certain addresses are occupied -- (indicated by set bits). type Address_Map is array (Address'Range) of Boolean; -- Convert the link map to an explicit address space view where -- the covered bits are set. function Link_Map_To_Address_Space (L : Link_Map) return Address_Map is -- Perform the computations without wraparound. type Large_Address is range -1 .. 3 * Integer (Address'Last); Addr : constant Large_Address := Large_Address (L.L_Addr); Vaddr : constant Large_Address := Large_Address (L.P_Vaddr); Memsz : constant Large_Address := Large_Address (L.P_Memsz); First : constant Large_Address := Addr + Vaddr; Last : constant Large_Address := First + Memsz - 1; -- Initially, the address space is empty. Address_Space : Address_Map := (others => False); begin -- Populate the addresses which fall into the range. for J in First .. Last loop Address_Space (Address (J)) := True; end loop; return Address_Space; end Link_Map_To_Address_Space; -- Print out the address space. procedure Print_Map (Map : Address_Map) is use Ada.Text_IO; begin for J in Map'Range loop if Map (J) then Put ('X'); else Put ('.'); end if; end loop; New_Line; end Print_Map; -- Direction of the pointer. type Direction is (Upwards, Downwards); -- Print a pointer into the address space. procedure Print_Pointer (Addr : Address; Dir : Direction; Label : String) is use Ada.Text_IO; begin -- Leading white space to position the pointer. for J in 1 .. Addr loop Put (' '); end loop; -- The arrow. case Dir is when Upwards => Put ('^'); when Downwards => Put ('v'); end case; -- The label for the pointer. Put (' '); Put_Line (Label); end Print_Pointer; -- Used to indicate test failure. Test_Failure : exception; -- For each address in the address space, check that -- Address_Inside_Object returns the expected value. procedure Check_Link_Map (L : Link_Map) is Address_Space : constant Address_Map := Link_Map_To_Address_Space (L); Inside_Count : Integer := 0; use Ada.Text_IO; begin for Probe in Address'Range loop declare Actual : constant Boolean := Address_Inside_Object (L, Probe); Expected : constant Boolean := Address_Space (Probe); begin if Actual /= Expected then Put_Line ("Address_Inside_Object: " & Boolean'Image (Actual)); Put_Line ("Expected: " & Boolean'Image (Expected)); New_Line; Put_Line ("l_addr:" & Address'Image (L.L_Addr)); Put_Line ("p_vaddr:" & Address'Image (L.P_Vaddr)); Put_Line ("p_memsz:" & Address'Image (L.P_Memsz)); New_Line; Print_Pointer (L.L_Addr, Downwards, "l_addr"); Print_Map (Address_Space); Print_Pointer (Probe, Upwards, "test address"); raise Test_Failure; end if; if Expected then Inside_Count := Inside_Count + 1; end if; end; end loop; -- Paranoia check to see if the addres space was consistent. if Inside_Count /= Integer (L.P_Memsz) then Put_Line ("Inside_Count:" & Integer'Image (Inside_Count)); Put_Line ("p_memsz:" & Address'Image (L.P_Memsz)); raise Test_Failure; end if; end Check_Link_Map; begin for L_Addr in Address'Range loop for P_Vaddr in Address'Range loop for P_Memsz in Address'Range loop declare L : constant Link_Map := (L_Addr => L_Addr, P_Vaddr => P_Vaddr, P_Memsz => P_Memsz); begin if Valid_Link_Map (L) then Check_Link_Map (L); end if; end; end loop; end loop; end loop; end Bug20292;